From a06e94eac2994909c594009add7b1d21985bf5ea Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 28 Feb 2019 11:01:48 -0800 Subject: [PATCH 1/7] added manual svg linking to project file --- .travis/install.sh | 4 ++-- olive.pro | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis/install.sh b/.travis/install.sh index d38d4e291..217361a4f 100644 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -8,11 +8,11 @@ if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then if [ "$ARCH" == "x86_64" ]; then - sudo apt-get -y install qt59base qt59multimedia libavformat-dev libavcodec-dev libavfilter-dev libavutil-dev libswscale-dev libswresample-dev frei0r-plugins-dev frei0r-plugins fuse + sudo apt-get -y install qt59base qt59multimedia qt59svg libavformat-dev libavcodec-dev libavfilter-dev libavutil-dev libswscale-dev libswresample-dev frei0r-plugins-dev frei0r-plugins fuse fi if [ "$ARCH" == "i386" ]; then - sudo apt-get -y install gcc-multilib g++-multilib qt59base:i386 qt59multimedia:i386 libavformat-dev:i386 libavcodec-dev:i386 libavfilter-dev:i386 libavutil-dev:i386 libswscale-dev:i386 libswresample-dev:i386 frei0r-plugins-dev:i386 frei0r-plugins:i386 pkg-config:i386 libgl1-mesa-dev:i386 fuse:i386 + sudo apt-get -y install gcc-multilib g++-multilib qt59base:i386 qt59multimedia:i386 qt59svg:i386 libavformat-dev:i386 libavcodec-dev:i386 libavfilter-dev:i386 libavutil-dev:i386 libswscale-dev:i386 libswresample-dev:i386 frei0r-plugins-dev:i386 frei0r-plugins:i386 pkg-config:i386 libgl1-mesa-dev:i386 fuse:i386 fi source /opt/qt*/bin/qt*-env.sh diff --git a/olive.pro b/olive.pro index 95066c9b0..0a38ee49a 100644 --- a/olive.pro +++ b/olive.pro @@ -4,7 +4,7 @@ # #------------------------------------------------- -QT += core gui multimedia opengl +QT += core gui multimedia opengl svg greaterThan(QT_MAJOR_VERSION, 4): QT += widgets From a7243c76c0c37af9f1622fbdf7a96b0cb7420244 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 28 Feb 2019 11:12:25 -0800 Subject: [PATCH 2/7] fixed missing nullptr checks on non-media clips --- project/clip.cpp | 4 ++- rendering/cacher.cpp | 62 ++++++++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/project/clip.cpp b/project/clip.cpp index 9e5b1b8b1..0a0902b5f 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -126,9 +126,11 @@ Media *Clip::media() FootageStream *Clip::media_stream() { - if (media()->get_type() == MEDIA_TYPE_FOOTAGE) { + if (media() != nullptr + && media()->get_type() == MEDIA_TYPE_FOOTAGE) { return media()->to_footage()->get_stream_from_file_index(track() < 0, media_stream_index()); } + return nullptr; } diff --git a/rendering/cacher.cpp b/rendering/cacher.cpp index 2c4055372..efd0eabdf 100644 --- a/rendering/cacher.cpp +++ b/rendering/cacher.cpp @@ -735,7 +735,10 @@ void Cacher::WakeMainThread() main_thread_lock_.unlock(); } -Cacher::Cacher(Clip* c) : clip(c) {} +Cacher::Cacher(Clip* c) : clip(c) { + frame_ = nullptr; + pkt = nullptr; +} void Cacher::OpenWorker() { qint64 time_start = QDateTime::currentMSecsSinceEpoch(); @@ -988,9 +991,15 @@ void Cacher::CloseWorker() { queue.clear(); queue.unlock(); - av_frame_free(&frame_); + if (frame_ != nullptr) { + av_frame_free(&frame_); + frame_ = nullptr; + } - av_packet_free(&pkt); + if (pkt != nullptr) { + av_packet_free(&pkt); + pkt = nullptr; + } if (clip->media() != nullptr && clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) { avfilter_graph_free(&filter_graph); @@ -1050,7 +1059,9 @@ void Cacher::Open() void Cacher::Cache(long playhead, bool scrubbing, QVector& nests, int playback_speed) { - if (clip->media_stream()->infinite_length && queue.size() > 0) { + if (clip->media_stream() != nullptr + && queue.size() > 0 + && clip->media_stream()->infinite_length) { retrieved_frame = queue.at(0); return; } @@ -1063,26 +1074,33 @@ void Cacher::Cache(long playhead, bool scrubbing, QVector& nests, int pla bool wait_for_cacher_to_respond = true; - // see if we already have this frame - retrieve_lock_.lock(); - queue.lock(); - retrieved_frame = nullptr; - int64_t target_pts = seconds_to_timestamp(clip, playhead_to_clip_seconds(clip, playhead_)); - for (int i=0;ipts == target_pts) { - retrieved_frame = queue.at(i); -// qDebug() << "================> found frame at" << i; - wait_for_cacher_to_respond = false; - break; - } else if (i > 0 && queue.at(i-1)->pts < target_pts && queue.at(i)->pts > target_pts) { - retrieved_frame = queue.at(i-1); -// qDebug() << "================> found frame at" << i-1; - wait_for_cacher_to_respond = false; - break; + if (clip->media() != nullptr) { + // see if we already have this frame + retrieve_lock_.lock(); + queue.lock(); + retrieved_frame = nullptr; + int64_t target_pts = seconds_to_timestamp(clip, playhead_to_clip_seconds(clip, playhead_)); + for (int i=0;ipts == target_pts) { + + // the queue has a frame with the exact timestamp + + retrieved_frame = queue.at(i); + wait_for_cacher_to_respond = false; + break; + } else if (i > 0 && queue.at(i-1)->pts < target_pts && queue.at(i)->pts > target_pts) { + + // the queue has a frame with a close timestamp that we'll assume is different due to a rounding error + + retrieved_frame = queue.at(i-1); + wait_for_cacher_to_respond = false; + break; + } } + queue.unlock(); + retrieve_lock_.unlock(); } - queue.unlock(); - retrieve_lock_.unlock(); if (wait_for_cacher_to_respond) { main_thread_lock_.lock(); From e649982bde2ba7364cc63c4d892691d3e3f328d7 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 28 Feb 2019 11:17:57 -0800 Subject: [PATCH 3/7] Sequence::copy copies markers too --- project/sequence.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/project/sequence.cpp b/project/sequence.cpp index 2e070ce00..da1bad08f 100644 --- a/project/sequence.cpp +++ b/project/sequence.cpp @@ -42,6 +42,8 @@ SequencePtr Sequence::copy() { s->frame_rate = frame_rate; s->audio_frequency = audio_frequency; s->audio_layout = audio_layout; + + // deep copy all of the sequence's clips s->clips.resize(clips.size()); for (int i=0;iclips[i] = copy; } } + + // copy all of the sequence's markers + s->markers = markers; + return s; } From 5b9c389efc286186684e259a4732ac4fb57d6cc7 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 28 Feb 2019 11:25:14 -0800 Subject: [PATCH 4/7] added svg plugin to linuxdeployqt --- .travis/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/script.sh b/.travis/script.sh index b15b61eee..8f172df7e 100644 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -58,7 +58,7 @@ elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export VERSION=$(git rev-parse --short HEAD) # use linuxdeployqt to set up dependencies - ./linuxdeployqt-continuous-x86_64.AppImage appdir/usr/share/applications/*.desktop -appimage + ./linuxdeployqt-continuous-x86_64.AppImage appdir/usr/share/applications/*.desktop -extra-plugins=imageformats/libqsvg.so -appimage # 64-bit linuxdeployqt can only generate a 64-bit AppImage # to generate a 32-bit one, we need to download and run 32-bit AppImageTool From cab3c93004cf5486d2b7cebd4550071cc455d558 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 28 Feb 2019 12:33:59 -0800 Subject: [PATCH 5/7] added eof tolerance to frame queue #570 --- rendering/cacher.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/rendering/cacher.cpp b/rendering/cacher.cpp index efd0eabdf..6c5785bb8 100644 --- a/rendering/cacher.cpp +++ b/rendering/cacher.cpp @@ -571,13 +571,12 @@ void Cacher::CacheVideoWorker() { do { AVFrame* decoded_frame; -// qint64 time = QDateTime::currentMSecsSinceEpoch(); + // retrieve raw RGBA frame from decoder + filter stack int retrieve_code = RetrieveFrameAndProcess(&decoded_frame); - //qDebug() << "decode took:" << (QDateTime::currentMSecsSinceEpoch() - time); - // for some reason we were unable to retrieve a frame, likely a decoder error so we report it - // again an EOF, is not really an "error", and we can continue execution if we encounter it if (retrieve_code < 0 && retrieve_code != AVERROR_EOF) { + // for some reason we were unable to retrieve a frame, likely a decoder error so we report it + // again, an EOF isn't an "error" but will how we add frames (see below) qCritical() << "Failed to retrieve frame from buffersink." << retrieve_code; @@ -668,7 +667,22 @@ void Cacher::CacheVideoWorker() { qWarning() << clip->name() << "frame had no PTS value"; av_frame_free(&decoded_frame); - SetRetrievedFrame(nullptr); + + if (retrieve_code == AVERROR_EOF && retrieved_frame == nullptr) { + // if we reached the end of the file, it's not an error but there are no more frames to retrieve + // some formats EOF before the end of the duration that Olive calculates. In this event, we simply + // return the last frame we retrieved + // + // TODO: Check duration formula + + SetRetrievedFrame(queue.last()); + + } else { + + SetRetrievedFrame(nullptr); + + } + break; } From 0d0aa2af65992dc70da5b9389e51fb058cd9e35a Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 28 Feb 2019 12:36:49 -0800 Subject: [PATCH 6/7] fixed old casts in Footage::get_length_in_frames --- project/footage.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/project/footage.cpp b/project/footage.cpp index b7e7f5a28..d4654410d 100644 --- a/project/footage.cpp +++ b/project/footage.cpp @@ -55,7 +55,9 @@ void Footage::reset() { } long Footage::get_length_in_frames(double frame_rate) { - if (length >= 0) return qFloor(((double) length / (double) AV_TIME_BASE) * frame_rate / speed); + if (length >= 0) { + return qFloor((double(length) / double(AV_TIME_BASE)) * frame_rate / speed); + } return 0; } From 6c166a1a4e6068857c1daeb4f9bae034e6d06652 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 28 Feb 2019 12:58:28 -0800 Subject: [PATCH 7/7] XML formatted panel layout config file --- mainwindow.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 03ce31903..bd2b25bc2 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -73,9 +73,22 @@ MainWindow* olive::MainWindow; void MainWindow::setup_layout(bool reset) { // load panels from file if (!reset) { - QFile panel_config(get_config_path() + "/layout"); + QFile panel_config(get_config_dir().filePath("layout")); if (panel_config.exists() && panel_config.open(QFile::ReadOnly)) { - restoreState(panel_config.readAll(), 0); + + // default to resetting unless we find the tag in the XML file + reset = true; + + // read XML layout file + QXmlStreamReader stream(&panel_config); + while (!stream.atEnd()) { + stream.readNextStartElement(); + if (stream.name() == "panels") { + restoreState(QByteArray::fromBase64(stream.readElementText().toUtf8()), 0); + reset = false; + } + } + panel_config.close(); } else { reset = true; @@ -888,9 +901,14 @@ void MainWindow::closeEvent(QCloseEvent *e) { olive::CurrentConfig.save(config_fn); // save panel layout - QFile panel_config(config_path + "/layout"); + QFile panel_config(get_config_dir().filePath("layout")); if (panel_config.open(QFile::WriteOnly)) { - panel_config.write(saveState(0)); + QXmlStreamWriter stream(&panel_config); + stream.writeStartDocument(); + + stream.writeTextElement("panels", saveState(0).toBase64()); + + stream.writeEndDocument(); panel_config.close(); } else { qCritical() << "Failed to save layout";