From 6a6aaddb74c3ed0923ee14df7094c588f28cf3bf Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 16 Sep 2020 16:41:23 +1000 Subject: [PATCH 01/14] crashpad: ask users before submitting report --- app/common/crashpadinterface.cpp | 56 +++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/app/common/crashpadinterface.cpp b/app/common/crashpadinterface.cpp index 85cf37fad..6c55ab45e 100644 --- a/app/common/crashpadinterface.cpp +++ b/app/common/crashpadinterface.cpp @@ -25,21 +25,55 @@ #include #include #include +#include #include "filefunctions.h" +#ifdef Q_OS_WINDOWS +#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() +// 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() +// 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 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); +} + +#ifdef Q_OS_WINDOWS +LONG WINAPI Win32ExceptionHandler(_EXCEPTION_POINTERS *ExceptionInfo) +{ + if (ShowCrashConfirmation()) { + client->DumpAndCrash(ExceptionInfo); + } + + return EXCEPTION_CONTINUE_SEARCH; +} +#endif + bool InitializeCrashpad() { QString exe_dir = QCoreApplication::applicationDirPath(); @@ -73,9 +107,15 @@ bool InitializeCrashpad() settings->SetUploadsEnabled(true); // Start crash handler - crashpad::CrashpadClient *client = new crashpad::CrashpadClient(); + client = new crashpad::CrashpadClient(); bool status = client->StartHandler(handler, reports_dir, metrics_dir, url, annotations, arguments, true, true); + + // Override Crashpad exception filter with our own +#ifdef Q_OS_WINDOWS + SetUnhandledExceptionFilter(Win32ExceptionHandler); +#endif + return status; } From b5863fdadd91d531fc70c656cd7b0eacfa53e93f Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 18 Sep 2020 11:34:10 +1000 Subject: [PATCH 02/14] workaround: don't use standardPalette on Qt 5.15 --- app/ui/style/style.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/ui/style/style.cpp b/app/ui/style/style.cpp index 9de184cb1..26ee7d86f 100644 --- a/app/ui/style/style.cpp +++ b/app/ui/style/style.cpp @@ -39,6 +39,7 @@ QMap StyleManager::available_themes_; void StyleManager::UseOSNativeStyling(QWidget *widget) { +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) || QT_VERSION > QT_VERSION_CHECK(5, 15, 1) #if defined(Q_OS_WINDOWS) QStyle* s = QStyleFactory::create(QStringLiteral("windowsvista")); widget->setStyle(s); @@ -48,6 +49,7 @@ void StyleManager::UseOSNativeStyling(QWidget *widget) widget->setStyle(s); widget->setPalette(s->standardPalette()); #endif +#endif } QPalette StyleManager::ParsePalette(const QString& ini_path) From 9a46d4a57fc30d95f63d109ac8601fb6106846b4 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 18 Sep 2020 12:17:05 +1000 Subject: [PATCH 03/14] ci: install visual c++ 2010 redist on windows installer --- .github/workflows/ci.yml | 50 ++++++++++++------------ app/packaging/windows/nsis/olive.nsi | 58 ++++++++++++++-------------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9566f287e..310a45902 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CMake on: push: - branches: + branches: - master env: @@ -24,49 +24,49 @@ jobs: - name: Set package name shell: bash run: echo "::set-env name=PKGNAME::$(echo Olive-${GITHUB_SHA::8}-Windows-x86_64)" - + - uses: actions/checkout@v2 - name: Create Build Environment # Some projects don't allow in-source building, so create a separate build directory # We'll use this as our working directory for all subsequent commands run: cmake -E make_directory ${{runner.workspace}}/build - + - name: Enable Developer Command Prompt uses: ilammy/msvc-dev-cmd@v1.3.0 - + - name: Acquire Qt uses: jurplel/install-qt-action@v2.8.0 with: version: 5.15.1 - + - name: Acquire FFmpeg run: curl -fLOSs --retry 3 http://olivevideoeditor.org/deps/ffmpeg-win.7z && 7z x ffmpeg-win.7z - + - name: Acquire OpenColorIO run: curl -fLOSs --retry 3 http://olivevideoeditor.org/deps/ocio-win.7z && 7z x ocio-win.7z - + - name: Acquire OpenEXR run: curl -fLOSs --retry 3 http://olivevideoeditor.org/deps/openexr-win.7z && 7z x openexr-win.7z - + - name: Acquire OpenImageIO run: curl -fLOSs --retry 3 http://olivevideoeditor.org/deps/oiio-win.7z && 7z x oiio-win.7z - + - name: Acquire libpng run: curl -fLOSs --retry 3 http://olivevideoeditor.org/deps/libpng-win.7z && 7z x libpng-win.7z - + - name: Acquire libtiff run: curl -fLOSs --retry 3 http://olivevideoeditor.org/deps/libtiff-win.7z && 7z x libtiff-win.7z - + - name: Acquire turbojpeg run: curl -fLOSs --retry 3 http://olivevideoeditor.org/deps/turbojpeg-win.7z && 7z x turbojpeg-win.7z - + - name: Acquire zlib run: curl -fLOSs --retry 3 http://olivevideoeditor.org/deps/zlib-win.7z && 7z x zlib-win.7z - + - name: Acquire Boost run: curl -fLOSs --retry 3 http://olivevideoeditor.org/deps/boost-win.7z && 7z x boost-win.7z - + - name: Acquire Crashpad run: curl -fLOSs --retry 3 http://olivevideoeditor.org/deps/crashpad-win.7z && 7z x crashpad-win.7z @@ -75,8 +75,8 @@ jobs: # access regardless of the host operating system shell: bash working-directory: ${{runner.workspace}}/build - # Note the current convention is to use the -S and -B options here to specify source - # and build directories, but this is only available with CMake 3.13 and higher. + # Note the current convention is to use the -S and -B options here to specify source + # and build directories, but this is only available with CMake 3.13 and higher. # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 run: PATH=$GITHUB_WORKSPACE:$PATH cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G "Ninja" @@ -89,7 +89,7 @@ jobs: - name: Test working-directory: ${{runner.workspace}}/build shell: bash - # Execute tests defined by the CMake configuration. + # Execute tests defined by the CMake configuration. # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest -C $BUILD_TYPE @@ -97,44 +97,44 @@ jobs: working-directory: ${{runner.workspace}}/build shell: cmd run: mkdir olive-editor && copy app\olive-editor.exe olive-editor && copy app\olive-editor.pdb olive-editor && windeployqt olive-editor\olive-editor.exe && copy %GITHUB_WORKSPACE%\bin\*.dll olive-editor && copy %GITHUB_WORKSPACE%\out\Default\crashpad_handler.exe olive-editor - + - name: Deploy Installer working-directory: ${{runner.workspace}}/build shell: cmd - run: copy %GITHUB_WORKSPACE%\app\packaging\windows\nsis\* . && copy %GITHUB_WORKSPACE%\LICENSE . && "C:/Program Files (x86)/NSIS/makensis.exe" -V4 -DX64 "-XOutFile %PKGNAME%.exe" olive.nsi - + run: curl -fLOSs https://download.microsoft.com/download/3/2/2/3224B87F-CFA0-4E70-BDA3-3DE650EFEBA5/vcredist_x64.exe && copy %GITHUB_WORKSPACE%\app\packaging\windows\nsis\* . && copy %GITHUB_WORKSPACE%\LICENSE . && "C:/Program Files (x86)/NSIS/makensis.exe" -V4 -DX64 "-XOutFile %PKGNAME%.exe" olive.nsi + - name: Deploy Portable working-directory: ${{runner.workspace}}/build shell: cmd run: type NUL > olive-editor\portable && 7z a %PKGNAME%.zip olive-editor - + - name: Export Crashpad Symbols and Upload To Server working-directory: ${{runner.workspace}}/build shell: cmd env: GH_AUTH_KEY: ${{secrets.GH_AUTH_KEY}} run: curl -fLSs --retry 3 https://github.com/google/breakpad/blob/master/src/tools/windows/binaries/dump_syms.exe?raw=true > dump_syms.exe && dump_syms app\olive-editor.pdb > olive-editor.sym && curl -X POST -F symfile=@olive-editor.sym -F key="%GH_AUTH_KEY%" https://olivevideoeditor.org/crashpad/symbols.php - + - name: Upload Installer to Nightly Page shell: bash working-directory: ${{runner.workspace}}/build env: GH_AUTH_KEY: ${{secrets.GH_AUTH_KEY}} run: curl -X POST -F file=@$PKGNAME.exe -F key="$GH_AUTH_KEY" -F hash="$GITHUB_SHA" -F time="$(git -C $GITHUB_WORKSPACE show -s --format=%ct)" -F comment="$(git -C $GITHUB_WORKSPACE show -s --format=%B)" https://olivevideoeditor.org/dl/push.php - + - name: Upload Portable to Nightly Page shell: bash working-directory: ${{runner.workspace}}/build env: GH_AUTH_KEY: ${{secrets.GH_AUTH_KEY}} run: curl -X POST -F file=@$PKGNAME.zip -F key="$GH_AUTH_KEY" -F hash="$GITHUB_SHA" -F time="$(git -C $GITHUB_WORKSPACE show -s --format=%ct)" -F comment="$(git -C $GITHUB_WORKSPACE show -s --format=%B)" https://olivevideoeditor.org/dl/push.php - + - name: Upload Installer Artifact uses: actions/upload-artifact@v2 with: name: ${{env.PKGNAME}}.exe path: ${{runner.workspace}}/build/${{env.PKGNAME}}.exe - + - name: Upload Portable Artifact uses: actions/upload-artifact@v2 with: diff --git a/app/packaging/windows/nsis/olive.nsi b/app/packaging/windows/nsis/olive.nsi index 9e9d5e4b9..0aa27c8b6 100644 --- a/app/packaging/windows/nsis/olive.nsi +++ b/app/packaging/windows/nsis/olive.nsi @@ -32,35 +32,35 @@ InstallDir "$PROGRAMFILES32\${APP_NAME}" !insertmacro MUI_LANGUAGE "English" -Section "Olive (required)" - - SectionIn RO - - SetOutPath $INSTDIR - - File /r olive-editor\* - - WriteUninstaller "$INSTDIR\uninstall.exe" +Section "Olive" + SectionIn RO + SetOutPath $INSTDIR + File /r olive-editor\* + WriteUninstaller "$INSTDIR\uninstall.exe" + # Install Visual C++ 2010 Redistributable + File "vcredist_x64.exe" + ExecWait '"$INSTDIR\vcredist_x64.exe" /quiet' + Delete "$INSTDIR\vcredist_x64.exe" SectionEnd Section "Create Desktop shortcut" - CreateShortCut "$DESKTOP\${APP_NAME}.lnk" "$INSTDIR\${APP_TARGET}.exe" + CreateShortCut "$DESKTOP\${APP_NAME}.lnk" "$INSTDIR\${APP_TARGET}.exe" SectionEnd Section "Create Start Menu shortcut" - CreateDirectory "$SMPROGRAMS\${APP_NAME}" - CreateShortCut "$SMPROGRAMS\${APP_NAME}\${APP_NAME}.lnk" "$INSTDIR\${APP_TARGET}.exe" - CreateShortCut "$SMPROGRAMS\${APP_NAME}\Uninstall ${APP_NAME}.lnk" "$INSTDIR\uninstall.exe" + CreateDirectory "$SMPROGRAMS\${APP_NAME}" + CreateShortCut "$SMPROGRAMS\${APP_NAME}\${APP_NAME}.lnk" "$INSTDIR\${APP_TARGET}.exe" + CreateShortCut "$SMPROGRAMS\${APP_NAME}\Uninstall ${APP_NAME}.lnk" "$INSTDIR\uninstall.exe" SectionEnd Section "Associate *.ove files with Olive" - WriteRegStr HKCR ".ove" "" "OliveEditor.OVEFile" - WriteRegStr HKCR ".ove" "Content Type" "application/vnd.olive-project" - WriteRegStr HKCR "OliveEditor.OVEFile" "" "Olive project file" - WriteRegStr HKCR "OliveEditor.OVEFile\DefaultIcon" "" "$INSTDIR\olive-editor.exe,1" - WriteRegStr HKCR "OliveEditor.OVEFile\shell\open\command" "" "$\"$INSTDIR\olive-editor.exe$\" $\"%1$\"" - System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' + WriteRegStr HKCR ".ove" "" "OliveEditor.OVEFile" + WriteRegStr HKCR ".ove" "Content Type" "application/vnd.olive-project" + WriteRegStr HKCR "OliveEditor.OVEFile" "" "Olive project file" + WriteRegStr HKCR "OliveEditor.OVEFile\DefaultIcon" "" "$INSTDIR\olive-editor.exe,1" + WriteRegStr HKCR "OliveEditor.OVEFile\shell\open\command" "" "$\"$INSTDIR\olive-editor.exe$\" $\"%1$\"" + System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' SectionEnd UninstPage uninstConfirm @@ -68,18 +68,18 @@ UninstPage instfiles Section "uninstall" - rmdir /r "$INSTDIR" + rmdir /r "$INSTDIR" - Delete "$DESKTOP\${APP_NAME}.lnk" - rmdir /r "$SMPROGRAMS\${APP_NAME}" - - DeleteRegKey HKCR ".ove" - DeleteRegKey HKCR "OliveEditor.OVEFile" - DeleteRegKey HKCR "OliveEditor.OVEFile\DefaultIcon" "" - DeleteRegKey HKCR "OliveEditor.OVEFile\shell\open\command" "" - System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' + Delete "$DESKTOP\${APP_NAME}.lnk" + rmdir /r "$SMPROGRAMS\${APP_NAME}" + + DeleteRegKey HKCR ".ove" + DeleteRegKey HKCR "OliveEditor.OVEFile" + DeleteRegKey HKCR "OliveEditor.OVEFile\DefaultIcon" "" + DeleteRegKey HKCR "OliveEditor.OVEFile\shell\open\command" "" + System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' SectionEnd Function LaunchOlive - ExecShell "" "$INSTDIR\${APP_TARGET}.exe" + ExecShell "" "$INSTDIR\${APP_TARGET}.exe" FunctionEnd From e733d1c278aa4a644bb0a6ae6fe03735a9cfc409 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 18 Sep 2020 12:26:30 +1000 Subject: [PATCH 04/14] github: clarify what "commit hash" means in all templates --- .github/ISSUE_TEMPLATE/01-crash_issue.md | 2 +- .github/ISSUE_TEMPLATE/50-build_issue.md | 2 +- .github/ISSUE_TEMPLATE/50-cache_issue.md | 2 +- .github/ISSUE_TEMPLATE/50-codec_issue.md | 2 +- .github/ISSUE_TEMPLATE/50-color_issue.md | 2 +- .github/ISSUE_TEMPLATE/50-editing_issue.md | 2 +- .github/ISSUE_TEMPLATE/50-export_issue.md | 2 +- .github/ISSUE_TEMPLATE/50-node_issue.md | 2 +- .github/ISSUE_TEMPLATE/50-playback_issue.md | 2 +- .github/ISSUE_TEMPLATE/50-project_issue.md | 2 +- .github/ISSUE_TEMPLATE/50-renderer_issue.md | 2 +- .github/ISSUE_TEMPLATE/50-ui_issue.md | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/01-crash_issue.md b/.github/ISSUE_TEMPLATE/01-crash_issue.md index c05544838..0b68b7202 100644 --- a/.github/ISSUE_TEMPLATE/01-crash_issue.md +++ b/.github/ISSUE_TEMPLATE/01-crash_issue.md @@ -6,7 +6,7 @@ labels: "Crash, Triage" assignees: '' --- -**Commit Hash** +**Commit Hash (8 character string of letters/numbers in title bar)** **Platform** diff --git a/.github/ISSUE_TEMPLATE/50-build_issue.md b/.github/ISSUE_TEMPLATE/50-build_issue.md index f14b6c914..8d93ad06d 100644 --- a/.github/ISSUE_TEMPLATE/50-build_issue.md +++ b/.github/ISSUE_TEMPLATE/50-build_issue.md @@ -6,7 +6,7 @@ labels: "Building/Packaging, Triage" assignees: '' --- -**Commit Hash** +**Commit Hash (8 character string of letters/numbers in title bar)** **Platform** diff --git a/.github/ISSUE_TEMPLATE/50-cache_issue.md b/.github/ISSUE_TEMPLATE/50-cache_issue.md index 13b8bc14b..0d088aa8c 100644 --- a/.github/ISSUE_TEMPLATE/50-cache_issue.md +++ b/.github/ISSUE_TEMPLATE/50-cache_issue.md @@ -6,7 +6,7 @@ labels: "Disk Cache, Triage" assignees: '' --- -**Commit Hash** +**Commit Hash (8 character string of letters/numbers in title bar)** **Platform** diff --git a/.github/ISSUE_TEMPLATE/50-codec_issue.md b/.github/ISSUE_TEMPLATE/50-codec_issue.md index a3a936915..04082833f 100644 --- a/.github/ISSUE_TEMPLATE/50-codec_issue.md +++ b/.github/ISSUE_TEMPLATE/50-codec_issue.md @@ -6,7 +6,7 @@ labels: "Codec, Triage" assignees: '' --- -**Commit Hash** +**Commit Hash (8 character string of letters/numbers in title bar)** **Platform** diff --git a/.github/ISSUE_TEMPLATE/50-color_issue.md b/.github/ISSUE_TEMPLATE/50-color_issue.md index 6a7464ea3..99889a56b 100644 --- a/.github/ISSUE_TEMPLATE/50-color_issue.md +++ b/.github/ISSUE_TEMPLATE/50-color_issue.md @@ -6,7 +6,7 @@ labels: "Color Management, Triage" assignees: '' --- -**Commit Hash** +**Commit Hash (8 character string of letters/numbers in title bar)** **Platform** diff --git a/.github/ISSUE_TEMPLATE/50-editing_issue.md b/.github/ISSUE_TEMPLATE/50-editing_issue.md index c731e221f..0465e88a5 100644 --- a/.github/ISSUE_TEMPLATE/50-editing_issue.md +++ b/.github/ISSUE_TEMPLATE/50-editing_issue.md @@ -6,7 +6,7 @@ labels: "Timeline/Editing, Triage" assignees: '' --- -**Commit Hash** +**Commit Hash (8 character string of letters/numbers in title bar)** **Platform** diff --git a/.github/ISSUE_TEMPLATE/50-export_issue.md b/.github/ISSUE_TEMPLATE/50-export_issue.md index e21a79294..7ccef22fc 100644 --- a/.github/ISSUE_TEMPLATE/50-export_issue.md +++ b/.github/ISSUE_TEMPLATE/50-export_issue.md @@ -6,7 +6,7 @@ labels: "Export, Triage" assignees: '' --- -**Commit Hash** +**Commit Hash (8 character string of letters/numbers in title bar)** **Platform** diff --git a/.github/ISSUE_TEMPLATE/50-node_issue.md b/.github/ISSUE_TEMPLATE/50-node_issue.md index 7749521ba..4d15ecebe 100644 --- a/.github/ISSUE_TEMPLATE/50-node_issue.md +++ b/.github/ISSUE_TEMPLATE/50-node_issue.md @@ -6,7 +6,7 @@ labels: "Nodes/Compositing, Triage" assignees: '' --- -**Commit Hash** +**Commit Hash (8 character string of letters/numbers in title bar)** **Platform** diff --git a/.github/ISSUE_TEMPLATE/50-playback_issue.md b/.github/ISSUE_TEMPLATE/50-playback_issue.md index 00aa98149..5e35446f5 100644 --- a/.github/ISSUE_TEMPLATE/50-playback_issue.md +++ b/.github/ISSUE_TEMPLATE/50-playback_issue.md @@ -6,7 +6,7 @@ labels: "Playback, Triage" assignees: '' --- -**Commit Hash** +**Commit Hash (8 character string of letters/numbers in title bar)** **Platform** diff --git a/.github/ISSUE_TEMPLATE/50-project_issue.md b/.github/ISSUE_TEMPLATE/50-project_issue.md index 9e151539c..fa65f393e 100644 --- a/.github/ISSUE_TEMPLATE/50-project_issue.md +++ b/.github/ISSUE_TEMPLATE/50-project_issue.md @@ -6,7 +6,7 @@ labels: "Project, Triage" assignees: '' --- -**Commit Hash** +**Commit Hash (8 character string of letters/numbers in title bar)** **Platform** diff --git a/.github/ISSUE_TEMPLATE/50-renderer_issue.md b/.github/ISSUE_TEMPLATE/50-renderer_issue.md index 3d6812004..f97a22079 100644 --- a/.github/ISSUE_TEMPLATE/50-renderer_issue.md +++ b/.github/ISSUE_TEMPLATE/50-renderer_issue.md @@ -6,7 +6,7 @@ labels: "Renderer, Triage" assignees: '' --- -**Commit Hash** +**Commit Hash (8 character string of letters/numbers in title bar)** **Platform** diff --git a/.github/ISSUE_TEMPLATE/50-ui_issue.md b/.github/ISSUE_TEMPLATE/50-ui_issue.md index 12af9f863..a0cfa3c02 100644 --- a/.github/ISSUE_TEMPLATE/50-ui_issue.md +++ b/.github/ISSUE_TEMPLATE/50-ui_issue.md @@ -6,7 +6,7 @@ labels: "User Interface, Triage" assignees: '' --- -**Commit Hash** +**Commit Hash (8 character string of letters/numbers in title bar)** **Platform** From 8506c82a0c2d00aae4e814e2e02f2d99b23f2a2c Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 18 Sep 2020 12:58:24 +1000 Subject: [PATCH 05/14] import: safely handle unsupported files Fixes #1191 --- app/codec/ffmpeg/ffmpegdecoder.cpp | 34 +++++++++--- app/core.cpp | 10 +++- app/task/project/import/CMakeLists.txt | 2 + app/task/project/import/import.cpp | 5 +- app/task/project/import/import.h | 12 +++++ app/task/project/import/importerrordialog.cpp | 53 +++++++++++++++++++ app/task/project/import/importerrordialog.h | 40 ++++++++++++++ 7 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 app/task/project/import/importerrordialog.cpp create mode 100644 app/task/project/import/importerrordialog.h diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index 096cfcd07..46cac10fc 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -477,14 +477,19 @@ bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled) // Retrieve metadata about the media avformat_find_stream_info(fmt_ctx, nullptr); + QVector streams(fmt_ctx->nb_streams); + // Dump it into the Footage object for (unsigned int i=0;inb_streams;i++) { AVStream* avstream = fmt_ctx->streams[i]; + // Find decoder for this stream, if it exists we can proceed + AVCodec* decoder = avcodec_find_decoder(avstream->codecpar->codec_id); + StreamPtr str; - if (avstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + if (avstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && decoder) { bool image_is_still = false; rational pixel_aspect_ratio; @@ -564,7 +569,7 @@ bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled) str = image_stream; - } else if (avstream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + } else if (avstream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && decoder) { // Create an audio stream object AudioStreamPtr audio_stream = std::make_shared(); @@ -600,7 +605,7 @@ bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled) str->set_type(Stream::kAttachment); break; default: - // We should never realistically get here, but we make an "invalid" stream just in case + // Fallback to an unknown stream str->set_type(Stream::kUnknown); break; } @@ -611,11 +616,27 @@ bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled) str->set_timebase(avstream->time_base); str->set_duration(avstream->duration); - f->add_stream(str); + streams[i] = str; } - // As long as we can open the container and retrieve information, this was a successful probe - result = true; + // Check if we could pick up any streams in this file + bool found_valid_streams = false; + + foreach (StreamPtr stream, streams) { + if (stream->type() != Stream::kUnknown) { + found_valid_streams = true; + break; + } + } + + if (found_valid_streams) { + // Copy streams over + foreach (StreamPtr stream, streams) { + f->add_stream(stream); + } + + result = true; + } } // Free all memory @@ -1330,6 +1351,7 @@ void FFmpegDecoderInstance::RemoveFirstFrame() FFmpegDecoderInstance::FFmpegDecoderInstance(const char *filename, int stream_index) : fmt_ctx_(nullptr), + codec_ctx_(nullptr), opts_(nullptr), scale_ctx_(nullptr), scale_divider_(0), diff --git a/app/core.cpp b/app/core.cpp index 9790246ed..5ba51ee45 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -51,6 +51,7 @@ #include "render/pixelformat.h" #include "render/shaderinfo.h" #include "task/project/import/import.h" +#include "task/project/import/importerrordialog.h" #include "task/project/load/load.h" #include "task/project/save/save.h" #include "task/taskmanager.h" @@ -473,7 +474,14 @@ void Core::AddOpenProjectFromTask(Task *task) void Core::ImportTaskComplete(Task* task) { - QUndoCommand *command = static_cast(task)->GetCommand(); + ProjectImportTask* import_task = static_cast(task); + + QUndoCommand *command = import_task->GetCommand(); + + if (import_task->HasInvalidFiles()) { + ProjectImportErrorDialog d(import_task->GetInvalidFiles(), main_window_); + d.exec(); + } undo_stack_.pushIfHasChildren(command); } diff --git a/app/task/project/import/CMakeLists.txt b/app/task/project/import/CMakeLists.txt index 77b4f31a6..4a25a6b03 100644 --- a/app/task/project/import/CMakeLists.txt +++ b/app/task/project/import/CMakeLists.txt @@ -18,5 +18,7 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} task/project/import/import.h task/project/import/import.cpp + task/project/import/importerrordialog.h + task/project/import/importerrordialog.cpp PARENT_SCOPE ) diff --git a/app/task/project/import/import.cpp b/app/task/project/import/import.cpp index 270e3a7d4..ef5767886 100644 --- a/app/task/project/import/import.cpp +++ b/app/task/project/import/import.cpp @@ -122,7 +122,10 @@ void ProjectImportTask::Import(Folder *folder, const QFileInfoList &import, int f->set_project(nullptr); - if (f->status() != Footage::kInvalid) { + if (f->status() == Footage::kInvalid) { + // Add to list so we can tell the user about it later + invalid_files_.append(file_info.absoluteFilePath()); + } else { // Create undoable command that adds the items to the model new ProjectViewModel::AddItemCommand(model_, folder, diff --git a/app/task/project/import/import.h b/app/task/project/import/import.h index d092fa192..2257fc8ea 100644 --- a/app/task/project/import/import.h +++ b/app/task/project/import/import.h @@ -42,6 +42,16 @@ public: return command_; } + const QStringList& GetInvalidFiles() const + { + return invalid_files_; + } + + bool HasInvalidFiles() const + { + return !invalid_files_.isEmpty(); + } + protected: virtual bool Run() override; @@ -58,6 +68,8 @@ private: int file_count_; + QStringList invalid_files_; + }; OLIVE_NAMESPACE_EXIT diff --git a/app/task/project/import/importerrordialog.cpp b/app/task/project/import/importerrordialog.cpp new file mode 100644 index 000000000..c6b5e4d8c --- /dev/null +++ b/app/task/project/import/importerrordialog.cpp @@ -0,0 +1,53 @@ +/*** + + 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 "importerrordialog.h" + +#include +#include +#include +#include + +OLIVE_NAMESPACE_ENTER + +ProjectImportErrorDialog::ProjectImportErrorDialog(const QStringList& filenames, QWidget* parent) : + QDialog(parent) +{ + QVBoxLayout* layout = new QVBoxLayout(this); + + setWindowTitle(tr("Import Error")); + + layout->addWidget(new QLabel(tr("The following files failed to import. Olive likely does not " + "support their formats."))); + + QListWidget* list_widget = new QListWidget(); + foreach (const QString& s, filenames) { + list_widget->addItem(s); + } + layout->addWidget(list_widget); + + QDialogButtonBox* buttons = new QDialogButtonBox(); + buttons->setStandardButtons(QDialogButtonBox::Ok); + buttons->setCenterButtons(true); + connect(buttons, &QDialogButtonBox::accepted, this, &ProjectImportErrorDialog::accept); + layout->addWidget(buttons); +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/task/project/import/importerrordialog.h b/app/task/project/import/importerrordialog.h new file mode 100644 index 000000000..8ee6bf740 --- /dev/null +++ b/app/task/project/import/importerrordialog.h @@ -0,0 +1,40 @@ +/*** + + 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 . + +***/ + +#ifndef PROJECTIMPORTERRORDIALOG_H +#define PROJECTIMPORTERRORDIALOG_H + +#include + +#include "common/define.h" + +OLIVE_NAMESPACE_ENTER + +class ProjectImportErrorDialog : public QDialog +{ + Q_OBJECT +public: + ProjectImportErrorDialog(const QStringList& filenames, QWidget* parent = nullptr); + +}; + +OLIVE_NAMESPACE_EXIT + +#endif // PROJECTIMPORTERRORDIALOG_H From 9c488d9a37fd3c15aa00f354defeccaf7a84b82d Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 18 Sep 2020 12:59:16 +1000 Subject: [PATCH 06/14] timeline: use full viewport update Fixes #1190 --- app/widget/timelinewidget/view/timelineview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/app/widget/timelinewidget/view/timelineview.cpp b/app/widget/timelinewidget/view/timelineview.cpp index 4b60ec0b7..99fd892a0 100644 --- a/app/widget/timelinewidget/view/timelineview.cpp +++ b/app/widget/timelinewidget/view/timelineview.cpp @@ -46,6 +46,7 @@ TimelineView::TimelineView(Qt::Alignment vertical_alignment, QWidget *parent) : setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); setBackgroundRole(QPalette::Window); setContextMenuPolicy(Qt::CustomContextMenu); + setViewportUpdateMode(QGraphicsView::FullViewportUpdate); viewport()->setMouseTracking(true); } From 01428276f74a34cd493c8285e0e5a74b7f7b26b4 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 18 Sep 2020 13:06:10 +1000 Subject: [PATCH 07/14] export: alternate method of checking video/audio parameters based on ticket type Fixes #1196 --- app/render/backend/renderbackend.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/app/render/backend/renderbackend.cpp b/app/render/backend/renderbackend.cpp index 9c72f47a9..8e5c0110b 100644 --- a/app/render/backend/renderbackend.cpp +++ b/app/render/backend/renderbackend.cpp @@ -375,13 +375,6 @@ void RenderBackend::RunNextJob() return; } - // Check if params are valid - if (!video_params_.is_valid() - || !audio_params_.is_valid()) { - qDebug() << "Failed to run job, parameters are invalid"; - return; - } - // If we have a value update queued, check if all workers are available and proceed from there if (autocache_enabled_ && !graph_update_queue_.isEmpty()) { bool all_workers_available = true; @@ -449,6 +442,8 @@ void RenderBackend::RunNextJob() switch (ticket->GetType()) { case RenderTicket::kTypeHash: + Q_ASSERT(video_params_.is_valid()); + QtConcurrent::run(&thread_pool_, worker, &RenderWorker::Hash, @@ -458,6 +453,8 @@ void RenderBackend::RunNextJob() break; case RenderTicket::kTypeVideo: { + Q_ASSERT(video_params_.is_valid()); + rational frame = ticket->GetTime().value(); QtConcurrent::run(&thread_pool_, @@ -474,6 +471,8 @@ void RenderBackend::RunNextJob() break; } case RenderTicket::kTypeAudio: + Q_ASSERT(audio_params_.is_valid()); + QtConcurrent::run(&thread_pool_, worker, &RenderWorker::RenderAudio, From 27a4dbc85fd16fae623ee8822c2e3363d45ab60a Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 18 Sep 2020 13:19:18 +1000 Subject: [PATCH 08/14] import: fixed progres reporting --- app/task/project/import/import.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/task/project/import/import.cpp b/app/task/project/import/import.cpp index ef5767886..c8cd0a6c9 100644 --- a/app/task/project/import/import.cpp +++ b/app/task/project/import/import.cpp @@ -135,7 +135,7 @@ void ProjectImportTask::Import(Folder *folder, const QFileInfoList &import, int counter++; - emit ProgressChanged((counter * 100) / file_count_); + emit ProgressChanged(static_cast(counter) / static_cast(file_count_)); } } From 3103359cd6898fe219af5a1c0c421d1dc20fc54e Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 18 Sep 2020 23:49:40 +1000 Subject: [PATCH 09/14] slider: fixed crash when clicking another mouse button while dragging --- app/widget/slider/sliderlabel.cpp | 10 ++++++---- app/widget/slider/sliderladder.cpp | 13 ++++++++++--- app/widget/slider/sliderladder.h | 2 ++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/widget/slider/sliderlabel.cpp b/app/widget/slider/sliderlabel.cpp index d100379a5..ffc07fb2c 100644 --- a/app/widget/slider/sliderlabel.cpp +++ b/app/widget/slider/sliderlabel.cpp @@ -51,10 +51,12 @@ SliderLabel::SliderLabel(QWidget *parent) : void SliderLabel::mousePressEvent(QMouseEvent *e) { - if (e->modifiers() & Qt::AltModifier) { - emit RequestReset(); - } else { - emit LabelPressed(); + if (e->button() == Qt::LeftButton) { + if (e->modifiers() & Qt::AltModifier) { + emit RequestReset(); + } else { + emit LabelPressed(); + } } } diff --git a/app/widget/slider/sliderladder.cpp b/app/widget/slider/sliderladder.cpp index 5a9c4d235..c5c0054ae 100644 --- a/app/widget/slider/sliderladder.cpp +++ b/app/widget/slider/sliderladder.cpp @@ -103,9 +103,7 @@ void SliderLadder::mouseReleaseEvent(QMouseEvent *event) { Q_UNUSED(event) - drag_timer_.stop(); - - emit Released(); + this->close(); } void SliderLadder::showEvent(QShowEvent *event) @@ -115,6 +113,15 @@ void SliderLadder::showEvent(QShowEvent *event) drag_timer_.start(); } +void SliderLadder::closeEvent(QCloseEvent *event) +{ + Q_UNUSED(event) + + drag_timer_.stop(); + + emit Released(); +} + void SliderLadder::TimerUpdate() { int32_t x_mvmt, y_mvmt; diff --git a/app/widget/slider/sliderladder.h b/app/widget/slider/sliderladder.h index ce0ae6193..9fc30e511 100644 --- a/app/widget/slider/sliderladder.h +++ b/app/widget/slider/sliderladder.h @@ -75,6 +75,8 @@ protected: virtual void showEvent(QShowEvent *event) override; + virtual void closeEvent(QCloseEvent* event) override; + signals: void DraggedByValue(int value, double multiplier); From 6117ca44e931e14c9c715d05653c7250437d4d0d Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 19 Sep 2020 12:07:36 +1000 Subject: [PATCH 10/14] sequence: ignore disabled streams --- app/project/item/sequence/sequence.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp index fcf76c8dd..ede8f6f88 100644 --- a/app/project/item/sequence/sequence.cpp +++ b/app/project/item/sequence/sequence.cpp @@ -268,6 +268,10 @@ void Sequence::set_parameters_from_footage(const QList footage) foreach (Footage* f, footage) { foreach (StreamPtr s, f->streams()) { + if (!s->enabled()) { + continue; + } + switch (s->type()) { case Stream::kVideo: { From 9c57899ae2d6582ec6b084ed13f1f6a539311d67 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 19 Sep 2020 12:07:52 +1000 Subject: [PATCH 11/14] mainwindow: auto-close footage in footage viewer when closing parent project --- app/window/mainwindow/mainwindow.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 4c010e963..cbb4b48da 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -349,6 +349,22 @@ void MainWindow::ProjectClose(Project *p) CloseSequence(seq); } } + + // Close any open footage in footage viewer + QList footage = p->get_items_of_type(Item::kFootage); + QList footage_in_viewer = footage_viewer_panel_->GetSelectedFootage(); + + if (!footage_in_viewer.isEmpty()) { + // FootageViewer only has the one footage item + Footage* f = footage_in_viewer.first(); + + foreach (ItemPtr i, footage) { + if (f == i.get()) { + footage_viewer_panel_->SetFootage(nullptr); + break; + } + } + } } void MainWindow::SetApplicationProgressStatus(ProgressStatus status) From 855c460ff37687f3a1c5167ea6b650772fe057a5 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 19 Sep 2020 12:30:42 +1000 Subject: [PATCH 12/14] footageviewer: use sequence functions to set video/audio params Code improvement by re-using existing code. Existing code prevents crash when loading a still image. --- app/widget/viewer/footageviewer.cpp | 51 +++++++++++------------------ app/widget/viewer/footageviewer.h | 4 +-- 2 files changed, 22 insertions(+), 33 deletions(-) diff --git a/app/widget/viewer/footageviewer.cpp b/app/widget/viewer/footageviewer.cpp index c4df185ce..5ca81ae1e 100644 --- a/app/widget/viewer/footageviewer.cpp +++ b/app/widget/viewer/footageviewer.cpp @@ -33,8 +33,10 @@ FootageViewerWidget::FootageViewerWidget(QWidget *parent) : footage_(nullptr) { video_node_ = new VideoInput(); + sequence_.AddNode(video_node_); + audio_node_ = new AudioInput(); - viewer_node_ = new ViewerOutput(); + sequence_.AddNode(audio_node_); connect(display_widget(), &ViewerDisplayWidget::DragStarted, this, &FootageViewerWidget::StartFootageDrag); @@ -55,17 +57,29 @@ void FootageViewerWidget::SetFootage(Footage *footage) ConnectViewerNode(nullptr); - NodeParam::DisconnectEdge(video_node_->output(), viewer_node_->texture_input()); - NodeParam::DisconnectEdge(audio_node_->output(), viewer_node_->samples_input()); + NodeParam::DisconnectEdge(video_node_->output(), sequence_.viewer_output()->texture_input()); + NodeParam::DisconnectEdge(audio_node_->output(), sequence_.viewer_output()->samples_input()); } footage_ = footage; if (footage_) { + // Update sequence media name + sequence_.viewer_output()->set_media_name(footage_->name()); + + // Reset parameters and then attempt to set from footage + sequence_.set_default_parameters(); + sequence_.set_parameters_from_footage({footage_}); + + // Use first of each stream VideoStreamPtr video_stream = nullptr; AudioStreamPtr audio_stream = nullptr; foreach (StreamPtr s, footage_->streams()) { + if (!s->enabled()) { + continue; + } + if (!audio_stream && s->type() == Stream::kAudio) { audio_stream = std::static_pointer_cast(s); } @@ -80,42 +94,17 @@ void FootageViewerWidget::SetFootage(Footage *footage) } } - viewer_node_->set_media_name(footage_->name()); - if (video_stream) { video_node_->SetFootage(video_stream); - viewer_node_->set_video_params(VideoParams(video_stream->width(), - video_stream->height(), - video_stream->frame_rate().flipped(), - static_cast(Config::Current()["DefaultSequencePreviewFormat"].toInt()), - video_stream->pixel_aspect_ratio(), - video_stream->interlacing(), - VideoParams::generate_auto_divider(video_stream->width(), video_stream->height()))); - NodeParam::ConnectEdge(video_node_->output(), viewer_node_->texture_input()); - } else { - int width = Config::Current()["DefaultSequenceWidth"].toInt(); - int height = Config::Current()["DefaultSequenceHeight"].toInt(); - - viewer_node_->set_video_params(VideoParams(width, - height, - Config::Current()["DefaultSequenceFrameRate"].value(), - static_cast(Config::Current()["DefaultSequencePreviewFormat"].toInt()), - Config::Current()["DefaultSequencePixelAspect"].value(), - Config::Current()["DefaultSequenceInterlacing"].value(), - VideoParams::generate_auto_divider(width, height))); + NodeParam::ConnectEdge(video_node_->output(), sequence_.viewer_output()->texture_input()); } if (audio_stream) { audio_node_->SetFootage(audio_stream); - viewer_node_->set_audio_params(AudioParams(audio_stream->sample_rate(), audio_stream->channel_layout(), SampleFormat::kInternalFormat)); - NodeParam::ConnectEdge(audio_node_->output(), viewer_node_->samples_input()); - } else { - viewer_node_->set_audio_params(AudioParams(Config::Current()["DefaultSequenceAudioFrequency"].toInt(), - Config::Current()["DefaultSequenceAudioLayout"].toULongLong(), - SampleFormat::kInternalFormat)); + NodeParam::ConnectEdge(audio_node_->output(), sequence_.viewer_output()->samples_input()); } - ConnectViewerNode(viewer_node_, footage_->project()->color_manager()); + ConnectViewerNode(sequence_.viewer_output(), footage_->project()->color_manager()); SetTimestamp(cached_timestamps_.value(footage_, 0)); } diff --git a/app/widget/viewer/footageviewer.h b/app/widget/viewer/footageviewer.h index 36f688fa9..af093eb8f 100644 --- a/app/widget/viewer/footageviewer.h +++ b/app/widget/viewer/footageviewer.h @@ -47,12 +47,12 @@ private: Footage* footage_; + Sequence sequence_; + VideoInput* video_node_; AudioInput* audio_node_; - ViewerOutput* viewer_node_; - QHash cached_timestamps_; private slots: From 7bc841904a6fe802f0bf42b6110a649458b362c8 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 19 Sep 2020 12:45:40 +1000 Subject: [PATCH 13/14] viewer: display image infinitely if video length is null Allows for displaying still images in viewer without a finite length. --- app/widget/viewer/viewer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 4af7869b6..b3b52231a 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -566,7 +566,9 @@ QString ViewerWidget::GetCachedFilenameFromTime(const rational &time) bool ViewerWidget::FrameExistsAtTime(const rational &time) { - return GetConnectedNode() && time >= 0 && time < GetConnectedNode()->video_frame_cache()->GetLength(); + return GetConnectedNode() + && ((time >= 0 && time < GetConnectedNode()->video_frame_cache()->GetLength()) + || GetConnectedNode()->video_frame_cache()->GetLength().isNull()); } void ViewerWidget::SetDisplayImage(FramePtr frame, bool main_only) From 8e0c86a6fa7bc32bd2177d8b72f19f6a4f92d8e9 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 19 Sep 2020 12:53:07 +1000 Subject: [PATCH 14/14] renderer: if texture is null, don't allocate a frame unless exporting --- app/render/backend/renderworker.cpp | 2 +- app/widget/viewer/viewerdisplay.cpp | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/render/backend/renderworker.cpp b/app/render/backend/renderworker.cpp index 28e8a50f5..2db075c25 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_ || texture.isNull()) { + if (video_force_download_resolution_) { // 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/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 983f422e1..25f13ac58 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -99,7 +99,11 @@ void ViewerDisplayWidget::SetSignalCursorColorEnabled(bool e) void ViewerDisplayWidget::SetImage(FramePtr in_buffer) { - last_loaded_buffer_ = in_buffer; + if (in_buffer && in_buffer->is_allocated()) { + last_loaded_buffer_ = in_buffer; + } else { + last_loaded_buffer_ = nullptr; + } if (last_loaded_buffer_) { makeCurrent();