diff --git a/dialogs/exportdialog.cpp b/dialogs/exportdialog.cpp index d8ee35825..c94c87de2 100644 --- a/dialogs/exportdialog.cpp +++ b/dialogs/exportdialog.cpp @@ -75,6 +75,11 @@ ExportDialog::ExportDialog(QWidget *parent) : ui->formatCombobox->addItem(format_strings[i]); } ui->formatCombobox->setCurrentIndex(FORMAT_MPEG4); + + ui->widthSpinbox->setValue(sequence->width); + ui->heightSpinbox->setValue(sequence->height); + ui->samplingRateSpinbox->setValue(sequence->audio_frequency); + ui->framerateSpinbox->setValue(sequence->frame_rate); } ExportDialog::~ExportDialog() @@ -442,13 +447,6 @@ void ExportDialog::on_pushButton_clicked() } } -void ExportDialog::set_defaults(Sequence* s) { - ui->widthSpinbox->setValue(s->width); - ui->heightSpinbox->setValue(s->height); - ui->samplingRateSpinbox->setValue(s->audio_frequency); - ui->framerateSpinbox->setValue(s->frame_rate); -} - void ExportDialog::update_progress_bar(int value) { ui->progressBar->setValue(value); } diff --git a/dialogs/exportdialog.h b/dialogs/exportdialog.h index db8241bee..ed45312e6 100644 --- a/dialogs/exportdialog.h +++ b/dialogs/exportdialog.h @@ -15,9 +15,7 @@ class ExportDialog : public QDialog Q_OBJECT public: explicit ExportDialog(QWidget *parent = 0); - ~ExportDialog(); - - void set_defaults(Sequence* s); + ~ExportDialog(); private slots: void on_formatCombobox_currentIndexChanged(int index); diff --git a/effects/effects.h b/effects/effects.h index daa5bdf5b..aae488b71 100644 --- a/effects/effects.h +++ b/effects/effects.h @@ -53,6 +53,7 @@ public: VolumeEffect(Clip* c); void process_audio(uint8_t* samples, int nb_bytes); Effect* copy(); + void load(QXmlStreamReader* stream); void save(QXmlStreamWriter* stream); QSpinBox* volume_val; @@ -63,6 +64,7 @@ public: PanEffect(Clip* c); void process_audio(uint8_t* samples, int nb_bytes); Effect* copy(); + void load(QXmlStreamReader* stream); void save(QXmlStreamWriter* stream); QSpinBox* pan_val; diff --git a/effects/paneffect.cpp b/effects/paneffect.cpp index 685f441ad..d99a8c1e8 100644 --- a/effects/paneffect.cpp +++ b/effects/paneffect.cpp @@ -31,6 +31,16 @@ Effect* PanEffect::copy() { return p; } +void PanEffect::load(QXmlStreamReader *stream) { + while (!(stream->isEndElement() && stream->name() == "effect") && !stream->atEnd()) { + stream->readNext(); + if (stream->isStartElement() && stream->name() == "pan") { + stream->readNext(); + pan_val->setValue(stream->text().toInt()); + } + } +} + void PanEffect::save(QXmlStreamWriter *stream) { stream->writeTextElement("pan", QString::number(pan_val->value())); } diff --git a/effects/volumeeffect.cpp b/effects/volumeeffect.cpp index 3caca736c..08a0e8da9 100644 --- a/effects/volumeeffect.cpp +++ b/effects/volumeeffect.cpp @@ -31,6 +31,16 @@ Effect* VolumeEffect::copy() { return v; } +void VolumeEffect::load(QXmlStreamReader *stream) { + while (!(stream->isEndElement() && stream->name() == "effect") && !stream->atEnd()) { + stream->readNext(); + if (stream->isStartElement() && stream->name() == "volume") { + stream->readNext(); + volume_val->setValue(stream->text().toInt()); + } + } +} + void VolumeEffect::save(QXmlStreamWriter *stream) { stream->writeTextElement("volume", QString::number(volume_val->value())); } diff --git a/io/exportthread.cpp b/io/exportthread.cpp index 0856240ed..5fbe4a7eb 100644 --- a/io/exportthread.cpp +++ b/io/exportthread.cpp @@ -49,8 +49,6 @@ bool encode(AVFormatContext* fmt_ctx, AVCodecContext* codec_ctx, AVFrame* frame, void ExportThread::run() { av_log_set_level(AV_LOG_DEBUG); - Sequence* sequence = panel_timeline->sequence; - // TODO make customizable long start = 0; long end = sequence->getEndFrame(); diff --git a/mainwindow.cpp b/mainwindow.cpp index 3783b73a2..01e888feb 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -15,6 +15,10 @@ #include #include +#include +#include + +#define OLIVE_FILE_FILTER "Olive Project (*.ove)" void MainWindow::setup_layout() { panel_project = new Project(this); @@ -133,7 +137,6 @@ void MainWindow::on_actionTimeline_Track_Lines_toggled(bool e) void MainWindow::on_actionExport_triggered() { ExportDialog e(this); - if (panel_timeline->sequence != NULL) e.set_defaults(panel_timeline->sequence); e.exec(); } @@ -204,7 +207,61 @@ void MainWindow::on_action_Paste_triggered() } } +bool MainWindow::save_project_as() { + QString fn = QFileDialog::getSaveFileName(this, "Save Project As...", "", OLIVE_FILE_FILTER); + if (!fn.isEmpty()) { + project_url = fn; + panel_project->save_project(); + return true; + } + return false; +} + +bool MainWindow::save_project() { + if (project_url.isEmpty()) { + return save_project_as(); + } else { + panel_project->save_project(); + return true; + } +} + +bool MainWindow::can_close_project() { + if (project_changed) { + int r = QMessageBox::question(this, "Unsaved Project", "This project has changed since it was last saved. Would you like to save it before closing?", QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes); + if (r == QMessageBox::Yes) { + return save_project(); + } else if (r == QMessageBox::Cancel) { + return false; + } + } + return true; +} + void MainWindow::on_action_Save_Project_triggered() { - panel_project->save_project(); + save_project(); +} + +void MainWindow::on_action_Open_Project_triggered() +{ + if (can_close_project()) { + QString fn = QFileDialog::getOpenFileName(this, "Open Project...", "", OLIVE_FILE_FILTER); + if (!fn.isEmpty()) { + project_url = fn; + panel_project->load_project(); + } + } +} + +void MainWindow::on_actionProject_triggered() +{ + if (can_close_project()) { + panel_project->new_project(); + } +} + +void MainWindow::on_actionSave_Project_As_triggered() +{ + save_project_as(); } diff --git a/mainwindow.h b/mainwindow.h index 453c20f59..c0239def1 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -65,9 +65,18 @@ private slots: void on_action_Save_Project_triggered(); + void on_action_Open_Project_triggered(); + + void on_actionProject_triggered(); + + void on_actionSave_Project_As_triggered(); + private: Ui::MainWindow *ui; void setup_layout(); + bool save_project_as(); + bool save_project(); + bool can_close_project(); }; #endif // MAINWINDOW_H diff --git a/olive.pro.user b/olive.pro.user index abdb7381c..861203364 100644 --- a/olive.pro.user +++ b/olive.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/panels/project.cpp b/panels/project.cpp index d0f00c3bb..4d2f8225a 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -5,6 +5,8 @@ #include "panels/panels.h" #include "panels/timeline.h" #include "panels/viewer.h" +#include "playback/playback.h" +#include "effects/effects.h" #include #include @@ -24,6 +26,9 @@ extern "C" { #include } +bool project_changed = false; +QString project_url = ""; + Project::Project(QWidget *parent) : QDockWidget(parent), ui(new Ui::Project) @@ -69,13 +74,80 @@ void Project::new_sequence(Sequence *s) { ui->treeWidget->addTopLevelItem(item); source_table = ui->treeWidget; + + project_changed = true; +} + +Media* Project::import_file(QString file) { + QByteArray ba = file.toLatin1(); + char* filename = new char[ba.size()+1]; + strcpy(filename, ba.data()); + + Media* m = NULL; + AVFormatContext* pFormatCtx = NULL; + int errCode = avformat_open_input(&pFormatCtx, filename, NULL, NULL); + if(errCode != 0) { + char err[1024]; + av_strerror(errCode, err, 1024); + qDebug() << "[ERROR] Could not open" << filename << "-" << err; + } else { + errCode = avformat_find_stream_info(pFormatCtx, NULL); + if (errCode < 0) { + char err[1024]; + av_strerror(errCode, err, 1024); + fprintf(stderr, "[ERROR] Could not find stream information. %s\n", err); + } else { + av_dump_format(pFormatCtx, 0, filename, 0); + + m = new Media(); + m->is_sequence = false; + m->url = file; + + // detect video/audio streams in file + for (int i=0;i<(int)pFormatCtx->nb_streams;i++) { + // Find the decoder for the video stream + if (avcodec_find_decoder(pFormatCtx->streams[i]->codecpar->codec_id) == NULL) { + qDebug() << "[ERROR] Unsupported codec in stream %d.\n"; + } else { + if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + qDebug() << "[WARNING] INFINITE_LENGTH calculation is inaccurate in this build\n"; + // TODO BETTER infinite length calculator + bool infinite_length = (pFormatCtx->streams[i]->nb_frames == 0); +// bool infinite_length = false; + + m->video_tracks.append({i, pFormatCtx->streams[i]->codecpar->width, pFormatCtx->streams[i]->codecpar->height, infinite_length}); + } else if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + m->audio_tracks.append({i, 0, 0, false}); + } + } + } + m->name = file.mid(file.lastIndexOf('/')+1); + m->length = pFormatCtx->duration; + + QTreeWidgetItem* item = new QTreeWidgetItem(); + if (m->video_tracks.size() == 0) { + item->setIcon(0, QIcon(":/icons/audiosource.png")); + } else { + item->setIcon(0, QIcon(":/icons/videosource.png")); + } + item->setText(0, m->name); + item->setText(1, QString::number(m->length)); + set_media_of_tree(item, m); + + ui->treeWidget->addTopLevelItem(item); + + project_changed = true; + } + } + avformat_close_input(&pFormatCtx); + delete [] filename; + return m; } void Project::import_dialog() { QStringList files = QFileDialog::getOpenFileNames(this, "Import media...", "", "All Files (*.*)"); for (int i=0;iis_sequence = false; - m->url = file; - - // detect video/audio streams in file - for (int i=0;i<(int)pFormatCtx->nb_streams;i++) { - // Find the decoder for the video stream - if (avcodec_find_decoder(pFormatCtx->streams[i]->codecpar->codec_id) == NULL) { - qDebug() << "[ERROR] Unsupported codec in stream %d.\n"; - } else { - if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - qDebug() << "[WARNING] INFINITE_LENGTH calculation is inaccurate in this build\n"; - // TODO BETTER infinite length calculator - bool infinite_length = (pFormatCtx->streams[i]->nb_frames == 0); -// bool infinite_length = false; - - m->video_tracks.append({i, pFormatCtx->streams[i]->codecpar->width, pFormatCtx->streams[i]->codecpar->height, infinite_length}); - } else if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - m->audio_tracks.append({i, 0, 0, false}); - } - } - } - m->name = files.at(i).mid(files.at(i).lastIndexOf('/')+1); - m->length = pFormatCtx->duration; - - QTreeWidgetItem* item = new QTreeWidgetItem(); - if (m->video_tracks.size() == 0) { - item->setIcon(0, QIcon(":/icons/audiosource.png")); - } else { - item->setIcon(0, QIcon(":/icons/videosource.png")); - } - item->setText(0, m->name); - item->setText(1, QString::number(m->length)); - set_media_of_tree(item, m); - - ui->treeWidget->addTopLevelItem(item); - } - } - avformat_close_input(&pFormatCtx); - delete [] filename; + import_file(file); } } @@ -185,26 +199,35 @@ void Project::remove_item(int i) { } delete m; ui->treeWidget->takeTopLevelItem(i); + project_changed = true; } void Project::clear() { - int len = ui->treeWidget->topLevelItemCount(); - for (int i=0;itreeWidget->topLevelItemCount() > 0) { + remove_item(0); } } -void Project::set_sequence(Sequence* s) { - panel_timeline->set_sequence(s); - panel_viewer->set_sequence(s); -} - -void Project::load_project() { +void Project::new_project() { // clear existing project set_sequence(NULL); clear(); + project_changed = false; +} - QFile file("C:/Users/Matt/Desktop/test.xml"); +#define LOAD_STATE_IDLE 0 +#define LOAD_STATE_MEDIA 1 +#define LOAD_STATE_FOOTAGE 2 +#define LOAD_STATE_TIMELINE 3 +#define LOAD_STATE_SEQUENCE 4 +#define LOAD_STATE_CLIP 5 +#define LOAD_STATE_CLIP_EFFECTS 6 +#define LOAD_STATE_EFFECT 7 + +void Project::load_project() { + new_project(); + + QFile file(project_url); if (!file.open(QIODevice::ReadOnly/* | QIODevice::Text*/)) { qDebug() << "[ERROR] Could not open file"; return; @@ -212,17 +235,174 @@ void Project::load_project() { QXmlStreamReader stream(&file); + // temp variables for loading + QVector temp_media_list; + QString temp_name; + QString temp_url; + int temp_media_id; + Sequence* temp_seq; + Clip* temp_clip; + + int state = LOAD_STATE_IDLE; while (!stream.atEnd()) { stream.readNext(); + switch (state) { + case LOAD_STATE_IDLE: + if (stream.isStartElement()) { + if (stream.name() == "footage") { + for (int j=0;jsave_id = temp_media_id; + m->name = temp_name; + temp_media_list.append(m); + state = LOAD_STATE_IDLE; + } else if (stream.isStartElement()) { + if (stream.name() == "name") { + stream.readNext(); + temp_name = stream.text().toString(); + } else if (stream.name() == "url") { + stream.readNext(); + temp_url = stream.text().toString(); + } + } + break; + case LOAD_STATE_SEQUENCE: + if (stream.isEndElement() && stream.name() == "sequence") { + new_sequence(temp_seq); + state = LOAD_STATE_IDLE; + } else if (stream.isStartElement()) { + if (stream.name() == "name") { + stream.readNext(); + temp_seq->name = stream.text().toString(); + } else if (stream.name() == "width") { + stream.readNext(); + temp_seq->width = stream.text().toInt(); + } else if (stream.name() == "height") { + stream.readNext(); + temp_seq->height = stream.text().toInt(); + } else if (stream.name() == "framerate") { + stream.readNext(); + temp_seq->frame_rate = stream.text().toFloat(); + } else if (stream.name() == "afreq") { + stream.readNext(); + temp_seq->audio_frequency = stream.text().toInt(); + } else if (stream.name() == "alayout") { + stream.readNext(); + temp_seq->audio_layout = stream.text().toInt(); + } else if (stream.name() == "clip") { + temp_clip = new Clip(); + temp_clip->sequence = temp_seq; + state = LOAD_STATE_CLIP; + } + } + break; + case LOAD_STATE_CLIP: + if (stream.isEndElement() && stream.name() == "clip") { + temp_seq->add_clip(temp_clip); + state = LOAD_STATE_SEQUENCE; + } else if (stream.isStartElement()) { + if (stream.name() == "name") { + stream.readNext(); + temp_clip->name = stream.text().toString(); + } else if (stream.name() == "clipin") { + stream.readNext(); + temp_clip->clip_in = stream.text().toInt(); + } else if (stream.name() == "in") { + stream.readNext(); + temp_clip->timeline_in = stream.text().toInt(); + } else if (stream.name() == "out") { + stream.readNext(); + temp_clip->timeline_out = stream.text().toInt(); + } else if (stream.name() == "track") { + stream.readNext(); + temp_clip->track = stream.text().toInt(); + } else if (stream.name() == "color") { + for (int j=0;jcolor_r = attr.value().toInt(); + } else if (attr.name().toString() == QLatin1String("g")) { + temp_clip->color_g = attr.value().toInt(); + } else if (attr.name().toString() == QLatin1String("b")) { + temp_clip->color_b = attr.value().toInt(); + } + } + } else if (stream.name() == "media") { + stream.readNext(); + for (int i=0;isave_id == stream.text().toInt()) { + temp_clip->media = m; + break; + } + } + } else if (stream.name() == "stream") { + // TODO very unintelligent code - i hate this + int stream_index = stream.text().toInt(); + bool found = false; + for (int i=0;imedia->video_tracks.size();i++) { + if (temp_clip->media->video_tracks.at(i).file_index == stream_index) { + temp_clip->media_stream = &temp_clip->media->video_tracks[i]; + found = true; + break; + } + } + if (!found) { + for (int i=0;imedia->audio_tracks.size();i++) { + if (temp_clip->media->audio_tracks.at(i).file_index == stream_index) { + temp_clip->media_stream = &temp_clip->media->audio_tracks[i]; + found = true; + break; + } + } + } + if (!found) { + qDebug() << "[WARNING] Could not load media stream - project file seems corrupt"; + } + } else if (stream.name() == "effect") { + int effect_id = -1; + for (int j=0;jload(&stream); + temp_clip->effects.append(e); + state = LOAD_STATE_CLIP; + } + } + } + break; + } + qDebug() << "read element:" << stream.name() << "- text:" << stream.text() << "- start:" << stream.isStartElement() << "- end:" << stream.isEndElement(); } if (stream.hasError()) { qDebug() << "[ERROR] Error parsing XML." << stream.error(); } + + project_changed = false; } void Project::save_project() { - QFile file("C:/Users/Matt/Desktop/test.xml"); + QFile file(project_url); if (!file.open(QIODevice::WriteOnly/* | QIODevice::Text*/)) { qDebug() << "[ERROR] Could not open file"; return; @@ -232,6 +412,10 @@ void Project::save_project() { stream.setAutoFormatting(true); stream.writeStartDocument(); + stream.writeStartElement("project"); + + stream.writeTextElement("version", "180601"); + int len = ui->treeWidget->topLevelItemCount(); stream.writeStartElement("media"); for (int i=0;igetEndFrame()); } -void Timeline::set_sequence(Sequence *s) { - if (sequence != NULL) { - // clean up - close all open clips - for (int i=0;iclip_count();i++) { - Clip* c = sequence->get_clip(i); - if (c->open) { - close_clip(c); - } - } - } - - sequence = s; - bool null_sequence = (s == NULL); +void Timeline::update_sequence() { + bool null_sequence = (sequence == NULL); for (int i=0;isetEnabled(!null_sequence); @@ -173,6 +162,7 @@ void Timeline::repaint_timeline() { void Timeline::redraw_all_clips() { // add current sequence to the undo stack sequence->undo_add_current(); + project_changed = true; ui->video_area->redraw_clips(); ui->audio_area->redraw_clips(); diff --git a/panels/timeline.h b/panels/timeline.h index eb959f366..5c6a82b81 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -67,14 +67,13 @@ public: void paste(); bool split_selection(); void split_at_playhead(); - void set_sequence(Sequence* s); + void update_sequence(); int getScreenPointFromFrame(long frame); long getFrameFromScreenPoint(int x); void snap_to_clip(long* l); - Sequence* sequence; long playhead; // playback functions diff --git a/panels/viewer.cpp b/panels/viewer.cpp index fb0c35aab..654fd8b79 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -19,19 +19,17 @@ Viewer::Viewer(QWidget *parent) : ui->setupUi(this); ui->glViewerPane->child = ui->openGLWidget; viewer_widget = ui->openGLWidget; - set_sequence(NULL); + update_sequence(); } Viewer::~Viewer() { - init_audio(NULL); - + init_audio(); delete ui; } -void Viewer::set_sequence(Sequence* s) { - bool null_sequence = (s == NULL); - sequence = s; +void Viewer::update_sequence() { + bool null_sequence = (sequence == NULL); ui->openGLWidget->setEnabled(!null_sequence); ui->openGLWidget->setVisible(!null_sequence); @@ -41,7 +39,7 @@ void Viewer::set_sequence(Sequence* s) { ui->pushButton_4->setEnabled(!null_sequence); ui->pushButton_5->setEnabled(!null_sequence); - init_audio(s); + init_audio(); if (!null_sequence) { ui->glViewerPane->aspect_ratio = (float) sequence->width / (float) sequence->height; diff --git a/panels/viewer.h b/panels/viewer.h index ffcad1f4f..53d99f778 100644 --- a/panels/viewer.h +++ b/panels/viewer.h @@ -18,10 +18,9 @@ class Viewer : public QDockWidget public: explicit Viewer(QWidget *parent = 0); ~Viewer(); - void set_sequence(Sequence* s); + void update_sequence(); void compose(); - Sequence* sequence; ViewerWidget* viewer_widget; private slots: diff --git a/playback/audio.cpp b/playback/audio.cpp index 7de4a562c..d7e0f37b3 100644 --- a/playback/audio.cpp +++ b/playback/audio.cpp @@ -17,17 +17,17 @@ qint8 audio_ibuffer[audio_ibuffer_size]; int audio_ibuffer_read = 0; QVector audio_ibuffer_write; -void init_audio(Sequence* s) { +void init_audio() { if (audio_device_set) { audio_output->stop(); delete audio_output; audio_device_set = false; } - if (s != NULL) { + if (sequence != NULL) { QAudioFormat audio_format; - audio_format.setSampleRate(s->audio_frequency); - audio_format.setChannelCount(av_get_channel_layout_nb_channels(s->audio_layout)); + audio_format.setSampleRate(sequence->audio_frequency); + audio_format.setChannelCount(av_get_channel_layout_nb_channels(sequence->audio_layout)); audio_format.setSampleSize(16); audio_format.setCodec("audio/pcm"); audio_format.setByteOrder(QAudioFormat::LittleEndian); diff --git a/playback/audio.h b/playback/audio.h index 555bc44b5..4370dedfd 100644 --- a/playback/audio.h +++ b/playback/audio.h @@ -17,6 +17,6 @@ extern int audio_ibuffer_read; //extern QVector audio_ibuffer_write; void clear_audio_ibuffer(); -void init_audio(Sequence* s); +void init_audio(); #endif // AUDIO_H diff --git a/playback/playback.cpp b/playback/playback.cpp index 53f427269..475c38a06 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -5,7 +5,9 @@ #include "io/media.h" #include "playback/audio.h" #include "playback/cacher.h" +#include "panels/panels.h" #include "panels/timeline.h" +#include "panels/viewer.h" #include extern "C" { @@ -287,3 +289,18 @@ void retrieve_next_frame_raw_data(Clip* c, AVFrame* output) { bool is_clip_active(Clip* c, long playhead) { return c->timeline_in < playhead + ceil(c->sequence->frame_rate) && c->timeline_out > playhead; } + +void set_sequence(Sequence* s) { + if (sequence != NULL) { + // clean up - close all open clips + for (int i=0;iclip_count();i++) { + Clip* c = sequence->get_clip(i); + if (c->open) { + close_clip(c); + } + } + } + sequence = s; + panel_timeline->update_sequence(); + panel_viewer->update_sequence(); +} diff --git a/playback/playback.h b/playback/playback.h index 6bd77a702..7cdf1fb13 100644 --- a/playback/playback.h +++ b/playback/playback.h @@ -29,6 +29,7 @@ int retrieve_next_frame(Clip* c, AVFrame* f); void retrieve_next_frame_raw_data(Clip* c, AVFrame* output); bool is_clip_active(Clip* c, long playhead); void get_next_audio(Clip* c, bool mix); +void set_sequence(Sequence* s); struct ClipCacheData { Clip& clip; diff --git a/project/clip.cpp b/project/clip.cpp index d97c45f56..de4404704 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -38,7 +38,6 @@ Clip* Clip::copy() { } void Clip::init() { - qDebug() << "init was called"; reset(); clip_in = timeline_in = timeline_out = track = undeletable = 0; texture = NULL; diff --git a/project/effect.cpp b/project/effect.cpp index f45ea6ad9..68a928772 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -29,6 +29,7 @@ void Effect::field_changed() { } Effect* Effect::copy() {return NULL;} +void Effect::load(QXmlStreamReader* stream) {} void Effect::save(QXmlStreamWriter *stream) {} void Effect::process_gl(int*, int*) {} diff --git a/project/effect.h b/project/effect.h index 9a092d538..c7e67b80a 100644 --- a/project/effect.h +++ b/project/effect.h @@ -7,6 +7,7 @@ class QWidget; class CollapsibleWidget; struct Clip; +class QXmlStreamReader; class QXmlStreamWriter; enum EffectTypes { EFFECT_TYPE_INVALID, EFFECT_TYPE_VIDEO, EFFECT_TYPE_AUDIO }; @@ -24,6 +25,7 @@ public: Clip* parent_clip; virtual Effect* copy(); + virtual void load(QXmlStreamReader* stream); virtual void save(QXmlStreamWriter* stream); virtual void process_gl(int* anchor_x, int* anchor_y); diff --git a/project/sequence.cpp b/project/sequence.cpp index 09d804785..2d4048dfc 100644 --- a/project/sequence.cpp +++ b/project/sequence.cpp @@ -162,3 +162,6 @@ void Sequence::redo() { set_undo(undo_pointer); } } + +// static variable for the currently active sequence +Sequence* sequence = NULL; diff --git a/project/sequence.h b/project/sequence.h index b3b6cab8f..da9c3f7dd 100644 --- a/project/sequence.h +++ b/project/sequence.h @@ -38,4 +38,7 @@ private: int undo_stack_start; }; +// static variable for the currently active sequence +extern Sequence* sequence; + #endif // SEQUENCE_H diff --git a/ui/sourcetable.cpp b/ui/sourcetable.cpp index edb63c38b..afb58ce0e 100644 --- a/ui/sourcetable.cpp +++ b/ui/sourcetable.cpp @@ -5,6 +5,7 @@ #include "panels/timeline.h" #include "panels/viewer.h" #include "panels/panels.h" +#include "playback/playback.h" #include @@ -19,7 +20,7 @@ void SourceTable::mouseDoubleClickEvent(QMouseEvent* ) } else if (selectedItems().count() == 1) { Media* m = reinterpret_cast(selectedItems().at(0)->data(0, Qt::UserRole + 1).value()); if (m->is_sequence) { - panel_project->set_sequence(m->sequence); + set_sequence(m->sequence); } } } diff --git a/ui/timelineheader.cpp b/ui/timelineheader.cpp index a7c6b4f3a..72367d820 100644 --- a/ui/timelineheader.cpp +++ b/ui/timelineheader.cpp @@ -37,10 +37,10 @@ void TimelineHeader::mouseReleaseEvent(QMouseEvent *) { } void TimelineHeader::paintEvent(QPaintEvent*) { - if (panel_timeline->sequence != NULL) { + if (sequence != NULL) { QPainter p(this); p.setPen(Qt::gray); - int interval = panel_timeline->getScreenPointFromFrame(panel_timeline->sequence->frame_rate); + int interval = panel_timeline->getScreenPointFromFrame(sequence->frame_rate); for (int i=0;isequence != NULL) redraw_clips(); + if (sequence != NULL) redraw_clips(); } void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { @@ -48,7 +48,7 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { for (int i=0;iget_media_from_tree(items.at(i)); - long duration = m->get_length_in_frames(panel_timeline->sequence->frame_rate); + long duration = m->get_length_in_frames(sequence->frame_rate); Ghost g = {NULL, entry_point, entry_point + duration}; g.media = m; g.clip_in = 0; @@ -94,7 +94,7 @@ void TimelineWidget::dropEvent(QDropEvent* event) { for (int i=0;ighosts.size();i++) { const Ghost& g = panel_timeline->ghosts.at(i); - panel_timeline->sequence->delete_area(g.in, g.out, g.track); + sequence->delete_area(g.in, g.out, g.track); Clip* c = new Clip(); c->media = g.media; @@ -105,7 +105,7 @@ void TimelineWidget::dropEvent(QDropEvent* event) { c->color_r = 128; c->color_g = 128; c->color_b = 192; - c->sequence = panel_timeline->sequence; + c->sequence = sequence; c->track = g.track; c->name = c->media->name; @@ -118,7 +118,7 @@ void TimelineWidget::dropEvent(QDropEvent* event) { c->effects.append(create_effect(AUDIO_PAN_EFFECT, c)); } - panel_timeline->sequence->add_clip(c); + sequence->add_clip(c); } panel_timeline->ghosts.clear(); @@ -156,7 +156,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { panel_timeline->selections.clear(); } - Clip* clip = panel_timeline->sequence->get_clip(clip_index); + Clip* clip = sequence->get_clip(clip_index); panel_timeline->selections.append({clip->timeline_in, clip->timeline_out, clip->track}); } panel_timeline->moving_init = true; @@ -173,7 +173,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { case TIMELINE_TOOL_RAZOR: { if (clip_index >= 0) { - panel_timeline->sequence->split_clip(clip_index, panel_timeline->drag_frame_start); + sequence->split_clip(clip_index, panel_timeline->drag_frame_start); } panel_timeline->splitting = true; panel_timeline->redraw_all_clips(); @@ -195,9 +195,9 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { c->track = g.track; // step 2 - delete anything that exists in area that clip is moving to - panel_timeline->sequence->delete_area(g.in, g.out, g.track); + sequence->delete_area(g.in, g.out, g.track); - panel_timeline->sequence->add_clip(c); + sequence->add_clip(c); } } else { // move clips @@ -212,7 +212,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { if (panel_timeline->tool == TIMELINE_TOOL_POINTER) { // step 2 - delete anything that exists in area that clip is moving to // note: ripples are non-destructive so this is pointer-tool exclusive - panel_timeline->sequence->delete_area(g.in, g.out, g.track); + sequence->delete_area(g.in, g.out, g.track); } // step 3 - move clips @@ -270,7 +270,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { // find out how many clips are selected bool single_select = false; int selected_clip = 0; - for (int i=0;isequence->clip_count();i++) { + for (int i=0;iclip_count();i++) { if (panel_timeline->is_clip_selected(i)) { if (!single_select) { // found ONE selected clip @@ -284,7 +284,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { } } if (single_select) { - panel_effect_controls->set_clip(panel_timeline->sequence->get_clip(selected_clip)); + panel_effect_controls->set_clip(sequence->get_clip(selected_clip)); } else { panel_effect_controls->set_clip(NULL); } @@ -301,7 +301,7 @@ void TimelineWidget::init_ghosts() { if (panel_timeline->trim_target > -1 || panel_timeline->tool == TIMELINE_TOOL_SLIP) { // used for trim ops g.ghost_length = g.old_out - g.old_in; - g.media_length = g.clip->media->get_length_in_frames(panel_timeline->sequence->frame_rate); + g.media_length = g.clip->media->get_length_in_frames(sequence->frame_rate); } } for (int i=0;iselections.size();i++) { @@ -335,8 +335,8 @@ void validate_snapping(Ghost& g, long* frame_diff) { panel_timeline->snapped = false; if (panel_timeline->snapping) { if (!subvalidate_snapping(g, frame_diff, panel_timeline->playhead)) { - for (int j=0;jsequence->clip_count();j++) { - Clip* c = panel_timeline->sequence->get_clip(j); + for (int j=0;jclip_count();j++) { + Clip* c = sequence->get_clip(j); if (!subvalidate_snapping(g, frame_diff, c->timeline_in)) { subvalidate_snapping(g, frame_diff, c->timeline_out); } @@ -572,9 +572,9 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { } else { // set up movement // create ghosts - for (int i=0;isequence->clip_count();i++) { + for (int i=0;iclip_count();i++) { if (panel_timeline->is_clip_selected(i)) { - Clip* c = panel_timeline->sequence->get_clip(i); + Clip* c = sequence->get_clip(i); panel_timeline->ghosts.append({c, c->timeline_in, c->timeline_out, c->track, c->clip_in}); } } @@ -583,10 +583,10 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) { for (int i=0;ighosts.size();i++) { // get clips before and after ripple point - for (int j=0;jsequence->clip_count();j++) { + for (int j=0;jclip_count();j++) { // don't cache any currently selected clips Clip* c = panel_timeline->ghosts.at(i).clip; - Clip* cc = panel_timeline->sequence->get_clip(j); + Clip* cc = sequence->get_clip(j); bool is_selected = false; for (int k=0;kghosts.size();k++) { if (panel_timeline->ghosts.at(k).clip == cc) { @@ -647,9 +647,9 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { } else if (panel_timeline->splitting) { int track = panel_timeline->cursor_track; bool repaint = false; - for (int i=0;isequence->clip_count();i++) { - if (panel_timeline->sequence->get_clip(i)->track == track) { - panel_timeline->sequence->split_clip(i, panel_timeline->drag_frame_start); + for (int i=0;iclip_count();i++) { + if (sequence->get_clip(i)->track == track) { + sequence->split_clip(i, panel_timeline->drag_frame_start); repaint = true; } } @@ -664,8 +664,8 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { long mouse_frame_lower = panel_timeline->getFrameFromScreenPoint(pos.x()-lim)-1; long mouse_frame_upper = panel_timeline->getFrameFromScreenPoint(pos.x()+lim)+1; bool found = false; - for (int i=0;isequence->clip_count();i++) { - Clip* c = panel_timeline->sequence->get_clip(i); + for (int i=0;iclip_count();i++) { + Clip* c = sequence->get_clip(i); if (c->track == mouse_track) { if (c->timeline_in > mouse_frame_lower && c->timeline_in < mouse_frame_upper) { panel_timeline->trim_target = i; @@ -704,7 +704,7 @@ int color_brightness(int r, int g, int b) { void TimelineWidget::redraw_clips() { // Draw clips - int panel_width = panel_timeline->getScreenPointFromFrame(panel_timeline->sequence->getEndFrame()) + 100; + int panel_width = panel_timeline->getScreenPointFromFrame(sequence->getEndFrame()) + 100; setMinimumWidth(panel_width); clip_pixmap = QPixmap(panel_width, height()); @@ -712,8 +712,8 @@ void TimelineWidget::redraw_clips() { QPainter clip_painter(&clip_pixmap); int video_track_limit = 0; int audio_track_limit = 0; - for (int i=0;isequence->clip_count();i++) { - Clip* clip = panel_timeline->sequence->get_clip(i); + for (int i=0;iclip_count();i++) { + Clip* clip = sequence->get_clip(i); if (is_track_visible(clip->track)) { if (clip->track < 0 && clip->track < video_track_limit) { // video clip video_track_limit = clip->track; @@ -765,7 +765,7 @@ void TimelineWidget::redraw_clips() { } void TimelineWidget::paintEvent(QPaintEvent*) { - if (panel_timeline->sequence != NULL) { + if (sequence != NULL) { QPainter p(this); p.drawPixmap(0, 0, minimumWidth(), height(), clip_pixmap); @@ -859,8 +859,8 @@ int TimelineWidget::getScreenPointFromTrack(int track) { } int TimelineWidget::getClipIndexFromCoords(long frame, int track) { - for (int i=0;isequence->clip_count();i++) { - Clip* c = panel_timeline->sequence->get_clip(i); + for (int i=0;iclip_count();i++) { + Clip* c = sequence->get_clip(i); if (c->track == track) { if (frame >= c->timeline_in && frame < c->timeline_out) { return i; diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 2f60990e7..b3bf99388 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -60,7 +60,7 @@ void ViewerWidget::paintGL() long playhead = panel_timeline->playhead; - handle_media(panel_viewer->sequence, playhead, multithreaded); + handle_media(sequence, playhead, multithreaded); texture_failed = false; bool render_audio = (panel_timeline->playing || force_audio);