diff --git a/.github/ISSUE_TEMPLATE/00-olive_unsupported.md b/.github/ISSUE_TEMPLATE/00-olive_unsupported.md
index 700c5c1cb..88e715ff8 100644
--- a/.github/ISSUE_TEMPLATE/00-olive_unsupported.md
+++ b/.github/ISSUE_TEMPLATE/00-olive_unsupported.md
@@ -5,7 +5,6 @@ title: "[UNSUPPORTED]"
labels: "Legacy (Unsupported)"
assignees: ''
---
-
# Olive 0.1 is unsupported
Unfortunately no one is supporting Olive 0.1 at this time. Any reports pertaining to it will be
diff --git a/.github/ISSUE_TEMPLATE/01-crash_issue.md b/.github/ISSUE_TEMPLATE/01-crash_issue.md
index 0b68b7202..87e916dee 100644
--- a/.github/ISSUE_TEMPLATE/01-crash_issue.md
+++ b/.github/ISSUE_TEMPLATE/01-crash_issue.md
@@ -4,16 +4,26 @@ about: Report a fatal crash that resulted in Olive unexpectedly closing.
title: "[CRASH]"
labels: "Crash, Triage"
assignees: ''
-
---
-**Commit Hash (8 character string of letters/numbers in title bar)**
+**Commit Hash**
+
**Platform**
+
**Summary**
+
**Steps to Reproduce**
-**Backtrace**
+1.
+2.
+3.
+
+Backtrace
+
+
+
+
**Additional Information**
diff --git a/.github/ISSUE_TEMPLATE/50-build_issue.md b/.github/ISSUE_TEMPLATE/50-build_issue.md
index 8d93ad06d..155c7c750 100644
--- a/.github/ISSUE_TEMPLATE/50-build_issue.md
+++ b/.github/ISSUE_TEMPLATE/50-build_issue.md
@@ -4,12 +4,14 @@ about: Report an issue related to compiling or packaging (including continuous i
title: "[BUILD]"
labels: "Building/Packaging, Triage"
assignees: ''
-
---
-**Commit Hash (8 character string of letters/numbers in title bar)**
+**Commit Hash**
+
**Platform**
+
**Summary**
+
**Additional Information / Output**
diff --git a/.github/ISSUE_TEMPLATE/50-cache_issue.md b/.github/ISSUE_TEMPLATE/50-cache_issue.md
index 0d088aa8c..f346d8245 100644
--- a/.github/ISSUE_TEMPLATE/50-cache_issue.md
+++ b/.github/ISSUE_TEMPLATE/50-cache_issue.md
@@ -4,12 +4,14 @@ about: Report an issue related to the disk cache system, including failure to c
title: "[CACHE]"
labels: "Disk Cache, Triage"
assignees: ''
-
---
-**Commit Hash (8 character string of letters/numbers in title bar)**
+**Commit Hash**
+
**Platform**
+
**Summary**
+
**Additional Information / Output**
diff --git a/.github/ISSUE_TEMPLATE/50-codec_issue.md b/.github/ISSUE_TEMPLATE/50-codec_issue.md
index 04082833f..09fc991ac 100644
--- a/.github/ISSUE_TEMPLATE/50-codec_issue.md
+++ b/.github/ISSUE_TEMPLATE/50-codec_issue.md
@@ -4,12 +4,14 @@ about: Report an issue related to codec handling, including importing footage or
title: "[CODEC]"
labels: "Codec, Triage"
assignees: ''
-
---
-**Commit Hash (8 character string of letters/numbers in title bar)**
+**Commit Hash**
+
**Platform**
+
**Summary**
+
**Additional Information / Output**
diff --git a/.github/ISSUE_TEMPLATE/50-color_issue.md b/.github/ISSUE_TEMPLATE/50-color_issue.md
index 99889a56b..99e4c803c 100644
--- a/.github/ISSUE_TEMPLATE/50-color_issue.md
+++ b/.github/ISSUE_TEMPLATE/50-color_issue.md
@@ -4,12 +4,14 @@ about: Report an issue related to the management of pixels and color, including
title: "[COLOR]"
labels: "Color Management, Triage"
assignees: ''
-
---
-**Commit Hash (8 character string of letters/numbers in title bar)**
+**Commit Hash**
+
**Platform**
+
**Summary**
+
**Additional Information / Output**
diff --git a/.github/ISSUE_TEMPLATE/50-editing_issue.md b/.github/ISSUE_TEMPLATE/50-editing_issue.md
index 0465e88a5..88d2f16c1 100644
--- a/.github/ISSUE_TEMPLATE/50-editing_issue.md
+++ b/.github/ISSUE_TEMPLATE/50-editing_issue.md
@@ -4,12 +4,14 @@ about: Report an issue related to the overall editing experience, including usa
title: "[EDIT]"
labels: "Timeline/Editing, Triage"
assignees: ''
-
---
-**Commit Hash (8 character string of letters/numbers in title bar)**
+**Commit Hash**
+
**Platform**
+
**Summary**
+
**Additional Information / Output**
diff --git a/.github/ISSUE_TEMPLATE/50-export_issue.md b/.github/ISSUE_TEMPLATE/50-export_issue.md
index 7ccef22fc..4e6e1f3a2 100644
--- a/.github/ISSUE_TEMPLATE/50-export_issue.md
+++ b/.github/ISSUE_TEMPLATE/50-export_issue.md
@@ -4,12 +4,14 @@ about: Report an issue related to exporting videos from Olive, including errors
title: "[EXPORT]"
labels: "Export, Triage"
assignees: ''
-
---
-**Commit Hash (8 character string of letters/numbers in title bar)**
+**Commit Hash**
+
**Platform**
+
**Summary**
+
**Additional Information / Output**
diff --git a/.github/ISSUE_TEMPLATE/50-node_issue.md b/.github/ISSUE_TEMPLATE/50-node_issue.md
index 4d15ecebe..ec31c8989 100644
--- a/.github/ISSUE_TEMPLATE/50-node_issue.md
+++ b/.github/ISSUE_TEMPLATE/50-node_issue.md
@@ -4,12 +4,14 @@ about: Report an issue related to the node-based compositing system, including
title: "[NODES]"
labels: "Nodes/Compositing, Triage"
assignees: ''
-
---
-**Commit Hash (8 character string of letters/numbers in title bar)**
+**Commit Hash**
+
**Platform**
+
**Summary**
+
**Additional Information / Output**
diff --git a/.github/ISSUE_TEMPLATE/50-playback_issue.md b/.github/ISSUE_TEMPLATE/50-playback_issue.md
index 5e35446f5..32a3cc13b 100644
--- a/.github/ISSUE_TEMPLATE/50-playback_issue.md
+++ b/.github/ISSUE_TEMPLATE/50-playback_issue.md
@@ -4,12 +4,14 @@ about: Report an issue related to the playback of video or audio, including lag
title: "[PLAYBACK]"
labels: "Playback, Triage"
assignees: ''
-
---
-**Commit Hash (8 character string of letters/numbers in title bar)**
+**Commit Hash**
+
**Platform**
+
**Summary**
+
**Additional Information / Output**
diff --git a/.github/ISSUE_TEMPLATE/50-project_issue.md b/.github/ISSUE_TEMPLATE/50-project_issue.md
index fa65f393e..ff9175354 100644
--- a/.github/ISSUE_TEMPLATE/50-project_issue.md
+++ b/.github/ISSUE_TEMPLATE/50-project_issue.md
@@ -4,12 +4,14 @@ about: Report an issue related to project management, including working with an
title: "[PROJECT]"
labels: "Project, Triage"
assignees: ''
-
---
-**Commit Hash (8 character string of letters/numbers in title bar)**
+**Commit Hash**
+
**Platform**
+
**Summary**
+
**Additional Information / Output**
diff --git a/.github/ISSUE_TEMPLATE/50-renderer_issue.md b/.github/ISSUE_TEMPLATE/50-renderer_issue.md
index f97a22079..e77316402 100644
--- a/.github/ISSUE_TEMPLATE/50-renderer_issue.md
+++ b/.github/ISSUE_TEMPLATE/50-renderer_issue.md
@@ -4,12 +4,14 @@ about: Report an issue related to rendering, including corrupted frames, incorr
title: "[RENDER]"
labels: "Renderer, Triage"
assignees: ''
-
---
-**Commit Hash (8 character string of letters/numbers in title bar)**
+**Commit Hash**
+
**Platform**
+
**Summary**
+
**Additional Information / Output**
diff --git a/.github/ISSUE_TEMPLATE/50-ui_issue.md b/.github/ISSUE_TEMPLATE/50-ui_issue.md
index a0cfa3c02..f746024de 100644
--- a/.github/ISSUE_TEMPLATE/50-ui_issue.md
+++ b/.github/ISSUE_TEMPLATE/50-ui_issue.md
@@ -4,12 +4,14 @@ about: Report an issue related to general user interface usability, including b
title: "[UI]"
labels: "User Interface, Triage"
assignees: ''
-
---
-**Commit Hash (8 character string of letters/numbers in title bar)**
+**Commit Hash**
+
**Platform**
+
**Summary**
+
**Additional Information / Output**
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 07ebcbdd7..b4756b7f3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -139,14 +139,21 @@ jobs:
then
mkdir olive-editor
cp app/olive-editor.exe olive-editor
+ cp app/olive-crashhandler.exe olive-editor
cp app/olive-editor.pdb olive-editor
+ windeployqt olive-editor/olive-crashhandler.exe
windeployqt olive-editor/olive-editor.exe
cp $(cygpath $GITHUB_WORKSPACE)/bin/*.dll olive-editor
cp $(cygpath $GITHUB_WORKSPACE)/out/Default/crashpad_handler.exe olive-editor
+ cp $(cygpath $GITHUB_WORKSPACE)/minidump_stackwalk/* olive-editor
elif [ "$MATRIX_OS" == "macos-latest" ]
then
export BUNDLE_NAME=Olive.app
mv app/$BUNDLE_NAME .
+
+ # HACK: OCIO doesn't link it's library properly so we need to manually correct
+ install_name_tool -change libOpenColorIO.1.dylib @rpath/libOpenColorIO.1.dylib $BUNDLE_NAME/Contents/MacOS/Olive
+
macdeployqt $BUNDLE_NAME
$DOWNLOAD_TOOL https://github.com/arl/macdeployqtfix/raw/master/macdeployqtfix.py
python2 macdeployqtfix.py $BUNDLE_NAME/Contents/MacOS/Olive /usr/local/Cellar/qt5/5.*/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2f8ab7419..06a282d31 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,6 +29,8 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
+set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13")
+
set(OLIVE_DEFINITIONS -DAPPVERSION="${PROJECT_VERSION}" -DQT_DEPRECATED_WARNINGS)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
diff --git a/README.md b/README.md
index 9b95c2b60..9291d1b77 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,17 @@
-# Olive Video Editor [](https://travis-ci.org/olive-editor/olive) [](https://ci.appveyor.com/project/itsmattkc/olive)
+# Olive Video Editor [](https://github.com/olive-editor/olive/actions?query=branch%3Amaster)
Olive is a free non-linear video editor for Windows, macOS, and Linux.
-
+
-**Discover more:** [Website](https://www.olivevideoeditor.org/) | [Twitter](https://twitter.com/oliveteam) | [Discord](https://discord.gg/4Ae9KZn) | [Patreon](https://www.patreon.com/olivevideoeditor)
-
-## Getting Started with Olive:
-
-Binaries of Olive are available at: https://olivevideoeditor.org/download.php
-
-Some tutorials can be seen on the GitHub Wiki: https://github.com/olive-editor/olive/wiki/Overview-Guide
+**Discover more:** [Website](https://www.olivevideoeditor.org/) | [Binaries](https://olivevideoeditor.org/download.php) | [Twitter](https://twitter.com/oliveteam) | [Discord](https://discord.gg/4Ae9KZn) | [Patreon](https://www.patreon.com/olivevideoeditor) | [Tutorials](https://github.com/olive-editor/olive/wiki/Overview-Guide)
**NOTE: Olive is alpha software and is considered highly unstable. While we highly appreciate users testing and providing usage information, please use at your own risk.**
+## Binaries
+
+[Nightly binaries are available on the website.](https://olivevideoeditor.org/download.php)
+
## Support Olive:
Please consider supporting Olive:
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index a313bb3a2..46a6ba9a3 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -185,6 +185,54 @@ if (GoogleCrashpad_FOUND)
PRIVATE
${CRASHPAD_LIBRARIES}
)
+
+ set(OLIVE_CRASH_TARGET "olive-crashhandler")
+
+ set(OLIVE_CRASH_SOURCES
+ dialog/crashhandler/crashhandler.h
+ dialog/crashhandler/crashhandler.cpp
+ dialog/crashhandler/crashhandlermain.cpp
+ )
+
+ if (WIN32)
+ add_executable(
+ ${OLIVE_CRASH_TARGET}
+ WIN32
+ ${OLIVE_CRASH_SOURCES}
+ )
+ else()
+ add_executable(
+ ${OLIVE_CRASH_TARGET}
+ ${OLIVE_CRASH_SOURCES}
+ )
+ endif()
+
+ target_include_directories(
+ ${OLIVE_CRASH_TARGET}
+ PRIVATE
+ ${CRASHPAD_INCLUDE_DIRS}
+ )
+
+ target_link_libraries(
+ ${OLIVE_CRASH_TARGET}
+ PRIVATE
+ Qt5::Core
+ Qt5::Gui
+ Qt5::Widgets
+ Qt5::Network
+ ${CRASHPAD_LIBRARIES}
+ )
+
+ if(UNIX AND NOT APPLE)
+ install(TARGETS ${OLIVE_TARGET} ${OLIVE_CRASH_TARGET} RUNTIME DESTINATION bin)
+ endif()
+
+ if(APPLE)
+ # Move crash handler program inside Mac app bundle
+ add_custom_command(TARGET ${OLIVE_CRASH_TARGET} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${OLIVE_CRASH_TARGET} $
+ )
+ endif()
endif()
# Set compiler definitions
@@ -209,43 +257,3 @@ if(DOXYGEN_FOUND)
set(DOXYGEN_EXTRACT_PRIVATE "YES")
doxygen_add_docs(docs ALL ${OLIVE_SOURCES})
endif()
-
-set(OLIVE_CRASH_TARGET "olive-crashhandler")
-
-set(OLIVE_CRASH_SOURCES
- dialog/crashhandler/crashhandler.h
- dialog/crashhandler/crashhandler.cpp
- dialog/crashhandler/crashhandlermain.cpp
-)
-
-if (WIN32)
- add_executable(
- ${OLIVE_CRASH_TARGET}
- WIN32
- ${OLIVE_CRASH_SOURCES}
- )
-else()
- add_executable(
- ${OLIVE_CRASH_TARGET}
- ${OLIVE_CRASH_SOURCES}
- )
-endif()
-
-target_link_libraries(
- ${OLIVE_CRASH_TARGET}
- PRIVATE
- Qt5::Core
- Qt5::Gui
- Qt5::Widgets
-)
-
-if(UNIX AND NOT APPLE)
- install(TARGETS ${OLIVE_TARGET} ${OLIVE_CRASH_TARGET} RUNTIME DESTINATION bin)
-endif()
-
-if(APPLE)
- # Move crash handler program inside Mac app bundle
- add_custom_command(TARGET ${OLIVE_CRASH_TARGET} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${OLIVE_CRASH_TARGET} $
- )
-endif()
diff --git a/app/codec/oiio/oiiodecoder.cpp b/app/codec/oiio/oiiodecoder.cpp
index 395284c44..bfaf46960 100644
--- a/app/codec/oiio/oiiodecoder.cpp
+++ b/app/codec/oiio/oiiodecoder.cpp
@@ -68,11 +68,17 @@ bool OIIODecoder::Probe(Footage *f, const QAtomicInt *cancelled)
// Heuristically determine whether this file is part of an image sequence or not
if (GetImageSequenceDigitCount(f->filename()) > 0) {
+ QSize dim(in->spec().width, in->spec().height);
+
int64_t ind = GetImageSequenceIndex(f->filename());
// Check if files around exist around it with that follow a sequence
- if (QFileInfo::exists(TransformImageSequenceFileName(f->filename(), ind - 1))
- || QFileInfo::exists(TransformImageSequenceFileName(f->filename(), ind + 1))) {
+ QString previous_img_fn = TransformImageSequenceFileName(f->filename(), ind - 1);
+ QString next_img_fn = TransformImageSequenceFileName(f->filename(), ind + 1);
+
+ // GetImageDimensions will return a 0,0 size if the file doesn't exist, so it's safe to check
+ // both existence and matching size with this
+ if (GetImageDimensions(previous_img_fn) == dim || GetImageDimensions(next_img_fn) == dim) {
// We need user feedback here and since UI must occur in the UI thread (and we could be in any thread), we defer
// to the Core which will definitely be in the UI thread and block here until we get an answer from the user
QMetaObject::invokeMethod(Core::instance(),
@@ -316,6 +322,25 @@ bool OIIODecoder::FileTypeIsSupported(const QString& fn)
return true;
}
+QSize OIIODecoder::GetImageDimensions(const QString &fn)
+{
+ QSize sz;
+ auto in = OIIO::ImageInput::open(fn.toStdString());
+
+ if (in) {
+ sz.setWidth(in->spec().width);
+ sz.setHeight(in->spec().height);
+
+ in->close();
+
+#if OIIO_VERSION < 10903
+ OIIO::ImageInput::destroy(in);
+#endif
+ }
+
+ return sz;
+}
+
bool OIIODecoder::OpenImageHandler(const QString &fn)
{
image_ = OIIO::ImageInput::open(fn.toStdString());
diff --git a/app/codec/oiio/oiiodecoder.h b/app/codec/oiio/oiiodecoder.h
index ff278fa63..979923be2 100644
--- a/app/codec/oiio/oiiodecoder.h
+++ b/app/codec/oiio/oiiodecoder.h
@@ -68,6 +68,8 @@ private:
static bool FileTypeIsSupported(const QString& fn);
+ static QSize GetImageDimensions(const QString& fn);
+
bool OpenImageHandler(const QString& fn);
void CloseImageHandle();
diff --git a/app/common/CMakeLists.txt b/app/common/CMakeLists.txt
index ee07f43c4..99521453c 100644
--- a/app/common/CMakeLists.txt
+++ b/app/common/CMakeLists.txt
@@ -23,10 +23,9 @@ set(OLIVE_SOURCES
common/clamp.h
common/commandlineparser.h
common/commandlineparser.cpp
- common/crashhandler.h
- common/crashhandler.cpp
- common/crashpadinterface.cpp
common/crashpadinterface.h
+ common/crashpadinterface.cpp
+ common/crashpadutils.h
common/debug.h
common/debug.cpp
common/define.h
diff --git a/app/common/crashhandler.cpp b/app/common/crashhandler.cpp
deleted file mode 100644
index 469e45233..000000000
--- a/app/common/crashhandler.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/***
-
- Olive - Non-Linear Video Editor
- Copyright (C) 2019 Olive Team
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-
-***/
-
-#include "crashhandler.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#if defined(Q_OS_WINDOWS)
-#include
-#include
-#include
-#include
-#elif defined(Q_OS_MAC) || defined(Q_OS_LINUX)
-#include
-#endif
-
-#include "common/filefunctions.h"
-
-OLIVE_NAMESPACE_ENTER
-
-void crash_handler(int sig)
-{
- QString log_path = QDir(FileFunctions::GetTempFilePath()).filePath(QStringLiteral("olive_crash"));
- QFile output(log_path);
-
- output.open(QFile::WriteOnly);
- QTextStream ostream(&output);
-
-#ifdef GITHASH
- ostream << "Version: " << GITHASH << "\n";
-#endif
- ostream << "Signal: " << sig << "\n\n";
-
-#if defined(Q_OS_WINDOWS)
- // Use Windows stackwalk API
- HANDLE process = GetCurrentProcess();
- HANDLE thread = GetCurrentThread();
-
- CONTEXT context;
- memset(&context, 0, sizeof(CONTEXT));
- context.ContextFlags = CONTEXT_FULL;
- RtlCaptureContext(&context);
-
- SymInitialize(process, NULL, TRUE);
-
- DWORD image;
- STACKFRAME64 stackframe;
- ZeroMemory(&stackframe, sizeof(STACKFRAME64));
-
-#ifdef _M_IX86
- image = IMAGE_FILE_MACHINE_I386;
- stackframe.AddrPC.Offset = context.Eip;
- stackframe.AddrPC.Mode = AddrModeFlat;
- stackframe.AddrFrame.Offset = context.Ebp;
- stackframe.AddrFrame.Mode = AddrModeFlat;
- stackframe.AddrStack.Offset = context.Esp;
- stackframe.AddrStack.Mode = AddrModeFlat;
-#elif _M_X64
- image = IMAGE_FILE_MACHINE_AMD64;
- stackframe.AddrPC.Offset = context.Rip;
- stackframe.AddrPC.Mode = AddrModeFlat;
- stackframe.AddrFrame.Offset = context.Rsp;
- stackframe.AddrFrame.Mode = AddrModeFlat;
- stackframe.AddrStack.Offset = context.Rsp;
- stackframe.AddrStack.Mode = AddrModeFlat;
-#elif _M_IA64
- image = IMAGE_FILE_MACHINE_IA64;
- stackframe.AddrPC.Offset = context.StIIP;
- stackframe.AddrPC.Mode = AddrModeFlat;
- stackframe.AddrFrame.Offset = context.IntSp;
- stackframe.AddrFrame.Mode = AddrModeFlat;
- stackframe.AddrBStore.Offset = context.RsBSP;
- stackframe.AddrBStore.Mode = AddrModeFlat;
- stackframe.AddrStack.Offset = context.IntSp;
- stackframe.AddrStack.Mode = AddrModeFlat;
-#endif
-
- for (int i = 0; i < 50; i++) {
-
- BOOL result = StackWalk64(
- image, process, thread,
- &stackframe, &context, NULL,
- SymFunctionTableAccess64, SymGetModuleBase64, NULL);
-
- if (!result) { break; }
-
- char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
- PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
- symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
- symbol->MaxNameLen = MAX_SYM_NAME;
-
- DWORD64 displacement = 0;
-
- ostream << "[" << i << "] ";
-
- if (SymFromAddr(process, stackframe.AddrPC.Offset, &displacement, symbol)) {
- ostream << symbol->Name;
- //printf("[%i] %s\n", i, symbol->Name);
- } else {
- ostream << "???";
- //printf("[%i] ???\n", i);
- }
-
- ostream << "\n";
- }
-
- SymCleanup(process);
-#elif defined(Q_OS_MAC) || defined(Q_OS_LINUX)
- void *array[10];
- size_t size;
-
- // get void*'s for all entries on the stack
- size = backtrace(array, 10);
-
- // print out all the frames to stderr
- backtrace_symbols_fd(array, size, output.handle());
-#endif
-
- output.close();
-
- QString crash_handler_exe = QDir(qApp->applicationDirPath()).filePath(QStringLiteral("olive-crashhandler"));
- QProcess::startDetached(crash_handler_exe, {log_path});
-
- exit(1);
-}
-
-OLIVE_NAMESPACE_EXIT
diff --git a/app/common/crashpadinterface.cpp b/app/common/crashpadinterface.cpp
index 770e8a84a..393cba4c6 100644
--- a/app/common/crashpadinterface.cpp
+++ b/app/common/crashpadinterface.cpp
@@ -23,75 +23,67 @@
#ifdef USE_CRASHPAD
#include
+#include
#include
#include
#include
+#include
+#include "crashpadutils.h"
#include "filefunctions.h"
-#ifdef Q_OS_WINDOWS
+#ifdef OS_WIN
#include
#endif
-// Copied from base::FilePath to match its macro
-#if defined(OS_POSIX)
-// On most platforms, native pathnames are char arrays, and the encoding
-// may or may not be specified. On Mac OS X, native pathnames are encoded
-// in UTF-8.
-#define TO_BASE_STRING_TYPE(x) x.toStdString()
-#elif defined(OS_WIN)
-// On Windows, for Unicode-aware applications, native pathnames are wchar_t
-// arrays encoded in UTF-16.
-#define TO_BASE_STRING_TYPE(x) x.toStdWString()
-#endif // OS_WIN
-
crashpad::CrashpadClient *client;
-bool ShowCrashConfirmation()
+QString GenerateReportPath()
{
- QString msg = QCoreApplication::translate("CrashReport",
- "We're sorry, Olive has crashed. "
- "Would you like to send an error report to "
- "help developers fix this issue?\n\n"
- "Crash reports are anonymous and only send "
- "non-specific details about your computer and"
- "how the crash occurred.");
-
- return (QMessageBox::critical(nullptr,
- QString(),
- msg,
- QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes);
+ return QDir(OLIVE_NAMESPACE::FileFunctions::GetTempFilePath()).filePath(QStringLiteral("reports"));
}
-#ifdef Q_OS_WINDOWS
+base::FilePath GenerateReportPathForCrashpad()
+{
+ return base::FilePath(QSTRING_TO_BASE_STRING(GenerateReportPath()));
+}
+
+#if defined(OS_WIN)
LONG WINAPI Win32ExceptionHandler(_EXCEPTION_POINTERS *ExceptionInfo)
{
- if (ShowCrashConfirmation()) {
- client->DumpAndCrash(ExceptionInfo);
- }
+ QString crash_handler_exe = QDir(qApp->applicationDirPath()).filePath(QStringLiteral("olive-crashhandler"));
+ QProcess::startDetached(crash_handler_exe, {GenerateReportPath(), QString::number(QDateTime::currentSecsSinceEpoch())});
+
+ client->DumpAndCrash(ExceptionInfo);
return EXCEPTION_CONTINUE_SEARCH;
}
+#elif defined(OS_LINUX)
+bool LinuxExceptionHandler(int, siginfo_t*, ucontext_t*)
+{
+ QString crash_handler_exe = QDir(qApp->applicationDirPath()).filePath(QStringLiteral("olive-crashhandler"));
+ QProcess::startDetached(crash_handler_exe, {GenerateReportPath(), QString::number(QDateTime::currentSecsSinceEpoch())});
+
+ // Returning false signals to Crashpad to proceed with its own exception handling
+ return false;
+}
#endif
bool InitializeCrashpad()
{
QString exe_dir = QCoreApplication::applicationDirPath();
+#ifdef OS_WIN
+ base::FilePath handler(QSTRING_TO_BASE_STRING(QDir(exe_dir).filePath(QStringLiteral("crashpad_handler.exe"))));
+#else
// FIXME: On Linux, probably should put this in a subdir so that it doesn't conflict with
// anything else in /usr/bin
-
-#ifdef Q_OS_WINDOWS
- base::FilePath handler(TO_BASE_STRING_TYPE(QDir(exe_dir).filePath(QStringLiteral("crashpad_handler.exe"))));
-#else
- base::FilePath handler(TO_BASE_STRING_TYPE(QDir(exe_dir).filePath(QStringLiteral("crashpad_handler"))));
+ base::FilePath handler(QSTRING_TO_BASE_STRING(QDir(exe_dir).filePath(QStringLiteral("crashpad_handler"))));
#endif
- base::FilePath reports_dir(TO_BASE_STRING_TYPE(QDir(OLIVE_NAMESPACE::FileFunctions::GetTempFilePath()).filePath("reports")));
+ base::FilePath reports_dir = GenerateReportPathForCrashpad();
- base::FilePath metrics_dir(TO_BASE_STRING_TYPE(QDir(OLIVE_NAMESPACE::FileFunctions::GetTempFilePath()).filePath("metrics")));
-
- std::string url = "https://olivevideoeditor.org/crashpad/report.php";
+ base::FilePath metrics_dir(QSTRING_TO_BASE_STRING(QDir(OLIVE_NAMESPACE::FileFunctions::GetTempFilePath()).filePath(QStringLiteral("metrics"))));
// Metadata that will be posted to the server with the crash report map
std::map annotations;
@@ -105,19 +97,22 @@ bool InitializeCrashpad()
std::unique_ptr database = crashpad::CrashReportDatabase::Initialize(reports_dir);
if (database == NULL) return false;
- // Enable automated crash uploads
+ // Disable automated crash uploads
crashpad::Settings *settings = database->GetSettings();
if (settings == NULL) return false;
- settings->SetUploadsEnabled(true);
+ settings->SetUploadsEnabled(false);
// Start crash handler
client = new crashpad::CrashpadClient();
bool status = client->StartHandler(handler, reports_dir, metrics_dir,
- url, annotations, arguments, true, true);
+ "https://olivevideoeditor.org/crashpad/report.php",
+ annotations, arguments, true, true);
// Override Crashpad exception filter with our own
-#ifdef Q_OS_WINDOWS
+#if defined(OS_WIN)
SetUnhandledExceptionFilter(Win32ExceptionHandler);
+#elif defined(OS_LINUX)
+ crashpad::CrashpadClient::SetFirstChanceExceptionHandler(LinuxExceptionHandler);
#endif
return status;
diff --git a/app/common/crashpadinterface.h b/app/common/crashpadinterface.h
index 26bd17b65..2388ece96 100644
--- a/app/common/crashpadinterface.h
+++ b/app/common/crashpadinterface.h
@@ -23,7 +23,6 @@
#ifdef USE_CRASHPAD
-#include
#include
#include
diff --git a/app/common/crashhandler.h b/app/common/crashpadutils.h
similarity index 50%
rename from app/common/crashhandler.h
rename to app/common/crashpadutils.h
index 10ed30627..a2a36e49d 100644
--- a/app/common/crashhandler.h
+++ b/app/common/crashpadutils.h
@@ -18,15 +18,23 @@
***/
-#ifndef CRASHHANDLER_H
-#define CRASHHANDLER_H
+#ifndef CRASHPADUTILS_H
+#define CRASHPADUTILS_H
-#include "common/define.h"
+#include
-OLIVE_NAMESPACE_ENTER
+// Copied from base::FilePath to match its macro
+#if defined(OS_POSIX)
+// On most platforms, native pathnames are char arrays, and the encoding
+// may or may not be specified. On Mac OS X, native pathnames are encoded
+// in UTF-8.
+#define QSTRING_TO_BASE_STRING(x) x.toStdString()
+#define BASE_STRING_TO_QSTRING(x) QString::fromStdString(x)
+#elif defined(OS_WIN)
+// On Windows, for Unicode-aware applications, native pathnames are wchar_t
+// arrays encoded in UTF-16.
+#define QSTRING_TO_BASE_STRING(x) x.toStdWString()
+#define BASE_STRING_TO_QSTRING(x) QString::fromStdWString(x)
+#endif // OS_WIN
-void crash_handler(int sig);
-
-OLIVE_NAMESPACE_EXIT
-
-#endif // CRASHHANDLER_H
+#endif // CRASHPADUTILS_H
diff --git a/app/dialog/crashhandler/crashhandler.cpp b/app/dialog/crashhandler/crashhandler.cpp
index 7645eb5f9..e6120a5d9 100644
--- a/app/dialog/crashhandler/crashhandler.cpp
+++ b/app/dialog/crashhandler/crashhandler.cpp
@@ -20,66 +20,181 @@
#include "crashhandler.h"
+#include
+#include
#include
+#include
#include
-#include
+#include
+#include
+#include
+#include
#include
-#include
+#include
+#include
#include
+#include "common/crashpadutils.h"
+
OLIVE_NAMESPACE_ENTER
-CrashHandlerDialog::CrashHandlerDialog(const char *log_file)
+CrashHandlerDialog::CrashHandlerDialog(const char *report_dir, const char* crash_time)
{
setWindowTitle(tr("Olive"));
+ crash_time_ = QString(crash_time).toULongLong();
+ report_dir_ = report_dir;
QVBoxLayout* layout = new QVBoxLayout(this);
- layout->addWidget(new QLabel(tr("We're sorry, Olive has crashed. Please send the following log to the developers to "
- "help resolve this.")));
+ layout->addWidget(new QLabel(tr("We're sorry, Olive has crashed. Please help us fix it by "
+ "sending an error report.")));
- QTextEdit* edit = new QTextEdit();
- edit->setReadOnly(true);
- layout->addWidget(edit);
+ summary_edit_ = new QTextEdit();
+ summary_edit_->setPlaceholderText(tr("Describe what you were doing in as much detail as "
+ "possible. If you can, provide steps to reproduce this crash."));
- edit->append(QStringLiteral("Build Environment: %1 (%2)").arg(QSysInfo::buildCpuArchitecture(), QSysInfo::buildAbi()));
- edit->append(QStringLiteral("Run Environment: %1").arg(QSysInfo::currentCpuArchitecture()));
- edit->append(QStringLiteral("Kernel: %1 %2").arg(QSysInfo::kernelType(), QSysInfo::kernelVersion()));
- edit->append(QStringLiteral("System: %1 (%2 %3)").arg(QSysInfo::prettyProductName(), QSysInfo::productType(), QSysInfo::productVersion()));
- edit->append(QString());
+ layout->addWidget(summary_edit_);
- QDialogButtonBox* buttons = new QDialogButtonBox();
+ layout->addWidget(new QLabel(tr("Crash Report:")));
- // FIXME: Implement auto-reporting
- //buttons->addButton(tr("Send Error Report"), QDialogButtonBox::AcceptRole);
- //buttons->addButton(tr("Don't Send"), QDialogButtonBox::RejectRole);
- buttons->addButton(QDialogButtonBox::Ok);
+ crash_report_ = new QTextEdit();
+ crash_report_->setReadOnly(true);
+ crash_report_->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
+ layout->addWidget(crash_report_);
- connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
- connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
- layout->addWidget(buttons);
+ QHBoxLayout* btn_layout = new QHBoxLayout();
+ btn_layout->setMargin(0);
+ btn_layout->addStretch();
- QFile log(log_file);
- if (log.open(QFile::ReadOnly | QFile::Text)) {
- edit->append(log.readAll());
+ send_report_btn_ = new QPushButton(tr("Send Error Report"));
+ connect(send_report_btn_, &QPushButton::clicked, this, &CrashHandlerDialog::SendErrorReport);
+ btn_layout->addWidget(send_report_btn_);
- QMetaObject::invokeMethod(edit->verticalScrollBar(),
- "setValue",
- Qt::QueuedConnection,
- Q_ARG(int, 0));
+ dont_send_btn_ = new QPushButton(tr("Don't Send"));
+ connect(dont_send_btn_, &QPushButton::clicked, this, &CrashHandlerDialog::reject);
+ btn_layout->addWidget(dont_send_btn_);
- log.close();
+ layout->addLayout(btn_layout);
+
+ crash_report_->setEnabled(false);
+ send_report_btn_->setEnabled(false);
+
+ crash_report_->setText(tr("Waiting for crash report to be generated..."));
+
+ AttemptToFindReport();
+}
+
+void CrashHandlerDialog::SetGUIObjectsEnabled(bool e)
+{
+ summary_edit_->setEnabled(e);
+ crash_report_->setEnabled(e);
+ send_report_btn_->setEnabled(e);
+ dont_send_btn_->setEnabled(e);
+}
+
+void CrashHandlerDialog::GenerateReport()
+{
+ QProcess* p = new QProcess();
+
+ connect(p, QOverload::of(&QProcess::finished),
+ this, &CrashHandlerDialog::ReadProcessFinished);
+ connect(p, &QProcess::readyReadStandardOutput, this, &CrashHandlerDialog::ReadProcessHasData);
+
+ QString stackwalk_filename;
+
+#if defined(OS_WIN)
+ stackwalk_filename = QStringLiteral("minidump_stackwalk.exe");
+#else
+ stackwalk_filename = QStringLiteral("minidump_stackwalk");
+#endif
+
+ QString stackwalk_bin = QDir(qApp->applicationDirPath()).filePath(stackwalk_filename);
+ p->start(stackwalk_bin, {report_filename_});
+ crash_report_->setText(QStringLiteral("Trying to run: %1").arg(stackwalk_bin));
+}
+
+void CrashHandlerDialog::ReplyFinished(QNetworkReply* reply)
+{
+ if (reply->error() == QNetworkReply::NoError) {
+ // Close dialog
+ QDialog::accept();
+ } else {
+ QMessageBox::critical(this, tr("Upload Failed"),
+ tr("Failed to send error report. Please try again later."),
+ QMessageBox::Ok);
+ SetGUIObjectsEnabled(true);
}
}
-void CrashHandlerDialog::accept()
+void CrashHandlerDialog::AttemptToFindReport()
{
- QDialog::accept();
+ // Retrieve reports from Crashpad database
+ std::unique_ptr database = crashpad::CrashReportDatabase::Initialize(base::FilePath(QSTRING_TO_BASE_STRING(QString(report_dir_))));
+ std::vector reports;
+ database->GetCompletedReports(&reports);
+
+ // Find report that was made after the crash time
+ foreach (const crashpad::CrashReportDatabase::Report& report, reports) {
+ if (report.creation_time >= crash_time_) {
+ report_filename_ = BASE_STRING_TO_QSTRING(report.file_path.value());
+ break;
+ }
+ }
+
+ // If we found it, use it, otherwise wait a second and try again
+ if (report_filename_.isEmpty()) {
+ // Couldn't find report, try again in one second
+ QTimer::singleShot(500, this, &CrashHandlerDialog::AttemptToFindReport);
+ } else {
+ GenerateReport();
+ }
}
-void CrashHandlerDialog::reject()
+void CrashHandlerDialog::ReadProcessHasData()
{
- QDialog::reject();
+ report_data_.append(static_cast(sender())->readAllStandardOutput());
+}
+
+void CrashHandlerDialog::ReadProcessFinished()
+{
+ SetGUIObjectsEnabled(true);
+ crash_report_->setText(report_data_);
+ delete sender();
+}
+
+void CrashHandlerDialog::SendErrorReport()
+{
+ SetGUIObjectsEnabled(false);
+
+ QNetworkAccessManager* manager = new QNetworkAccessManager();
+ connect(manager, &QNetworkAccessManager::finished, this, &CrashHandlerDialog::ReplyFinished);
+
+ QNetworkRequest request;
+ request.setSslConfiguration(QSslConfiguration::defaultConfiguration());
+ request.setUrl(QStringLiteral("https://olivevideoeditor.org/crashpad/report.php"));
+
+ // Create HTTP form
+ QHttpMultiPart* multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
+
+ // Create description section
+ QHttpPart desc_part;
+ desc_part.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("text/plain"));
+ desc_part.setHeader(QNetworkRequest::ContentDispositionHeader, QStringLiteral("form-data; name=\"description\""));
+ desc_part.setBody(summary_edit_->toPlainText().toUtf8());
+ multipart->append(desc_part);
+
+ // Create file section
+ QHttpPart file_part;
+ file_part.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/octet-stream"));
+ file_part.setHeader(QNetworkRequest::ContentDispositionHeader, QStringLiteral("form-data; name=\"upload_file_minidump\"; filename=\"%1\"")
+ .arg(QFileInfo(report_filename_).fileName()));
+ QFile* file = new QFile(report_filename_);
+ file->open(QFile::ReadOnly);
+ file_part.setBodyDevice(file);
+ file->setParent(multipart); // Delete file with multipart
+ multipart->append(file_part);
+
+ manager->post(request, multipart);
}
OLIVE_NAMESPACE_EXIT
diff --git a/app/dialog/crashhandler/crashhandler.h b/app/dialog/crashhandler/crashhandler.h
index 485f1d543..7ec91669b 100644
--- a/app/dialog/crashhandler/crashhandler.h
+++ b/app/dialog/crashhandler/crashhandler.h
@@ -21,7 +21,12 @@
#ifndef CRASHHANDLERDIALOG_H
#define CRASHHANDLERDIALOG_H
+#include
#include
+#include
+#include
+#include
+#include
#include "common/define.h"
@@ -31,12 +36,39 @@ class CrashHandlerDialog : public QDialog
{
Q_OBJECT
public:
- CrashHandlerDialog(const char* log_file);
+ CrashHandlerDialog(const char* report_dir, const char* crash_time);
-public slots:
- virtual void accept() override;
+private:
+ void SetGUIObjectsEnabled(bool e);
- virtual void reject() override;
+ void GenerateReport();
+
+ QTextEdit* summary_edit_;
+
+ QTextEdit* crash_report_;
+
+ QPushButton* send_report_btn_;
+
+ QPushButton* dont_send_btn_;
+
+ QString report_filename_;
+
+ time_t crash_time_;
+
+ QString report_dir_;
+
+ QByteArray report_data_;
+
+private slots:
+ void ReplyFinished(QNetworkReply *reply);
+
+ void AttemptToFindReport();
+
+ void ReadProcessHasData();
+
+ void ReadProcessFinished();
+
+ void SendErrorReport();
};
diff --git a/app/dialog/crashhandler/crashhandlermain.cpp b/app/dialog/crashhandler/crashhandlermain.cpp
index 88032fff4..d0fe76368 100644
--- a/app/dialog/crashhandler/crashhandlermain.cpp
+++ b/app/dialog/crashhandler/crashhandlermain.cpp
@@ -24,13 +24,13 @@
int main(int argc, char *argv[])
{
- if (argc < 2) {
+ if (argc < 3) {
return 1;
}
QApplication a(argc, argv);
- OLIVE_NAMESPACE::CrashHandlerDialog chd(argv[1]);
+ OLIVE_NAMESPACE::CrashHandlerDialog chd(argv[1], argv[2]);
chd.open();
return a.exec();
diff --git a/app/render/backend/renderworker.cpp b/app/render/backend/renderworker.cpp
index 2db075c25..28e8a50f5 100644
--- a/app/render/backend/renderworker.cpp
+++ b/app/render/backend/renderworker.cpp
@@ -126,7 +126,7 @@ void RenderWorker::RenderFrame(RenderTicketPtr ticket, ViewerOutput* viewer, con
FramePtr frame = Frame::Create();
frame->set_timestamp(time);
- if (video_force_download_resolution_) {
+ if (video_force_download_resolution_ || texture.isNull()) {
// If we're setting the resolution ourselves or we're zeroing it out, allocate the frame now
frame->set_video_params(VideoParams(video_params_.width(),
video_params_.height(),
diff --git a/app/render/framehashcache.cpp b/app/render/framehashcache.cpp
index b65234dc5..387baa12e 100644
--- a/app/render/framehashcache.cpp
+++ b/app/render/framehashcache.cpp
@@ -358,12 +358,17 @@ void FrameHashCache::HashDeleted(const QString& s, const QByteArray &hash)
return;
}
+ TimeRangeList ranges_to_invalidate;
QMap::const_iterator i;
for (i=time_hash_map_.constBegin(); i!=time_hash_map_.constEnd(); i++) {
if (i.value() == hash) {
- Invalidate(TimeRange(i.key(), i.key() + timebase_));
+ ranges_to_invalidate.InsertTimeRange(TimeRange(i.key(), i.key() + timebase_));
}
}
+
+ foreach (const TimeRange& range, ranges_to_invalidate) {
+ Invalidate(range);
+ }
}
void FrameHashCache::ProjectInvalidated(Project *p)
diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp
index 25f13ac58..983f422e1 100644
--- a/app/widget/viewer/viewerdisplay.cpp
+++ b/app/widget/viewer/viewerdisplay.cpp
@@ -99,11 +99,7 @@ void ViewerDisplayWidget::SetSignalCursorColorEnabled(bool e)
void ViewerDisplayWidget::SetImage(FramePtr in_buffer)
{
- if (in_buffer && in_buffer->is_allocated()) {
- last_loaded_buffer_ = in_buffer;
- } else {
- last_loaded_buffer_ = nullptr;
- }
+ last_loaded_buffer_ = in_buffer;
if (last_loaded_buffer_) {
makeCurrent();
diff --git a/cmake/FindGoogleCrashpad.cmake b/cmake/FindGoogleCrashpad.cmake
index 60ef6b849..17474a407 100644
--- a/cmake/FindGoogleCrashpad.cmake
+++ b/cmake/FindGoogleCrashpad.cmake
@@ -79,6 +79,10 @@ foreach (COMPONENT ${_crashpad_components})
list(APPEND CRASHPAD_LIBRARIES ${CRASHPAD_${UPPERCOMPONENT}_LIB})
endforeach()
+if (UNIX AND NOT APPLE)
+ list(APPEND CRASHPAD_LIBRARIES ${CMAKE_DL_LIBS} Threads::Threads)
+endif()
+
find_package_handle_standard_args(GoogleCrashpad
REQUIRED_VARS
CRASHPAD_LIBRARIES