diff --git a/dialogs/stabilizerdialog.cpp b/dialogs/stabilizerdialog.cpp new file mode 100644 index 000000000..935f26f6a --- /dev/null +++ b/dialogs/stabilizerdialog.cpp @@ -0,0 +1,20 @@ +#include "stabilizerdialog.h" + +#include +#include +#include + +StabilizerDialog::StabilizerDialog(QWidget *parent) : QDialog(parent) { + layout = new QVBoxLayout(this); + setLayout(layout); + + enable_stab = new QCheckBox(this); + enable_stab->setText("Enable Stabilizer"); + layout->addWidget(enable_stab); + + buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + layout->addWidget(buttons); + + connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); +} diff --git a/dialogs/stabilizerdialog.h b/dialogs/stabilizerdialog.h new file mode 100644 index 000000000..0f276b343 --- /dev/null +++ b/dialogs/stabilizerdialog.h @@ -0,0 +1,20 @@ +#ifndef STABILIZERDIALOG_H +#define STABILIZERDIALOG_H + +class QVBoxLayout; +class QCheckBox; +class QDialogButtonBox; + +#include + +class StabilizerDialog : public QDialog +{ +public: + StabilizerDialog(QWidget* parent = 0); +private: + QVBoxLayout* layout; + QCheckBox* enable_stab; + QDialogButtonBox* buttons; +}; + +#endif // STABILIZERDIALOG_H diff --git a/io/config.cpp b/io/config.cpp index 02ab90cdf..4f6980c0b 100644 --- a/io/config.cpp +++ b/io/config.cpp @@ -29,7 +29,8 @@ Config::Config() enable_seek_to_import(false), enable_audio_scrubbing(true), drop_on_media_to_replace(true), - autoscroll(AUTOSCROLL_PAGE_SCROLL) + autoscroll(AUTOSCROLL_PAGE_SCROLL), + audio_rate(48000) {} void Config::load(QString path) { @@ -103,6 +104,9 @@ void Config::load(QString path) { } else if (stream.name() == "Autoscroll") { stream.readNext(); autoscroll = stream.text().toInt(); + } else if (stream.name() == "AudioRate") { + stream.readNext(); + audio_rate = stream.text().toInt(); } } } @@ -148,6 +152,7 @@ void Config::save(QString path) { stream.writeTextElement("AudioScrubbing", QString::number(enable_audio_scrubbing)); stream.writeTextElement("DropFileOnMediaToReplace", QString::number(drop_on_media_to_replace)); stream.writeTextElement("Autoscroll", QString::number(autoscroll)); + stream.writeTextElement("AudioRate", QString::number(audio_rate)); stream.writeEndElement(); // configuration stream.writeEndDocument(); // doc diff --git a/io/config.h b/io/config.h index ea0745650..5b303e641 100644 --- a/io/config.h +++ b/io/config.h @@ -41,6 +41,7 @@ struct Config { bool enable_audio_scrubbing; bool drop_on_media_to_replace; int autoscroll; + int audio_rate; void load(QString path); void save(QString path); diff --git a/mainwindow.cpp b/mainwindow.cpp index 3b38c9dee..cf3abec0e 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -213,7 +213,9 @@ MainWindow::MainWindow(QWidget *parent) : config_dir = data_dir + "/config.xml"; config.load(config_dir); } - } + } + + init_audio(); connect(ui->action_Undo, SIGNAL(triggered(bool)), this, SLOT(undo())); connect(ui->action_Redo, SIGNAL(triggered(bool)), this, SLOT(redo())); diff --git a/olive.pro b/olive.pro index aabbbdaa3..16fa1bfcf 100644 --- a/olive.pro +++ b/olive.pro @@ -94,7 +94,8 @@ SOURCES += \ project/effectfield.cpp \ effects/internal/cubetransition.cpp \ project/effectgizmo.cpp \ - io/clipboard.cpp + io/clipboard.cpp \ + dialogs/stabilizerdialog.cpp HEADERS += \ mainwindow.h \ @@ -168,7 +169,8 @@ HEADERS += \ project/effectfield.h \ effects/internal/cubetransition.h \ project/effectgizmo.h \ - io/clipboard.h + io/clipboard.h \ + dialogs/stabilizerdialog.h FORMS += \ mainwindow.ui \ diff --git a/panels/viewer.cpp b/panels/viewer.cpp index e04655367..6cfc2dc86 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -102,15 +102,6 @@ void Viewer::reset_all_audio() { clear_audio_ibuffer(); } -void Viewer::assert_audio_device() { - if (is_audio_device_set() && - (audio_output->format().sampleRate() != seq->audio_frequency - || audio_output->format().channelCount() != av_get_channel_layout_nb_channels(seq->audio_layout))) { - closeActiveClips(seq, true); - init_audio(seq); - } -} - long timecode_to_frame(const QString& s, int view, double frame_rate) { QList list = s.split(QRegExp("[:;]")); @@ -242,7 +233,6 @@ void Viewer::seek(long p) { seq->playhead = p; update_parents(); reset_all_audio(); - assert_audio_device(); audio_scrub = true; } @@ -307,7 +297,6 @@ void Viewer::play() { if (seq != NULL) { reset_all_audio(); - assert_audio_device(); if (is_recording_cued() && !start_recording()) { dout << "[ERROR] Failed to record audio"; return; @@ -590,8 +579,6 @@ void Viewer::set_sequence(bool main, Sequence *s) { bool null_sequence = (seq == NULL); - init_audio(seq); - ui->headers->setEnabled(!null_sequence); ui->currentTimecode->setEnabled(!null_sequence); ui->openGLWidget->setEnabled(!null_sequence); diff --git a/panels/viewer.h b/panels/viewer.h index a7e1d84aa..81457674c 100644 --- a/panels/viewer.h +++ b/panels/viewer.h @@ -61,8 +61,7 @@ public: long recording_end; int recording_track; - void reset_all_audio(); - void assert_audio_device(); + void reset_all_audio(); void update_parents(); ViewerWidget* viewer_widget; diff --git a/playback/audio.cpp b/playback/audio.cpp index 591dc59f6..8d04cedce 100644 --- a/playback/audio.cpp +++ b/playback/audio.cpp @@ -40,52 +40,51 @@ bool is_audio_device_set() { return audio_device_set; } -void init_audio(Sequence* s) { +void init_audio() { stop_audio(); - if (s != NULL) { - QAudioFormat audio_format; - audio_format.setSampleRate(s->audio_frequency); - audio_format.setChannelCount(av_get_channel_layout_nb_channels(s->audio_layout)); - audio_format.setSampleSize(16); - audio_format.setCodec("audio/pcm"); - audio_format.setByteOrder(QAudioFormat::LittleEndian); - audio_format.setSampleType(QAudioFormat::SignedInt); + QAudioFormat audio_format; + audio_format.setSampleRate(config.audio_rate); + audio_format.setChannelCount(2); + audio_format.setSampleSize(16); + audio_format.setCodec("audio/pcm"); + audio_format.setByteOrder(QAudioFormat::LittleEndian); + audio_format.setSampleType(QAudioFormat::SignedInt); - QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); - QList devs = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); - dout << "[INFO] Found the following audio devices:"; - for (int i=0;i 0) { - dout << "[WARNING] Default audio returned NULL, attempting to use first device found..."; - info = devs.at(0); - } - dout << "[INFO] Using audio device" << info.deviceName(); + QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); + QList devs = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); + dout << "[INFO] Found the following audio devices:"; + for (int i=0;i 0) { + dout << "[WARNING] Default audio returned NULL, attempting to use first device found..."; + info = devs.at(0); + } + dout << "[INFO] Using audio device" << info.deviceName(); - if (!info.isFormatSupported(audio_format)) { - qWarning() << "[WARNING] Audio format is not supported by backend, using nearest"; - audio_format = info.nearestFormat(audio_format); - } + if (!info.isFormatSupported(audio_format)) { + qWarning() << "[WARNING] Audio format is not supported by backend, using nearest"; + audio_format = info.nearestFormat(audio_format); + } - audio_output = new QAudioOutput(info, audio_format); - audio_output->setNotifyInterval(5); + audio_output = new QAudioOutput(info, audio_format); + audio_output->moveToThread(QApplication::instance()->thread()); + audio_output->setNotifyInterval(5); - // connect - audio_io_device = audio_output->start(); - if (audio_io_device == NULL) { - dout << "[WARNING] Received NULL audio device. No compatible audio output was found."; - } else { - audio_device_set = true; + // connect + audio_io_device = audio_output->start(); + if (audio_io_device == NULL) { + dout << "[WARNING] Received NULL audio device. No compatible audio output was found."; + } else { + audio_device_set = true; - // start sender thread - audio_thread = new AudioSenderThread(); - QObject::connect(audio_output, SIGNAL(notify()), audio_thread, SLOT(notifyReceiver())); - audio_thread->start(QThread::TimeCriticalPriority); + // start sender thread + audio_thread = new AudioSenderThread(); + QObject::connect(audio_output, SIGNAL(notify()), audio_thread, SLOT(notifyReceiver())); + audio_thread->start(QThread::TimeCriticalPriority); - clear_audio_ibuffer(); - } + clear_audio_ibuffer(); } } diff --git a/playback/audio.h b/playback/audio.h index 96fc460cb..795c6ba01 100644 --- a/playback/audio.h +++ b/playback/audio.h @@ -45,7 +45,7 @@ void clear_audio_ibuffer(); bool is_audio_device_set(); -void init_audio(Sequence *s); +void init_audio(); void stop_audio(); int get_buffer_offset_from_frame(double framerate, long frame); diff --git a/playback/playback.cpp b/playback/playback.cpp index d24a03c8b..95d421161 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -193,7 +193,7 @@ void get_clip_frame(Clip* c, long playhead) { #ifdef GCF_DEBUG dout << "GCF ==> RESET" << target_pts << "(" << target_frame->pts << "-" << target_frame->pts+target_frame->pkt_duration << ")"; #endif -// target_frame = NULL; + target_frame = NULL; reset = true; c->last_invalid_ts = target_pts; } else { diff --git a/project/media.h b/project/media.h index 7dea09620..11ede6673 100644 --- a/project/media.h +++ b/project/media.h @@ -7,8 +7,6 @@ #define MEDIA_TYPE_FOOTAGE 0 #define MEDIA_TYPE_SEQUENCE 1 #define MEDIA_TYPE_FOLDER 2 -#define MEDIA_TYPE_SOLID 3 -#define MEDIA_TYPE_TONE 4 class Footage; class MediaThrobber; diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index aab15f9e4..5e3a318d7 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -16,6 +16,7 @@ #include "ui_timeline.h" #include "mainwindow.h" #include "ui/viewerwidget.h" +#include "dialogs/stabilizerdialog.h" #include "project/media.h" #include "debug.h" @@ -150,6 +151,11 @@ void TimelineWidget::show_context_menu(const QPoint& pos) { QAction* nestAction = menu.addAction("&Nest"); connect(nestAction, SIGNAL(triggered(bool)), mainWindow, SLOT(on_actionNest_triggered())); + if (selected_clips.size() == 1 && selected_clips.at(0)->media != NULL && selected_clips.at(0)->media->get_type() == MEDIA_TYPE_FOOTAGE) { + QAction* stabilizerAction = menu.addAction("S&tabilizer"); + connect(stabilizerAction, SIGNAL(triggered(bool)), this, SLOT(show_stabilizer_diag())); + } + // set autoscale arbitrarily to the first selected clip autoscaleAction->setChecked(selected_clips.at(0)->autoscale); @@ -229,7 +235,12 @@ void TimelineWidget::rename_clip() { undo_stack.push(rcc); update_ui(true); } - } + } +} + +void TimelineWidget::show_stabilizer_diag() { + StabilizerDialog sd; + sd.exec(); } bool same_sign(int a, int b) { diff --git a/ui/timelinewidget.h b/ui/timelinewidget.h index 0af743afb..2ba01cab4 100644 --- a/ui/timelinewidget.h +++ b/ui/timelinewidget.h @@ -85,6 +85,7 @@ private slots: void toggle_autoscale(); void tooltip_timer_timeout(); void rename_clip(); + void show_stabilizer_diag(); }; #endif // TIMELINEWIDGET_H diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index cf51ee2eb..5f51c3811 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -32,6 +32,7 @@ #include #include #include +#include extern "C" { #include @@ -618,7 +619,17 @@ GLuint ViewerWidget::compose_sequence(QVector& nests, bool render_audio) } else if (rendering) { glViewport(0, 0, s->width, s->height); } else { - glViewport(0, 0, width(), height()); + int widget_width = width(); + int widget_height = height(); + + QString qt_scale_factor = QString(qgetenv("QT_SCALE_FACTOR")); + if (!qt_scale_factor.isEmpty()) { + double scale = qt_scale_factor.toDouble(); + widget_width *= scale; + widget_height *= scale; + } + + glViewport(0, 0, widget_width, widget_height); } glBindTexture(GL_TEXTURE_2D, composite_texture);