diff --git a/dialogs/exportdialog.cpp b/dialogs/exportdialog.cpp index ae3bbb4b4..69a3b0012 100644 --- a/dialogs/exportdialog.cpp +++ b/dialogs/exportdialog.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "panels/panels.h" #include "panels/viewer.h" diff --git a/io/media.h b/io/media.h index 869215769..6347d425c 100644 --- a/io/media.h +++ b/io/media.h @@ -8,6 +8,11 @@ #include #include +#define MEDIA_TYPE_FOOTAGE 0 +#define MEDIA_TYPE_SEQUENCE 1 +#define MEDIA_TYPE_FOLDER 2 +#define MEDIA_TYPE_SOLID 3 + struct Sequence; struct Clip; diff --git a/mainwindow.cpp b/mainwindow.cpp index 3d6f68bf8..c5d62588f 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -21,6 +21,7 @@ #include "dialogs/preferencesdialog.h" #include "playback/audio.h" +#include "playback/playback.h" #include "ui_timeline.h" @@ -142,6 +143,8 @@ MainWindow::MainWindow(QWidget *parent) : } MainWindow::~MainWindow() { + set_sequence(NULL); + QString data_dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); if (!data_dir.isEmpty() && !autorecovery_filename.isEmpty()) { if (QFile::exists(autorecovery_filename)) { @@ -375,7 +378,7 @@ void MainWindow::on_action_Save_Project_triggered() void MainWindow::on_action_Open_Project_triggered() { QString fn = QFileDialog::getOpenFileName(this, "Open Project...", "", OLIVE_FILE_FILTER); - if (!fn.isEmpty() && can_close_project()) { + if (!fn.isEmpty() && can_close_project()) { updateTitle(fn); panel_project->load_project(); undo_stack.clear(); @@ -385,7 +388,7 @@ void MainWindow::on_action_Open_Project_triggered() void MainWindow::on_actionProject_triggered() { if (can_close_project()) { - panel_effect_controls->clear_effects(true); + panel_effect_controls->clear_effects(true); undo_stack.clear(); project_url.clear(); panel_project->new_project(); diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index caa1a4f5f..dfcd2aec1 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -197,14 +197,6 @@ void EffectControls::load_effects() { } } if (selected_clips.size() > 0) { -// ui->scrollArea->setMinimumWidth(ui->effects_area->width()); - - /*ui->effects_area->layout()->update(); - ui->effects_area->layout()->activate(); - qDebug() << ui->effects_area->height(); - - ui->keyframeView->resize(ui->keyframeView->width(), ui->effects_area->height());*/ - ui->keyframeView->setMinimumHeight(ui->effects_area->height()); ui->keyframeView->setEnabled(true); ui->keyframeView->visible_in = effects_in; diff --git a/panels/project.cpp b/panels/project.cpp index 00f48bb54..6390be8b4 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -17,6 +17,7 @@ #include "io/config.h" #include "playback/cacher.h" #include "dialogs/replaceclipmediadialog.h" +#include "panels/effectcontrols.h" #include #include @@ -559,6 +560,9 @@ void Project::delete_clips_using_selected_media() { } void Project::clear() { + // clear effects cache + panel_effect_controls->clear_effects(true); + // delete sequences first because it's important to close all the clips before deleting the media QVector sequences = list_all_project_sequences(); for (int i=0;iinitializeGL(); - viewer_widget->repaint(); + viewer_widget->update(); update(); } diff --git a/playback/cacher.cpp b/playback/cacher.cpp index 0e3d79484..df8962114 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -416,13 +416,11 @@ void cache_clip_worker(Clip* clip, long playhead, bool write_A, bool write_B, bo void close_clip_worker(Clip* clip) { // closes ffmpeg file handle and frees any memory used for caching MediaStream* ms = static_cast(clip->media)->get_stream_from_file_index(clip->track < 0, clip->media_stream); - if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + if (clip->track < 0) { sws_freeContext(clip->sws_ctx); delete [] clip->comp_frame; - delete clip->fbo; - clip->fbo = NULL; - } else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + } else { swr_free(&clip->swr_ctx); } diff --git a/playback/playback.cpp b/playback/playback.cpp index 37bc7ce86..f4a7f9b88 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -22,27 +22,32 @@ extern "C" { #include #include #include +#include bool texture_failed = false; void open_clip(Clip* clip, bool multithreaded) { - if (multithreaded) { - if (clip->open_lock.tryLock()) { - clip->multithreaded = true; + if (clip->media_type == MEDIA_TYPE_FOOTAGE) { + if (multithreaded) { + if (clip->open_lock.tryLock()) { + clip->multithreaded = true; - // maybe keep cacher instance in memory while clip exists for performance? - clip->cacher = new Cacher(clip); - QObject::connect(clip->cacher, SIGNAL(finished()), clip->cacher, SLOT(deleteLater())); + // maybe keep cacher instance in memory while clip exists for performance? + clip->cacher = new Cacher(clip); + QObject::connect(clip->cacher, SIGNAL(finished()), clip->cacher, SLOT(deleteLater())); - clip->cacher->start(QThread::LowPriority); - } - } else { - clip->multithreaded = false; - clip->finished_opening = false; - clip->open = true; + clip->cacher->start(QThread::LowPriority); + } + } else { + clip->multithreaded = false; + clip->finished_opening = false; + clip->open = true; - open_clip_worker(clip); - } + open_clip_worker(clip); + } + } else if (clip->media_type == MEDIA_TYPE_SEQUENCE) { + clip->open = true; + } } void close_clip(Clip* clip) { @@ -52,11 +57,21 @@ void close_clip(Clip* clip) { clip->texture = NULL; } - if (clip->multithreaded) { - clip->cacher->caching = false; - clip->can_cache.wakeAll(); - } else { - close_clip_worker(clip); + if (clip->fbo != NULL) { + delete clip->fbo; + clip->fbo = NULL; + } + + if (clip->media_type == MEDIA_TYPE_FOOTAGE) { + if (clip->multithreaded) { + clip->cacher->caching = false; + clip->can_cache.wakeAll(); + } else { + close_clip_worker(clip); + } + } else if (clip->media_type == MEDIA_TYPE_SEQUENCE) { + closeActiveClips(static_cast(clip->media), false); + clip->open = false; } } @@ -270,17 +285,26 @@ bool is_clip_active(Clip* c, long 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 != NULL && c->open) { - close_clip(c); - } - } - } + closeActiveClips(sequence, true); sequence = s; panel_timeline->update_sequence(); panel_viewer->update_sequence(); panel_timeline->setFocus(); } + +void closeActiveClips(Sequence *s, bool wait) { + if (s != NULL) { + for (int i=0;iclip_count();i++) { + Clip* c = s->get_clip(i); + if (c != NULL) { + if (c->media_type == MEDIA_TYPE_SEQUENCE) { + closeActiveClips(static_cast(c->media), wait); + close_clip(c); + } else if (c->media_type == MEDIA_TYPE_FOOTAGE && c->open) { + close_clip(c); + if (c->multithreaded && wait) c->cacher->wait(); + } + } + } + } +} diff --git a/playback/playback.h b/playback/playback.h index a61efa33a..195e0668c 100644 --- a/playback/playback.h +++ b/playback/playback.h @@ -27,6 +27,7 @@ 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); +void closeActiveClips(Sequence* s, bool wait); struct ClipCacheData { Clip& clip; diff --git a/ui/viewercontainer.cpp b/ui/viewercontainer.cpp index 57e085001..81ce67454 100644 --- a/ui/viewercontainer.cpp +++ b/ui/viewercontainer.cpp @@ -4,8 +4,7 @@ #include // enforces aspect ratio -ViewerContainer::ViewerContainer(QWidget *parent) : QWidget(parent) -{ +ViewerContainer::ViewerContainer(QWidget *parent) : QWidget(parent) { child = NULL; aspect_ratio = 1; } diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 7d41fd1eb..d54078960 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -11,6 +11,7 @@ #include "playback/audio.h" #include "io/media.h" #include "ui_timeline.h" +#include "playback/cacher.h" #include #include @@ -18,6 +19,7 @@ #include #include #include +#include extern "C" { #include @@ -41,36 +43,20 @@ ViewerWidget::ViewerWidget(QWidget *parent) : void ViewerWidget::deleteFunction() { // destroy all textures as well - for (int i=0;iclip_count();i++) { - Clip* c = sequence->get_clip(i); - if (c->texture != NULL) { - /* TODO NOTE: apparently "destroy()" is non-functional here because - * it requires a valid current context, and I guess it's no longer - * valid or current by the time this function is called. Not sure - * how to handle that just yet... - */ - - c->texture->destroy(); - c->texture = NULL; - } - } + makeCurrent(); + closeActiveClips(sequence, true); + doneCurrent(); } void ViewerWidget::retry() { update(); } -void ViewerWidget::initializeGL() { - /*if (fbo != NULL) { - delete fbo; - fbo = NULL; - }*/ +void ViewerWidget::initializeGL() { + connect(context(), SIGNAL(aboutToBeDestroyed()), this, SLOT(deleteFunction()), Qt::DirectConnection); + glClearColor(0, 0, 0, 1); - connect(context(), SIGNAL(aboutToBeDestroyed()), this, SLOT(deleteFunction())); - - initializeOpenGLFunctions(); - - update(); + retry_timer.start(); } //void ViewerWidget::resizeGL(int w, int h) @@ -78,7 +64,10 @@ void ViewerWidget::initializeGL() { //} void ViewerWidget::paintEvent(QPaintEvent *e) { - if (enable_paint) QOpenGLWidget::paintEvent(e); + if (enable_paint) { + makeCurrent(); + QOpenGLWidget::paintEvent(e); + } } GLuint ViewerWidget::draw_clip(Clip* clip, GLuint texture) { @@ -122,12 +111,12 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { if (c != NULL && !(nest != NULL && !same_sign(c->track, nest->track))) { bool clip_is_active = false; - switch (c->media_type) { - case MEDIA_TYPE_FOOTAGE: - { - Media* m = static_cast(c->media); + switch (c->media_type) { + case MEDIA_TYPE_FOOTAGE: + { + Media* m = static_cast(c->media); if (m->ready) { - if (m->get_stream_from_file_index(c->track < 0, c->media_stream) != NULL + if (m->get_stream_from_file_index(c->track < 0, c->media_stream) != NULL && is_clip_active(c, playhead)) { // if thread is already working, we don't want to touch this, // but we also don't want to hang the UI thread @@ -142,12 +131,17 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { } else { texture_failed = true; } - } - break; - case MEDIA_TYPE_SEQUENCE: - clip_is_active = true; - break; - } + } + break; + case MEDIA_TYPE_SEQUENCE: + if (is_clip_active(c, playhead)) { + if (!c->open) open_clip(c, multithreaded); + clip_is_active = true; + } else if (c->open) { + close_clip(c); + } + break; + } if (clip_is_active) { bool added = false; @@ -294,12 +288,12 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { } void ViewerWidget::paintGL() { - glClearColor(0, 0, 0, 1); glMatrixMode(GL_PROJECTION); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); bool loop = true; + while (loop) { loop = false; texture_failed = false; diff --git a/ui/viewerwidget.h b/ui/viewerwidget.h index 489b400b6..450cbcb32 100644 --- a/ui/viewerwidget.h +++ b/ui/viewerwidget.h @@ -2,7 +2,6 @@ #define VIEWERWIDGET_H #include -#include #include #include #include @@ -13,7 +12,7 @@ struct Clip; struct Sequence; -class ViewerWidget : public QOpenGLWidget, public QOpenGLFunctions +class ViewerWidget : public QOpenGLWidget { Q_OBJECT public: