diff --git a/.appveyor/build.bat b/.appveyor/build.bat deleted file mode 100644 index fa4e48ecc..000000000 --- a/.appveyor/build.bat +++ /dev/null @@ -1,117 +0,0 @@ -REM Get git hash in variable [this seems to be the most efficient way] -git rev-parse --short=8 HEAD > hash.txt -git rev-parse HEAD > longhash.txt -set /p GITHASH= < hash.txt -set /p GITLONGHASH= < longhash.txt -set /p TRAVIS_COMMIT= < longhash.txt - -REM Set up Visual Studio x64 environment -call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" - -REM Install 64-bit packages -set VCPKG_DEFAULT_TRIPLET=x64-windows - -REM Hack to only install release builds for time -echo set(VCPKG_BUILD_TYPE release) >> C:\Tools\vcpkg\triplets\x64-windows.cmake - -REM Install Open*IO libraries -vcpkg install opencolorio -vcpkg install openimageio - -REM Integrate libraries -cd c:\tools\vcpkg -vcpkg integrate install -cd %APPVEYOR_BUILD_FOLDER% - -REM Acquire FFmpeg -set FFMPEG_VER=ffmpeg-4.2.3-win64 -curl https://ffmpeg.zeranoe.com/builds/win64/dev/%FFMPEG_VER%-dev.zip > %FFMPEG_VER%-dev.zip -curl https://ffmpeg.zeranoe.com/builds/win64/shared/%FFMPEG_VER%-shared.zip > %FFMPEG_VER%-shared.zip -7z x %FFMPEG_VER%-dev.zip -7z x %FFMPEG_VER%-shared.zip - -REM Acquire Google Crashpad -git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git -set PATH=%PATH%;%APPVEYOR_BUILD_FOLDER%\depot_tools - -REM Run `fetch` through cmd /c since fetch is a batch file that seems to call exit -cmd /c fetch crashpad -cd crashpad -cmd /c gn gen out/Default - -REM Patch to build a dynamic release instead of a static release -ren out\Default\toolchain.ninja toolchain.ninja.old -sed "s/${cflags_c}/${cflags_c} \/MD/g" out\Default\toolchain.ninja.old > out\Default\toolchain.ninja - -REM Build Crashpad -ninja.exe -C out/Default -cd .. - -REM Add Qt, FFmpeg, and Crashpad to path -set PATH=%PATH%;C:\Qt\5.13.2\msvc2017_64\bin;%APPVEYOR_BUILD_FOLDER%\%FFMPEG_VER%-dev;%APPVEYOR_BUILD_FOLDER%\crashpad;%APPVEYOR_BUILD_FOLDER%\crashpad\out\Default - -REM Run cmake -cmake -G "Ninja" . -DCMAKE_TOOLCHAIN_FILE=c:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo - -REM Build with Ninja -ninja.exe || exit /B 1 - -REM If this is a pull request, no further packaging/deploying needs to be done -if NOT "%APPVEYOR_PULL_REQUEST_NUMBER%" == "" goto end - -REM Create Crashpad symbol file and upload it -C:\msys64\usr\bin\wget.exe https://github.com/google/breakpad/blob/master/src/tools/windows/binaries/dump_syms.exe?raw=true -O dump_syms.exe -dump_syms app\olive-editor.pdb > olive-editor.sym -curl -F symfile=@olive-editor.sym https://olivevideoeditor.org/crashpad/symbols.php - -REM Start building package -mkdir olive-editor -cd olive-editor -copy ..\app\olive-editor.exe . -copy ..\app\olive-editor.pdb . -copy ..\app\crashhandler.exe . -copy ..\crashpad\out\Default\crashpad_handler.exe . -windeployqt olive-editor.exe -copy ..\%FFMPEG_VER%-shared\bin\*.dll . -copy ..\app\*.dll . - -REM Package done, begin deployment -cd .. -set PKGNAME=Olive-%GITHASH%-Windows-x86_64 - -REM Create installer -copy app\packaging\windows\nsis\* . -"C:/Program Files (x86)/NSIS/makensis.exe" -V4 -DX64 "-XOutFile %PKGNAME%.exe" olive.nsi - -REM Create portable -copy nul olive-editor\portable -7z a %PKGNAME%.zip olive-editor - -REM If this was a tagged build, upload -if "%APPVEYOR_REPO_TAG%"=="true" GOTO upload - -REM Else, if this is a continuous build, check if this commit is the most recent - -REM Force locale to UTF-8 or grep -P fails -set LC_ALL=en_US.UTF-8 - -curl -H "Authorization: token %GITHUB_TOKEN%" https://api.github.com/repos/olive-editor/olive/commits/master > repoinfo.txt -grep -Po '(?^<=: \")(([a-z0-9])\w+)(?=\")' -m 1 repoinfo.txt > latestcommit.txt -set /p REMOTEHASH= < latestcommit.txt -if "%REMOTEHASH%"=="%GITLONGHASH%" GOTO upload - -REM The previous if statements failed, skip to the end -GOTO end - -:upload -set /p UPLOADTOOL_BODY= < latestcommit.txt - -curl -L https://github.com/probonopd/uploadtool/raw/master/upload.sh > upload.sh -bash upload.sh Olive*.zip -bash upload.sh Olive*.exe - -:end -REM Check if this build should set up a debugging session -IF "%ENABLE_RDP%"=="1" ( - powershell -command "$blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))" -) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 02d7fd7b5..e120e18fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,15 @@ on: - 'docker/**' - 'CONTRIBUTING.md' - 'README.md' + pull_request: + branches: + - master + paths-ignore: + - '.github/ISSUE_TEMPLATE/**' + - '.github/FUNDING.yml' + - 'docker/**' + - 'CONTRIBUTING.md' + - 'README.md' env: DOWNLOAD_TOOL: curl -fLOSs --retry 2 --retry-delay 60 @@ -257,6 +266,7 @@ jobs: shell: bash env: GH_AUTH_KEY: ${{ secrets.GH_AUTH_KEY }} + if: github.event_name == 'push' run: | curl -fLSs --retry 2 --retry-delay 60 \ https://github.com/google/breakpad/blob/master/src/tools/windows/binaries/dump_syms.exe?raw=true > dump_syms.exe @@ -320,6 +330,12 @@ jobs: $DOWNLOAD_TOOL https://olivevideoeditor.org/deps/ocio-mac.zip $EXTRACT_TOOL ocio-mac.zip + - name: Acquire OpenTimelineIO + shell: bash + run: | + $DOWNLOAD_TOOL https://olivevideoeditor.org/deps/otio-mac.zip + $EXTRACT_TOOL otio-mac.zip + - name: Acquire OpenEXR shell: bash run: | diff --git a/.gitignore b/.gitignore index eaf33fa1c..88b977edd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,19 +1,39 @@ -*.pro.user* -Makefile -.qmake.stash -effects/frei0r -ts/*.qm -docs -history -build/ -.DS_Store +# CMake artifacts +/build*/ -.vscode -.vs +# Doxygen +/docs/ + +# Visual Studio (Code) +.localhistory/ +.history/ +.vscode/ +.vs/ +/out/ CmakeSettings.json +# macOS General +.DS_Store +.AppleDouble +.LSOverride + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Windows folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares (Windows) +$RECYCLE.BIN/ + +# Windows shortcuts +*.lnk + # -# Qt ignores taken from https://github.com/github/gitignore +# Qt ignores taken from https://github.com/github/gitignore/blob/master/Qt.gitignore # # C++ objects and libs @@ -24,6 +44,7 @@ CmakeSettings.json *.la *.lai *.so +*.so.* *.dll *.dylib @@ -46,6 +67,8 @@ ui_*.h *.jsc Makefile* *build-* +*.qm +*.prl # Qt unit tests target_wrapper.* @@ -65,3 +88,5 @@ compile_commands.json # QtCreator local machine specific files for imported projects *creator.user* + +*_qmlcache.qrc diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9b7b9d3ff..000000000 --- a/.travis.yml +++ /dev/null @@ -1,44 +0,0 @@ -language: cpp - -matrix: - include: - - os: linux - env: ARCH=x86_64 - compiler: gcc - sudo: require - dist: xenial - - os: osx - osx_image: xcode10.3 - before_cache: - - brew cleanup - cache: - directories: - - $HOME/Library/Caches/Homebrew - addons: - homebrew: - packages: - - ffmpeg - - qt5 - - grep - - opencolorio - - openimageio - update: true - # Can't build on Windows - affected by https://travis-ci.community/t/current-known-issues-please-read-this-before-posting-a-new-topic/264/10 - # - os: windows - -before_install: - - source ./.travis/before_install.sh - -install: - - source ./.travis/install.sh - -script: - - source ./.travis/script.sh - -after_success: - - source ./.travis/after_success.sh - -branches: - except: - - # Do not build tags that we create when we upload to GitHub Releases - - /^(?i:continuous)/ diff --git a/.travis/after_success.sh b/.travis/after_success.sh deleted file mode 100644 index e189720f2..000000000 --- a/.travis/after_success.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - -# Check if there's been a new commit since this build, and if so don't upload it - -GREP_PATH=grep - -if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - GREP_PATH=ggrep -fi - -# Get current repo commit from GitHub (problems arose from trying to pipe cURL directly into grep, so we buffer it through a file) -REMOTE=$(curl -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/olive-editor/olive/commits/master | $GREP_PATH -Po '(?<=: \")(([a-z0-9])\w+)(?=\")' -m 1 --) -LOCAL=$(git rev-parse HEAD) - -if [ "$TRAVIS_TAG" != "" ] || [ "$REMOTE" == "$LOCAL" ] -then - echo "[INFO] Still current. Uploading..." - - export UPLOADTOOL_BODY=$(cat release.txt) - - # Retrieve upload tool - wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - - bash upload.sh Olive*.zip - - elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - - find appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq - - bash upload.sh Olive*.AppImage* - - fi - -else - - echo "[INFO] No longer current. $REMOTE vs $LOCAL - aborting upload." - -fi diff --git a/.travis/before_install.sh b/.travis/before_install.sh deleted file mode 100644 index 569d5f5bb..000000000 --- a/.travis/before_install.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - - # Qt 5.11 - sudo add-apt-repository ppa:beineri/opt-qt-5.11.0-xenial -y - - # FFmpeg 4.x - sudo add-apt-repository ppa:jonathonf/ffmpeg-4 -y - - # OpenColorIO - sudo add-apt-repository ppa:olive-editor/opencolorio -y - - # Update apt - sudo apt-get update -qq - -fi diff --git a/.travis/install.sh b/.travis/install.sh deleted file mode 100644 index 8d57de697..000000000 --- a/.travis/install.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - - export PATH="/usr/local/opt/qt/bin:/usr/local/opt/python@2/libexec/bin:$PATH" - -elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - - sudo apt-get -y -o Dpkg::Options::="--force-overwrite" install qt511base qt511multimedia qt511svg qt511tools libavformat-dev libavcodec-dev libavfilter-dev libavutil-dev libswscale-dev libswresample-dev libopencolorio-dev libopenimageio-dev libgl1-mesa-dev - source /opt/qt*/bin/qt*-env.sh - - # Acquire latest cmake (apt somehow gets the wrong version?) - wget -c https://github.com/Kitware/CMake/releases/download/v3.17.2/cmake-3.17.2-Linux-x86_64.sh -O cmake.sh - chmod +x cmake.sh - ./cmake.sh --skip-license --prefix=cmake --exclude-dir - export PATH=$PWD/cmake/bin:$PATH - -fi diff --git a/.travis/script.sh b/.travis/script.sh deleted file mode 100644 index 4a7a7fa2c..000000000 --- a/.travis/script.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash - -# linuxdeployqt uses this for naming the file -export VERSION=$(git rev-parse --short=8 HEAD) - -if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - - # Generate Makefile - cmake . -DCMAKE_BUILD_TYPE=RelWithDebInfo - - # Make - make -j$(sysctl -n hw.ncpu) - - # Handle compile failure - if [ "$?" != "0" ] - then - exit 1 - fi - - BUNDLE_NAME=Olive.app - - # Move bundle to working directory - mv app/$BUNDLE_NAME . - - # Move Qt deps into bundle - macdeployqt $BUNDLE_NAME - - # Fix other deps that macdeployqt missed - curl -fLOSs --retry 3 https://github.com/arl/macdeployqtfix/raw/master/macdeployqtfix.py - python2 macdeployqtfix.py $BUNDLE_NAME/Contents/MacOS/Olive /usr/local/Cellar/qt5/5.*/ - - # Fix deps on crash handler - python2 macdeployqtfix.py $BUNDLE_NAME/Contents/MacOS/olive-crashhandler /usr/local/Cellar/qt5/5.*/ - - # Fix OpenEXR libs that seem to be missed by both macdeployqt _and_ macdeployqtfix - cd $BUNDLE_NAME/Contents/Frameworks - exrlib=(libImath-*.dylib libHalf-*.dylib libIexMath-*.dylib libIex-*.dylib libIlmThread-*.dylib) - - for a in ${exrlib[@]}; do - for b in ${exrlib[@]}; do - install_name_tool -change @rpath/$b @executable_path/../Frameworks/$b $a - done - done - - cd ../../.. - - # Distribute in zip - zip -r Olive-$VERSION-macOS.zip $BUNDLE_NAME - -elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - - # Generate Makefile - cmake . -DCMAKE_BUILD_TYPE=RelWithDebInfo - - # Make - make -j$(nproc) - - # Handle compile failure - if [ "$?" != "0" ] - then - exit 1 - fi - - # Use `make install` on `appdir` to place files in the correct place - make DESTDIR=appdir install - - # Download linuxdeployqt - wget -c -nv "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" - chmod a+x linuxdeployqt-continuous-x86_64.AppImage - - unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH - - # Use linuxdeployqt to set up dependencies - ./linuxdeployqt-continuous-x86_64.AppImage appdir/usr/local/share/applications/*.desktop -extra-plugins=imageformats/libqsvg.so -appimage - -fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b1f3471a..9b6312bec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -41,9 +41,9 @@ endif() find_package(OpenGL REQUIRED) -find_package(OpenColorIO REQUIRED) +find_package(OpenColorIO 2.0.0 REQUIRED) -find_package(OpenImageIO 1.6 REQUIRED) +find_package(OpenImageIO 2.1.12 REQUIRED) find_package(OpenEXR REQUIRED) diff --git a/README.md b/README.md index 9291d1b77..eda479b1c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Olive is a free non-linear video editor for Windows, macOS, and Linux. ![screen](https://olivevideoeditor.org/img/020-2.png) -**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) +**Discover more:** [Website](https://www.olivevideoeditor.org/) | [Binaries](https://olivevideoeditor.org/download.php) | [Patreon](https://www.patreon.com/olivevideoeditor) | [Twitter](https://twitter.com/oliveteam) | [Wiki](https://github.com/olive-editor/olive/wiki/Overview-Guide) | [Community Discord (Unofficial)](https://discord.gg/4Ae9KZn) **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.** diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index a5177e705..995c75d92 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -41,7 +41,9 @@ add_subdirectory(project) add_subdirectory(render) add_subdirectory(shaders) add_subdirectory(task) +add_subdirectory(threading) add_subdirectory(timeline) +add_subdirectory(ts) add_subdirectory(tool) add_subdirectory(ui) add_subdirectory(undo) @@ -61,11 +63,25 @@ if(APPLE) ) endif() +# Add translations +qt5_add_translation(OLIVE_QM_FILES ${OLIVE_TS_FILES}) + +set(QRC_BODY "") +foreach(QM_FILE ${OLIVE_QM_FILES}) + get_filename_component(QM_FILENAME_COMPONENT ${QM_FILE} NAME_WE) + string(APPEND QRC_BODY "${QM_FILE}\n") +endforeach() +configure_file(ts/translations.qrc.in ts/translations.qrc @ONLY) + +set(OLIVE_RESOURCES + ${OLIVE_RESOURCES} + ${CMAKE_CURRENT_BINARY_DIR}/ts/translations.qrc +) + # Add executable add_executable(${OLIVE_TARGET} ${OLIVE_SOURCES} ${OLIVE_RESOURCES} - ${OLIVE_QM_FILES} ) if(APPLE) @@ -264,16 +280,6 @@ endif() # Set compiler definitions target_compile_definitions(${OLIVE_TARGET} PRIVATE ${OLIVE_DEFINITIONS}) -set(OLIVE_TS_FILES - # FIXME: Empty variable -) - -if(UPDATE_TS) - qt5_create_translation(OLIVE_QM_FILES ${CMAKE_SOURCE_DIR} ${OLIVE_TS_FILES}) -else() - qt5_add_translation(OLIVE_QM_FILES ${OLIVE_TS_FILES}) -endif() - add_subdirectory(packaging) if(DOXYGEN_FOUND) diff --git a/app/audio/CMakeLists.txt b/app/audio/CMakeLists.txt index b8b8e49a2..ec33300f0 100644 --- a/app/audio/CMakeLists.txt +++ b/app/audio/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -24,8 +24,6 @@ set(OLIVE_SOURCES audio/outputdeviceproxy.cpp audio/outputmanager.h audio/outputmanager.cpp - audio/sampleformat.h - audio/sampleformat.cpp audio/tempoprocessor.h audio/tempoprocessor.cpp PARENT_SCOPE diff --git a/app/audio/audiomanager.cpp b/app/audio/audiomanager.cpp index a0afa7cce..d4716a7f9 100644 --- a/app/audio/audiomanager.cpp +++ b/app/audio/audiomanager.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "config/config.h" -OLIVE_NAMESPACE_ENTER +namespace olive { AudioManager* AudioManager::instance_ = nullptr; @@ -124,36 +124,8 @@ void AudioManager::SetOutputDevice(const QAudioDeviceInfo &info) format.setChannelCount(output_params_.channel_count()); format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); - - switch (output_params_.format()) { - case SampleFormat::SAMPLE_FMT_U8: - format.setSampleSize(8); - format.setSampleType(QAudioFormat::UnSignedInt); - break; - case SampleFormat::SAMPLE_FMT_S16: - format.setSampleSize(16); - format.setSampleType(QAudioFormat::SignedInt); - break; - case SampleFormat::SAMPLE_FMT_S32: - format.setSampleSize(32); - format.setSampleType(QAudioFormat::SignedInt); - break; - case SampleFormat::SAMPLE_FMT_S64: - format.setSampleSize(64); - format.setSampleType(QAudioFormat::SignedInt); - break; - case SampleFormat::SAMPLE_FMT_FLT: - format.setSampleSize(32); - format.setSampleType(QAudioFormat::Float); - break; - case SampleFormat::SAMPLE_FMT_DBL: - format.setSampleSize(64); - format.setSampleType(QAudioFormat::Float); - break; - case SampleFormat::SAMPLE_FMT_COUNT: - case SampleFormat::SAMPLE_FMT_INVALID: - abort(); - } + format.setSampleSize(output_params_.bits_per_sample()); + format.setSampleType(AudioParams::GetQtSampleType(output_params_.format())); if (info.isFormatSupported(format)) { QMetaObject::invokeMethod(output_manager_, @@ -296,4 +268,4 @@ void AudioManager::InputDevicesRefreshed() emit InputListReady(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/audio/audiomanager.h b/app/audio/audiomanager.h index d351e6852..26503e26c 100644 --- a/app/audio/audiomanager.h +++ b/app/audio/audiomanager.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -32,7 +32,7 @@ #include "render/audioparams.h" #include "render/audioplaybackcache.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief Audio input and output management class @@ -124,6 +124,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // AUDIOMANAGER_H diff --git a/app/audio/audiovisualwaveform.cpp b/app/audio/audiovisualwaveform.cpp index 9cba6f755..ec99aed9d 100644 --- a/app/audio/audiovisualwaveform.cpp +++ b/app/audio/audiovisualwaveform.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "config/config.h" -OLIVE_NAMESPACE_ENTER +namespace olive { const int AudioVisualWaveform::kSumSampleRate = 200; @@ -151,6 +151,10 @@ void AudioVisualWaveform::Shift(const rational &from, const rational &to) return; } + if (from_index > data_.size()) { + return; + } + if (from_index > to_index) { // Shifting backwards <- int copy_sz = data_.size() - from_index; @@ -330,4 +334,4 @@ void AudioVisualWaveform::ExpandMinMax(AudioVisualWaveform::SamplePerChannel &su } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/audio/audiovisualwaveform.h b/app/audio/audiovisualwaveform.h index 1273c576d..759f71385 100644 --- a/app/audio/audiovisualwaveform.h +++ b/app/audio/audiovisualwaveform.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "codec/samplebuffer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A buffer of data used to store a visual representation of audio @@ -108,8 +108,8 @@ private: }; -OLIVE_NAMESPACE_EXIT +} -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::AudioVisualWaveform) +Q_DECLARE_METATYPE(olive::AudioVisualWaveform) #endif // SUMSAMPLES_H diff --git a/app/audio/outputdeviceproxy.cpp b/app/audio/outputdeviceproxy.cpp index 112ee5c53..d7c77caa0 100644 --- a/app/audio/outputdeviceproxy.cpp +++ b/app/audio/outputdeviceproxy.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "audiomanager.h" -OLIVE_NAMESPACE_ENTER +namespace olive { AudioOutputDeviceProxy::AudioOutputDeviceProxy(QObject *parent) : QIODevice(parent), @@ -137,4 +137,4 @@ qint64 AudioOutputDeviceProxy::ReverseAwareRead(char *data, qint64 maxlen) return read_count; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/audio/outputdeviceproxy.h b/app/audio/outputdeviceproxy.h index 60ef8cf3c..5767d97c4 100644 --- a/app/audio/outputdeviceproxy.h +++ b/app/audio/outputdeviceproxy.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/define.h" #include "tempoprocessor.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief QIODevice wrapper that can adjust speed/reverse an audio file @@ -61,6 +61,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // AUDIOOUTPUTDEVICEPROXY_H diff --git a/app/audio/outputmanager.cpp b/app/audio/outputmanager.cpp index 8c4a059fc..42afd5f2a 100644 --- a/app/audio/outputmanager.cpp +++ b/app/audio/outputmanager.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { AudioOutputManager::AudioOutputManager(QObject *parent) : QObject(parent), @@ -151,4 +151,4 @@ void AudioOutputManager::OutputStateChanged(QAudio::State state) qDebug() << state << output_->error(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/audio/outputmanager.h b/app/audio/outputmanager.h index 994b4aff7..8c29ef299 100644 --- a/app/audio/outputmanager.h +++ b/app/audio/outputmanager.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "outputdeviceproxy.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class AudioOutputManager : public QObject { @@ -59,7 +59,7 @@ public slots: void ResetToPushMode(); // Queued - void SetParameters(OLIVE_NAMESPACE::AudioParams params); + void SetParameters(olive::AudioParams params); // Queued void Close(); @@ -84,6 +84,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // AUDIOHYBRIDDEVICE_H diff --git a/app/audio/sampleformat.cpp b/app/audio/sampleformat.cpp deleted file mode 100644 index f7af19c65..000000000 --- a/app/audio/sampleformat.cpp +++ /dev/null @@ -1,52 +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 "sampleformat.h" - -#include "core.h" - -OLIVE_NAMESPACE_ENTER - -const SampleFormat::Format SampleFormat::kInternalFormat = SAMPLE_FMT_FLT; - -QString SampleFormat::GetSampleFormatName(const SampleFormat::Format &f) -{ - switch (f) { - case SAMPLE_FMT_U8: - return tr("Unsigned 8-bit"); - case SAMPLE_FMT_S16: - return tr("Signed 16-bit"); - case SAMPLE_FMT_S32: - return tr("Signed 32-bit"); - case SAMPLE_FMT_S64: - return tr("Signed 64-bit"); - case SAMPLE_FMT_FLT: - return tr("32-bit Float"); - case SAMPLE_FMT_DBL: - return tr("64-bit Float"); - case SAMPLE_FMT_COUNT: - case SAMPLE_FMT_INVALID: - break; - } - - return tr("Invalid"); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/audio/sampleformat.h b/app/audio/sampleformat.h deleted file mode 100644 index 8b4dd5a9f..000000000 --- a/app/audio/sampleformat.h +++ /dev/null @@ -1,58 +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 . - -***/ - -#ifndef SAMPLEFORMAT_H -#define SAMPLEFORMAT_H - -#include - -#include "common/define.h" -#include "render/rendermodes.h" - -OLIVE_NAMESPACE_ENTER - -class SampleFormat : public QObject -{ - Q_OBJECT -public: - SampleFormat() = default; - - enum Format { - SAMPLE_FMT_INVALID = -1, - - SAMPLE_FMT_U8, - SAMPLE_FMT_S16, - SAMPLE_FMT_S32, - SAMPLE_FMT_S64, - SAMPLE_FMT_FLT, - SAMPLE_FMT_DBL, - - SAMPLE_FMT_COUNT - }; - - static const Format kInternalFormat; - - static QString GetSampleFormatName(const Format& f); - -}; - -OLIVE_NAMESPACE_EXIT - -#endif // SAMPLEFORMAT_H diff --git a/app/audio/tempoprocessor.cpp b/app/audio/tempoprocessor.cpp index 2deda4f33..444acece3 100644 --- a/app/audio/tempoprocessor.cpp +++ b/app/audio/tempoprocessor.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,9 +28,9 @@ extern "C" { #include -#include "codec/ffmpeg/ffmpegcommon.h" +#include "common/ffmpegutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TempoProcessor::TempoProcessor() : filter_graph_(nullptr), @@ -75,7 +75,7 @@ bool TempoProcessor::Open(const AudioParams ¶ms, const double& speed) 1, params_.sample_rate(), params_.sample_rate(), - FFmpegCommon::GetFFmpegSampleFormat(params_.format()), + FFmpegUtils::GetFFmpegSampleFormat(params_.format()), params.channel_layout()); // Create buffer and buffersink @@ -171,7 +171,7 @@ void TempoProcessor::Push(const char *data, int length) // Allocate a buffer for the number of samples we got src_frame->sample_rate = params_.sample_rate(); - src_frame->format = FFmpegCommon::GetFFmpegSampleFormat(params_.format()); + src_frame->format = FFmpegUtils::GetFFmpegSampleFormat(params_.format()); src_frame->channel_layout = params_.channel_layout(); src_frame->nb_samples = params_.bytes_to_samples(length); src_frame->pts = timestamp_; @@ -274,4 +274,4 @@ AVFilterContext *TempoProcessor::CreateTempoFilter(AVFilterGraph* graph, AVFilte return nullptr; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/audio/tempoprocessor.h b/app/audio/tempoprocessor.h index a118352e0..53d5ee96b 100644 --- a/app/audio/tempoprocessor.h +++ b/app/audio/tempoprocessor.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -35,7 +35,7 @@ extern "C" { #include "render/audioparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TempoProcessor { @@ -78,6 +78,6 @@ private: bool flushed_; }; -OLIVE_NAMESPACE_EXIT +} #endif // TEMPOPROCESSOR_H diff --git a/app/cli/CMakeLists.txt b/app/cli/CMakeLists.txt index 6fe09bdc8..69d74d13d 100644 --- a/app/cli/CMakeLists.txt +++ b/app/cli/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/cli/cliexport/cliexportmanager.cpp b/app/cli/cliexport/cliexportmanager.cpp index de0145729..f0bbaa0d4 100644 --- a/app/cli/cliexport/cliexportmanager.cpp +++ b/app/cli/cliexport/cliexportmanager.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,11 +20,11 @@ #include "cliexportmanager.h" -OLIVE_NAMESPACE_ENTER +namespace olive { CLIExportManager::CLIExportManager() { } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/cli/cliexport/cliexportmanager.h b/app/cli/cliexport/cliexportmanager.h index 6d3fc346b..7bfd9f14b 100644 --- a/app/cli/cliexport/cliexportmanager.h +++ b/app/cli/cliexport/cliexportmanager.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "task/export/export.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class CLIExportManager : public QObject { @@ -31,6 +31,6 @@ public: CLIExportManager(); }; -OLIVE_NAMESPACE_EXIT +} #endif // CLIEXPORTMANAGER_H diff --git a/app/cli/cliprogress/CMakeLists.txt b/app/cli/cliprogress/CMakeLists.txt index 27a57775c..c1a5e96fa 100644 --- a/app/cli/cliprogress/CMakeLists.txt +++ b/app/cli/cliprogress/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/cli/cliprogress/cliprogressdialog.cpp b/app/cli/cliprogress/cliprogressdialog.cpp index 88c0cfd57..522b23e31 100644 --- a/app/cli/cliprogress/cliprogressdialog.cpp +++ b/app/cli/cliprogress/cliprogressdialog.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { CLIProgressDialog::CLIProgressDialog(const QString& title, QObject *parent) : QObject(parent), @@ -103,4 +103,4 @@ void CLIProgressDialog::SetProgress(double p) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/cli/cliprogress/cliprogressdialog.h b/app/cli/cliprogress/cliprogressdialog.h index 40ffea6e8..c5874ed26 100644 --- a/app/cli/cliprogress/cliprogressdialog.h +++ b/app/cli/cliprogress/cliprogressdialog.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class CLIProgressDialog : public QObject { @@ -47,6 +47,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // CLIPROGRESSDIALOG_H diff --git a/app/cli/clitask/CMakeLists.txt b/app/cli/clitask/CMakeLists.txt index d3a84091d..3ac2f602e 100644 --- a/app/cli/clitask/CMakeLists.txt +++ b/app/cli/clitask/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/cli/clitask/clitaskdialog.cpp b/app/cli/clitask/clitaskdialog.cpp index bb567f586..b06c18a66 100644 --- a/app/cli/clitask/clitaskdialog.cpp +++ b/app/cli/clitask/clitaskdialog.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "clitaskdialog.h" -OLIVE_NAMESPACE_ENTER +namespace olive { CLITaskDialog::CLITaskDialog(Task *task, QObject* parent) : CLIProgressDialog(task->GetTitle(), parent), @@ -34,4 +34,4 @@ bool CLITaskDialog::Run() return task_->Start(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/cli/clitask/clitaskdialog.h b/app/cli/clitask/clitaskdialog.h index c574b6011..79a626900 100644 --- a/app/cli/clitask/clitaskdialog.h +++ b/app/cli/clitask/clitaskdialog.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "cli/cliprogress/cliprogressdialog.h" #include "task/task.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class CLITaskDialog : public CLIProgressDialog { @@ -39,6 +39,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // CLITASKDIALOG_H diff --git a/app/codec/CMakeLists.txt b/app/codec/CMakeLists.txt index bce758bfd..b3639dca8 100644 --- a/app/codec/CMakeLists.txt +++ b/app/codec/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/codec/decoder.cpp b/app/codec/decoder.cpp index d4dc7108b..26efa8ccc 100644 --- a/app/codec/decoder.cpp +++ b/app/codec/decoder.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,11 +24,11 @@ #include #include -#include "codec/ffmpeg/ffmpegcommon.h" #include "codec/ffmpeg/ffmpegdecoder.h" #include "codec/oiio/oiiodecoder.h" #include "codec/waveinput.h" #include "codec/waveoutput.h" +#include "common/ffmpegutils.h" #include "common/filefunctions.h" #include "common/timecodefunctions.h" #ifdef USE_OTIO @@ -37,57 +37,162 @@ #include "task/taskmanager.h" #include "project/project.h" -OLIVE_NAMESPACE_ENTER +namespace olive { + +QMutex Decoder::currently_conforming_mutex_; +QWaitCondition Decoder::currently_conforming_wait_cond_; +QVector Decoder::currently_conforming_; Decoder::Decoder() : - open_(false), stream_(nullptr) { } -Decoder::Decoder(Stream *fs) : - open_(false), - stream_(fs) +bool Decoder::Open(StreamPtr fs) { + QMutexLocker locker(&mutex_); + + if (stream_) { + // Decoder is already open. Return TRUE if the stream is the stream we have, or FALSE if not. + if (stream_ == fs) { + return true; + } else { + qWarning() << "Tried to open a decoder that was already open with another stream"; + return false; + } + } else { + // Stream was not open, try opening it now + if (fs == nullptr) { + // Cannot open null stream + qCritical() << "Decoder attempted to open null stream"; + return false; + } + + if (fs->footage()->decoder() != id()) { + qCritical() << "Tried to open footage in incorrect decoder"; + return false; + } + + // Set stream + stream_ = fs; + + // Try open internal + if (OpenInternal()) { + return true; + } else { + // Unset stream + CloseInternal(); + stream_ = nullptr; + return false; + } + } } -StreamPtr Decoder::stream() const +FramePtr Decoder::RetrieveVideo(const rational &timecode, const int ÷r) { - return stream_; + QMutexLocker locker(&mutex_); + + if (!stream_) { + qCritical() << "Can't retrieve video on a closed decoder"; + return nullptr; + } + + if (!SupportsVideo()) { + qCritical() << "Decoder doesn't support video"; + return nullptr; + } + + if (stream_->type() != Stream::kVideo) { + qCritical() << "Tried to retrieve video from a non-video stream"; + return nullptr; + } + + return RetrieveVideoInternal(timecode, divider); } -void Decoder::set_stream(StreamPtr fs) +SampleBufferPtr Decoder::RetrieveAudio(const TimeRange &range, const AudioParams ¶ms, const QAtomicInt *cancelled) { - Close(); + QMutexLocker locker(&mutex_); - stream_ = fs; + if (!stream_) { + qCritical() << "Can't retrieve audio on a closed decoder"; + return nullptr; + } + + if (!SupportsAudio()) { + qCritical() << "Decoder doesn't support audio"; + return nullptr; + } + + if (stream_->type() != Stream::kAudio) { + qCritical() << "Tried to retrieve audio from a non-audio stream"; + return nullptr; + } + + // Determine if we already have a conformed version + QString conform_filename = GetConformedFilename(params); + CurrentlyConforming want_conform = {stream_, params}; + + currently_conforming_mutex_.lock(); + + // Wait for conform to complete + while (currently_conforming_.contains(want_conform)) { + currently_conforming_wait_cond_.wait(¤tly_conforming_mutex_); + } + + // See if we got the conform + SampleBufferPtr buffer = RetrieveAudioFromConform(conform_filename, range); + + if (!buffer) { + // We'll need to conform this ourselves + currently_conforming_.append(want_conform); + currently_conforming_mutex_.unlock(); + + // We conform to a different filename until it's done to make it clear even across sessions + // whether this conform is ready or not + QString working_fn = conform_filename; + working_fn.append(QStringLiteral(".working")); + + if (ConformAudioInternal(working_fn, params, cancelled)) { + // Move file to standard conform name, making it clear this conform is ready for use + QFile::remove(conform_filename); + QFile::rename(working_fn, conform_filename); + + // Return audio as planned + buffer = RetrieveAudioFromConform(conform_filename, range); + } else { + // Failed + qCritical() << "Failed to conform audio"; + } + + currently_conforming_mutex_.lock(); + currently_conforming_.removeOne(want_conform); + currently_conforming_wait_cond_.wakeAll(); + } + + currently_conforming_mutex_.unlock(); + + return buffer; } -FramePtr Decoder::RetrieveVideo(const rational &/*timecode*/, const int &/*divider*/) +void Decoder::Close() { - return nullptr; -} + QMutexLocker locker(&mutex_); -SampleBufferPtr Decoder::RetrieveAudio(const rational &/*timecode*/, const rational &/*length*/, const AudioParams &/*params*/) -{ - return nullptr; -} - -bool Decoder::SupportsVideo() -{ - return false; -} - -bool Decoder::SupportsAudio() -{ - return false; + if (stream_) { + CloseInternal(); + stream_ = nullptr; + } else { + qWarning() << "Tried to close a decoder that wasn't open"; + } } /* * DECODER STATIC PUBLIC MEMBERS */ -QVector ReceiveListOfAllDecoders() { +QVector ReceiveListOfAllDecoders() +{ QVector decoders; // The order in which these decoders are added is their priority when probing. Hence FFmpeg should usually be last, @@ -98,7 +203,7 @@ QVector ReceiveListOfAllDecoders() { return decoders; } -FootagePtr Decoder::ProbeMedia(Project* project, const QString &filename, const QAtomicInt* cancelled) +FootagePtr Decoder::Probe(Project* project, const QString &filename, const QAtomicInt* cancelled) { // Check for a valid filename if (filename.isEmpty()) { @@ -184,37 +289,6 @@ QString Decoder::GetIndexFilename() return QDir(stream_->footage()->project()->cache_path()).filePath(FileFunctions::GetUniqueFileIdentifier(stream()->footage()->filename()).append(QString::number(stream()->index()))); } -bool Decoder::ConformAudio(const QAtomicInt *, const AudioParams& ) -{ - return false; -} - -bool Decoder::HasConformedVersion(const AudioParams ¶ms) -{ - if (stream()->type() != Stream::kAudio) { - return false; - } - - AudioStreamPtr audio_stream = std::static_pointer_cast(stream()); - - if (audio_stream->has_conformed_version(params)) { - return true; - } - - // Get indexed WAV file - WaveInput input(GetIndexFilename()); - - bool index_already_matches = false; - - if (input.open()) { - index_already_matches = (input.params() == params); - - input.close(); - } - - return index_already_matches; -} - void Decoder::SignalProcessingProgress(const int64_t &ts) { if (stream()->duration() != AV_NOPTS_VALUE && stream()->duration() != 0) { @@ -267,4 +341,40 @@ int64_t Decoder::GetImageSequenceIndex(const QString &filename) return number_only.toLongLong(); } -OLIVE_NAMESPACE_EXIT +FramePtr Decoder::RetrieveVideoInternal(const rational &timecode, const int ÷r) +{ + Q_UNUSED(timecode) + Q_UNUSED(divider) + return nullptr; +} + +bool Decoder::ConformAudioInternal(const QString& filename, const AudioParams ¶ms, const QAtomicInt* cancelled) +{ + Q_UNUSED(filename) + Q_UNUSED(cancelled) + Q_UNUSED(params) + return false; +} + +SampleBufferPtr Decoder::RetrieveAudioFromConform(const QString &conform_filename, const TimeRange& range) +{ + WaveInput input(conform_filename); + + if (input.open()) { + const AudioParams& input_params = input.params(); + + // Read bytes from wav + QByteArray packed_data = input.read(input_params.time_to_bytes(range.in()), + input_params.time_to_bytes(range.length())); + input.close(); + + // Create sample buffer + SampleBufferPtr sample_buffer = SampleBuffer::CreateFromPackedData(input_params, packed_data); + + return sample_buffer; + } + + return nullptr; +} + +} diff --git a/app/codec/decoder.h b/app/codec/decoder.h index a096d5b08..74137e33b 100644 --- a/app/codec/decoder.h +++ b/app/codec/decoder.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,6 +27,7 @@ extern "C" { #include #include +#include #include #include "codec/frame.h" @@ -35,7 +36,7 @@ extern "C" { #include "common/rational.h" #include "project/item/footage/footage.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Decoder; using DecoderPtr = std::shared_ptr; @@ -68,117 +69,46 @@ public: Decoder(); - Decoder(Stream* fs); - - DISABLE_COPY_MOVE(Decoder) - + /** + * @brief Unique decoder ID + */ virtual QString id() = 0; - StreamPtr stream() const; - void set_stream(StreamPtr fs); + virtual bool SupportsVideo(){return false;} + virtual bool SupportsAudio(){return false;} /** - * @brief Probe a footage file and dump metadata about it + * @brief Open stream for decoding * - * When a Footage file is imported, we'll need to know whether Olive is equipped with a decoder for utilizing it - * and metadata should be retrieved about it if so. For this purpose, the Footage object is passed through all - * Probe() functions of available deocders until one returns TRUE. A FALSE return means the Decoder was unable to - * parse this file and the next should be tried. + * This function is thread safe. * - * Probe() differs from Open() since it focuses on a file as a whole rather than one particular stream. Probe() - * should be able to be run directly without calling Open() or Close() and should free its memory before returning. - * - * Probe() will never be called on an object that is also used for decoding. In other words, it will never be called - * alongside Open() or Close() externally, so Probe() can use variables that would otherwise be used for decoding - * without conflict. - * - * @param f - * - * A Footage object to probe. The Footage object will have a valid filename and will be empty prior to being sent - * to this function (i.e. Footage::Clear() will not have to be called). - * - * @return - * - * TRUE if the Decoder was able to decode this file. FALSE if not. This function should have filled the Footage - * object with metadata if it returns TRUE. Otherwise, the Footage object should be untouched. + * Returns TRUE if stream could be opened successfully. Also returns TRUE if the decoder is + * already open and the stream == the stream provided. Returns FALSE if the stream couldn't + * be opened OR if already open and the stream is NOT the same. */ - virtual FootagePtr Probe(const QString& filename, const QAtomicInt* cancelled) const = 0; + bool Open(StreamPtr fs); /** - * @brief Open media/allocate memory + * @brief Retrieves a video frame from footage * - * Any file handles or memory allocation that needs to be done before this instance of a Decoder can return data - * should be done here. + * This function will always return a valid frame unless a fatal error occurs (in such case, + * nullptr will return). If the timecode is before the start of the footage, this function should + * return the first frame. Likewise, if it is after the timecode, this function should return the + * last frame. * - * @return - * - * TRUE if successful and ready to return data, FALSE if failed to open and unable to retrieve data. If the function - * fails, any memory allocated should be free'd before returning FALSE, possibly by calling Close(). + * This function is thread safe and can only run while the decoder is open. \see Open() */ - virtual bool Open() = 0; + FramePtr RetrieveVideo(const rational& timecode, const int& divider); /** - * @brief Retrieve video frame + * @brief Retrieve audio data from footage * - * The main function for retrieving video data from the Decoder. This function should always provide complete frame - * data (i.e. no partial frames) at the timecode provided. The Decoder should perform any steps required to retrieve - * a complete frame separate from the rest of the program, using any form of caching/indexing to keep this as - * performant as possible. + * This function will always return a sample buffer unless a fatal error occurs (in such case, + * nullptr will return). The SampleBuffer should always have enough audio for the range provided. * - * It's acceptable for this function to check whether the Decoder is open, and call Open() if not. If Open() returns - * false, this function should return nullptr. - * - * @param timecode - * - * The timecode (a rational in seconds) to retrieve the frame at. If there is not a frame at this precise location - * this should be corrected internally to the closest fit for the timecode. - * - * @return - * - * A FramePtr of valid data at this timecode or nullptr if there was nothing to retrieve at the provided timecode or - * the media could not be opened. + * This function is thread safe and can only run while the decoder is open. \see Open() */ - virtual FramePtr RetrieveVideo(const rational& timecode, const int& divider); - - /** - * @brief Retrieve video frame - * - * The main function for retrieving audio data from the Decoder. This function should always provide complete frame - * data (i.e. no missing samples) at the timecode and length requested. The Decoder should perform any steps - * required to retrieve a complete frame separate from the rest of the program, using any form of caching/indexing - * to keep this as performant as possible. - * - * It's acceptable for this function to check whether the Decoder is open, and call Open() if not. If Open() returns - * false, this function should return nullptr. - * - * @param timecode - * - * The starting timecode (a rational in seconds) to retrieve the data at. - * - * @param length - * - * The total length of audio data to retrieve (a rational in seconds). - * - * @return - * - * A FramePtr of valid data at this timecode of the requested length or nullptr if there was nothing to retrieve at - * the provided timecode or the media could not be opened. - */ - virtual SampleBufferPtr RetrieveAudio(const rational& timecode, const rational& length, const AudioParams& params); - - virtual bool SupportsVideo(); - virtual bool SupportsAudio(); - - /** - * @brief Close media/deallocate memory - * - * Any file handles or memory allocations opened in Open() should be cleaned up here. - * - * As the main memory freeing function, it's good practice to call this in Open() if there's an error that prevents - * correct function before Open() returns. As such, Close() should be prepared for not all memory/file handles to - * have been opened successfully. - */ - virtual void Close() = 0; + SampleBufferPtr RetrieveAudio(const TimeRange& range, const AudioParams& params, const QAtomicInt *cancelled); /** * @brief Try to probe a Footage file by passing it through all available Decoders @@ -199,7 +129,27 @@ public: * * TRUE if a Decoder was successfully able to parse and probe this file. FALSE if not. */ - static FootagePtr ProbeMedia(Project *project, const QString& filename, const QAtomicInt *cancelled); + static FootagePtr Probe(Project *project, const QString& filename, const QAtomicInt *cancelled); + + /** + * @brief Generate a Footage object from a file + * + * If this decoder is able to parse this file, it will return a valid FootagePtr. Otherwise, it + * will return nullptr. + * + * For sub-classes, this function should be effectively static. We can't do virtual static + * functions in C++, but it should hold and access no state during its run. + * + * This function is re-entrant. + */ + virtual FootagePtr Probe(const QString& filename, const QAtomicInt* cancelled) const = 0; + + /** + * @brief Closes media/deallocates memory + * + * This function is thread safe and can only run while the decoder is open. \see Open() + */ + void Close(); /** * @brief Create a Decoder instance using a Decoder ID @@ -210,42 +160,45 @@ public: */ static DecoderPtr CreateFromID(const QString& id); - /** - * @brief AUDIO ONLY: Produces a complete PCM extraction of the audio stream - * - * Internally, our render engine only deals with PCM since it provides the least headaches and - * modern computers have the processing power to do it. - * - * Resamples and converts the currently open audio to match the params. If the audio doesn't need - * conforming (e.g. audio params already match or a conformed match already exists), this function - * will return immediately. Otherwise it will block the calling thread until the conform is - * complete. This function should therefore only be called from a background render thread. - * - * All audio decoders must override this. It's not pure since video decoders don't need to use - * this, but default behavior will abort since it should never be called. - */ - virtual bool ConformAudio(const QAtomicInt* cancelled, const AudioParams ¶ms); - - /** - * @brief AUDIO ONLY: Returns whether a transcode of this audio matching the specified params - * already exists - */ - bool HasConformedVersion(const AudioParams& params); - static QString TransformImageSequenceFileName(const QString& filename, const int64_t& number); static int GetImageSequenceDigitCount(const QString& filename); static int64_t GetImageSequenceIndex(const QString& filename); -signals: - /** - * @brief While indexing, this signal will provide progress as a percentage (0-100 inclusive) if - * available - */ - void IndexProgress(double); - protected: + /** + * @brief Internal open function + * + * Sub-classes must override this function. Function will already be mutexed, so there is no need + * to worry about thread safety. Also many other sanity checks will be done before this, so + * sub-classes only need to worry about their own opening functions. It is guaranteed that the + * decoder is not open yet and that the footage stream was from that sub-classes probe function. + * + * Return TRUE if everything opened successfully and the decoder is ready to work. Otherwise, + * return FALSE. If this function returns false, Decoder will call CloseInternal to clean any + * memory allocated during OpenInternal. + */ + virtual bool OpenInternal() = 0; + + /** + * @brief Internal close function + * + * Sub-classes must override this function. Function should be able to safely clear all allocated + * memory. It may be called even if Open() didn't complete or RetrieveVideo() was never called. + */ + virtual void CloseInternal() = 0; + + /** + * @brief Internal frame retrieval function + * + * Sub-classes must override this function IF they support video. Function is already mutexed + * so sub-classes don't need to worry about thread safety. + */ + virtual FramePtr RetrieveVideoInternal(const rational& timecode, const int& divider); + + virtual bool ConformAudioInternal(const QString& filename, const AudioParams ¶ms, const QAtomicInt* cancelled); + void SignalProcessingProgress(const int64_t& ts); /** @@ -255,15 +208,48 @@ protected: QString GetIndexFilename(); - bool open_; + struct CurrentlyConforming { + StreamPtr stream; + AudioParams params; + + bool operator==(const CurrentlyConforming& rhs) const + { + return this->stream == rhs.stream && this->params == rhs.params; + } + }; + + /** + * @brief Return currently open stream + * + * This function is NOT thread safe and should therefore only be called by thread safe functions. + */ + StreamPtr stream() const + { + return stream_; + } + + static QMutex currently_conforming_mutex_; + static QWaitCondition currently_conforming_wait_cond_; + static QVector currently_conforming_; + +signals: + /** + * @brief While indexing, this signal will provide progress as a percentage (0-100 inclusive) if + * available + */ + void IndexProgress(double); private: + SampleBufferPtr RetrieveAudioFromConform(const QString& conform_filename, const TimeRange &range); + StreamPtr stream_; + QMutex mutex_; + }; -OLIVE_NAMESPACE_EXIT +} -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::Decoder::RetrieveState) +Q_DECLARE_METATYPE(olive::Decoder::RetrieveState) #endif // DECODER_H diff --git a/app/codec/encoder.cpp b/app/codec/encoder.cpp index 0f648884e..fe7204c36 100644 --- a/app/codec/encoder.cpp +++ b/app/codec/encoder.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "ffmpeg/ffmpegencoder.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Encoder::Encoder(const EncodingParams ¶ms) : params_(params) @@ -232,8 +232,8 @@ void EncodingParams::Save(QXmlStreamWriter *writer) const Encoder* Encoder::CreateFromID(const QString &id, const EncodingParams& params) { Q_UNUSED(id) - + return new FFmpegEncoder(params); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/codec/encoder.h b/app/codec/encoder.h index 4acf38bde..24ac3a84c 100644 --- a/app/codec/encoder.h +++ b/app/codec/encoder.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -32,7 +32,7 @@ #include "render/audioparams.h" #include "render/videoparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Encoder; using EncoderPtr = std::shared_ptr; @@ -114,19 +114,24 @@ public: virtual bool Open() = 0; - virtual bool WriteFrame(OLIVE_NAMESPACE::FramePtr frame, OLIVE_NAMESPACE::rational time) = 0; - virtual void WriteAudio(OLIVE_NAMESPACE::AudioParams pcm_info, + virtual bool WriteFrame(olive::FramePtr frame, olive::rational time) = 0; + virtual void WriteAudio(olive::AudioParams pcm_info, QIODevice *file) = 0; - void WriteAudio(OLIVE_NAMESPACE::AudioParams pcm_info, + void WriteAudio(olive::AudioParams pcm_info, const QString& pcm_filename); virtual void Close() = 0; + virtual VideoParams::Format GetDesiredPixelFormat() const + { + return VideoParams::kFormatInvalid; + } + private: EncodingParams params_; }; -OLIVE_NAMESPACE_EXIT +} #endif // ENCODER_H diff --git a/app/codec/exportcodec.cpp b/app/codec/exportcodec.cpp index 4f8aca533..0654c5f78 100644 --- a/app/codec/exportcodec.cpp +++ b/app/codec/exportcodec.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ extern "C" { #include } -OLIVE_NAMESPACE_ENTER +namespace olive { QString ExportCodec::GetCodecName(ExportCodec::Codec c) { @@ -125,4 +125,4 @@ QStringList ExportCodec::GetPixelFormatsForCodec(ExportCodec::Codec c) return pix_fmts; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/codec/exportcodec.h b/app/codec/exportcodec.h index d7a41124b..6f3e0c49e 100644 --- a/app/codec/exportcodec.h +++ b/app/codec/exportcodec.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,9 +26,11 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -class ExportCodec : public QObject { +class ExportCodec : public QObject +{ + Q_OBJECT public: enum Codec { kCodecDNxHD, @@ -55,6 +57,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // EXPORTCODEC_H diff --git a/app/codec/exportformat.cpp b/app/codec/exportformat.cpp index 8f9f76973..caeca6412 100644 --- a/app/codec/exportformat.cpp +++ b/app/codec/exportformat.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "exportformat.h" -OLIVE_NAMESPACE_ENTER +namespace olive { QString ExportFormat::GetName(olive::ExportFormat::Format f) { @@ -135,4 +135,4 @@ QList ExportFormat::GetAudioCodecs(ExportFormat::Format f) return {}; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/codec/exportformat.h b/app/codec/exportformat.h index 566bb3175..eaaea84c5 100644 --- a/app/codec/exportformat.h +++ b/app/codec/exportformat.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,9 +27,11 @@ #include "common/define.h" #include "exportcodec.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -class ExportFormat : public QObject { +class ExportFormat : public QObject +{ + Q_OBJECT public: enum Format { kFormatDNxHD, @@ -51,6 +53,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // EXPORTFORMAT_H diff --git a/app/codec/ffmpeg/CMakeLists.txt b/app/codec/ffmpeg/CMakeLists.txt index 12267fe76..436598852 100644 --- a/app/codec/ffmpeg/CMakeLists.txt +++ b/app/codec/ffmpeg/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -16,9 +16,6 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} - codec/ffmpeg/avframeptr.h - codec/ffmpeg/ffmpegcommon.h - codec/ffmpeg/ffmpegcommon.cpp codec/ffmpeg/ffmpegdecoder.h codec/ffmpeg/ffmpegdecoder.cpp codec/ffmpeg/ffmpegencoder.h diff --git a/app/codec/ffmpeg/ffmpegcommon.cpp b/app/codec/ffmpeg/ffmpegcommon.cpp deleted file mode 100644 index f66804048..000000000 --- a/app/codec/ffmpeg/ffmpegcommon.cpp +++ /dev/null @@ -1,139 +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 "ffmpegcommon.h" - -OLIVE_NAMESPACE_ENTER - -AVPixelFormat FFmpegCommon::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt) -{ - AVPixelFormat possible_pix_fmts[] = { - AV_PIX_FMT_RGB24, - AV_PIX_FMT_RGBA, - AV_PIX_FMT_RGB48, - AV_PIX_FMT_RGBA64, - AV_PIX_FMT_NONE - }; - - return avcodec_find_best_pix_fmt_of_list(possible_pix_fmts, - pix_fmt, - 1, - nullptr); -} - -SampleFormat::Format FFmpegCommon::GetNativeSampleFormat(const AVSampleFormat &smp_fmt) -{ - switch (smp_fmt) { - case AV_SAMPLE_FMT_U8: - return SampleFormat::SAMPLE_FMT_U8; - case AV_SAMPLE_FMT_S16: - return SampleFormat::SAMPLE_FMT_S16; - case AV_SAMPLE_FMT_S32: - return SampleFormat::SAMPLE_FMT_S32; - case AV_SAMPLE_FMT_S64: - return SampleFormat::SAMPLE_FMT_S64; - case AV_SAMPLE_FMT_FLT: - return SampleFormat::SAMPLE_FMT_FLT; - case AV_SAMPLE_FMT_DBL: - return SampleFormat::SAMPLE_FMT_DBL; - case AV_SAMPLE_FMT_U8P : - case AV_SAMPLE_FMT_S16P: - case AV_SAMPLE_FMT_S32P: - case AV_SAMPLE_FMT_S64P: - case AV_SAMPLE_FMT_FLTP: - case AV_SAMPLE_FMT_DBLP: - case AV_SAMPLE_FMT_NONE: - case AV_SAMPLE_FMT_NB: - break; - } - - return SampleFormat::SAMPLE_FMT_INVALID; -} - -AVSampleFormat FFmpegCommon::GetFFmpegSampleFormat(const SampleFormat::Format &smp_fmt) -{ - switch (smp_fmt) { - case SampleFormat::SAMPLE_FMT_U8: - return AV_SAMPLE_FMT_U8; - case SampleFormat::SAMPLE_FMT_S16: - return AV_SAMPLE_FMT_S16; - case SampleFormat::SAMPLE_FMT_S32: - return AV_SAMPLE_FMT_S32; - case SampleFormat::SAMPLE_FMT_S64: - return AV_SAMPLE_FMT_S64; - case SampleFormat::SAMPLE_FMT_FLT: - return AV_SAMPLE_FMT_FLT; - case SampleFormat::SAMPLE_FMT_DBL: - return AV_SAMPLE_FMT_DBL; - case SampleFormat::SAMPLE_FMT_INVALID: - case SampleFormat::SAMPLE_FMT_COUNT: - break; - } - - return AV_SAMPLE_FMT_NONE; -} - -AVPixelFormat FFmpegCommon::GetFFmpegPixelFormat(const PixelFormat::Format &pix_fmt) -{ - switch (pix_fmt) { - case PixelFormat::PIX_FMT_RGBA8: - return AV_PIX_FMT_RGBA; - case PixelFormat::PIX_FMT_RGBA16U: - return AV_PIX_FMT_RGBA64; - case PixelFormat::PIX_FMT_RGB8: - return AV_PIX_FMT_RGB24; - case PixelFormat::PIX_FMT_RGB16U: - return AV_PIX_FMT_RGB48; - case PixelFormat::PIX_FMT_RGBA16F: - case PixelFormat::PIX_FMT_RGBA32F: - case PixelFormat::PIX_FMT_RGB16F: - case PixelFormat::PIX_FMT_RGB32F: - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - return AV_PIX_FMT_NONE; -} - -PixelFormat::Format FFmpegCommon::GetCompatiblePixelFormat(const PixelFormat::Format &pix_fmt) -{ - switch (pix_fmt) { - case PixelFormat::PIX_FMT_RGB8: - return PixelFormat::PIX_FMT_RGB8; - case PixelFormat::PIX_FMT_RGBA8: - return PixelFormat::PIX_FMT_RGBA8; - case PixelFormat::PIX_FMT_RGB16U: - case PixelFormat::PIX_FMT_RGB16F: - case PixelFormat::PIX_FMT_RGB32F: - return PixelFormat::PIX_FMT_RGB16U; - case PixelFormat::PIX_FMT_RGBA16U: - case PixelFormat::PIX_FMT_RGBA16F: - case PixelFormat::PIX_FMT_RGBA32F: - return PixelFormat::PIX_FMT_RGBA16U; - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - return PixelFormat::PIX_FMT_INVALID; -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index c5a0f3546..bfafa2b2f 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -38,95 +38,58 @@ extern "C" { #include "codec/waveinput.h" #include "common/define.h" +#include "common/ffmpegutils.h" #include "common/filefunctions.h" #include "common/functiontimer.h" #include "common/timecodefunctions.h" -#include "ffmpegcommon.h" #include "render/framehashcache.h" #include "render/diskmanager.h" -#include "render/pixelformat.h" -OLIVE_NAMESPACE_ENTER - -QHash< Stream*, QList > FFmpegDecoder::instance_map_; -QMutex FFmpegDecoder::instance_map_lock_; -QHash< FFmpegDecoder::FFmpegFramePoolKey, FFmpegDecoder::FFmpegFramePoolValue > FFmpegDecoder::frame_pool_map_; - -// FIXME: Hardcoded value. It seems to work fine, but is there a possibility we should make -// this a dynamic value somehow or a configurable value? -const int FFmpegDecoderInstance::kMaxFrameLife = 2000; +namespace olive { FFmpegDecoder::FFmpegDecoder() : scale_ctx_(nullptr), - scale_divider_(0) + scale_divider_(0), + pool_(QThread::idealThreadCount()*2), + is_working_(false), + cache_at_zero_(false), + cache_at_eof_(false) { } FFmpegDecoder::~FFmpegDecoder() { - Close(); + CloseInternal(); } -bool FFmpegDecoder::Open() +bool FFmpegDecoder::OpenInternal() { - if (open_) { + if (instance_.Open(stream()->footage()->filename().toUtf8(), stream()->index())) { + AVStream* s = instance_.avstream(); + + // Store one second in the source's timebase + second_ts_ = qRound64(av_q2d(av_inv_q(s->time_base))); + + if (stream()->type() == Stream::kVideo) { + // Get an Olive compatible AVPixelFormat + ideal_pix_fmt_ = FFmpegUtils::GetCompatiblePixelFormat(static_cast(s->codecpar->format)); + + // Determine which Olive native pixel format we retrieved + // Note that FFmpeg doesn't support float formats + native_pix_fmt_ = GetNativePixelFormat(ideal_pix_fmt_); + native_channel_count_ = GetNativeChannelCount(ideal_pix_fmt_); + + if (native_pix_fmt_ == VideoParams::kFormatInvalid + || native_channel_count_ == 0) { + qDebug() << "Failed to find valid native pixel format for" << ideal_pix_fmt_; + return false; + } + } + return true; } - Q_ASSERT(stream()); - - // Convert QString to a C string - QByteArray fn_bytes = stream()->footage()->filename().toUtf8(); - - FFmpegDecoderInstance* our_instance = new FFmpegDecoderInstance(fn_bytes.constData(), stream()->index()); - - if (!our_instance->IsValid()) { - delete our_instance; - return false; - } - - if (stream()->type() == Stream::kVideo) { - // Get an Olive compatible AVPixelFormat - src_pix_fmt_ = static_cast(our_instance->stream()->codecpar->format); - ideal_pix_fmt_ = FFmpegCommon::GetCompatiblePixelFormat(src_pix_fmt_); - - // Determine which Olive native pixel format we retrieved - // Note that FFmpeg doesn't support float formats - native_pix_fmt_ = GetNativePixelFormat(ideal_pix_fmt_); - - Q_ASSERT(native_pix_fmt_ != PixelFormat::PIX_FMT_INVALID); - } - - if (StreamUsesMultipleInstances(stream())) { - // Video optimizes with multiple instances that we can swap between - QMutexLocker map_locker(&instance_map_lock_); - - VideoStreamPtr vs = std::static_pointer_cast(stream()); - - FFmpegFramePoolKey key = {vs->width(), vs->height(), src_pix_fmt_}; - FFmpegFramePoolValue& frame_pool = frame_pool_map_[key]; - - if (!frame_pool.pool) { - // Frames are allocated as threads * threads, to scale from each thread sharing one set - // to all of them working individually - int thread_count = QThread::idealThreadCount(); - int max_memory_frame_count = thread_count * thread_count; - frame_pool.pool = new FFmpegFramePool(max_memory_frame_count); - } - frame_pool.handles++; - - our_instance->SetFramePool(frame_pool.pool); - - instance_map_[stream().get()].append(our_instance); - } else { - // Images, image sequences, and audio don't need an instance - delete our_instance; - } - - // All allocation succeeded so we set the state to open - open_ = true; - - return true; + return false; } FramePtr FFmpegDecoder::RetrieveStillImage(const rational &timecode, const int ÷r) @@ -136,51 +99,64 @@ FramePtr FFmpegDecoder::RetrieveStillImage(const rational &timecode, const int & QString img_filename = stream()->footage()->filename(); + int64_t ts; + // If it's an image sequence, we'll probably need to transform the filename if (is->video_type() == VideoStream::kVideoTypeImageSequence) { - int64_t ts = std::static_pointer_cast(stream())->get_time_in_timebase_units(timecode); + ts = std::static_pointer_cast(stream())->get_time_in_timebase_units(timecode); img_filename = TransformImageSequenceFileName(stream()->footage()->filename(), ts); + } else { + ts = 0; } - FFmpegDecoderInstance i(img_filename.toUtf8(), stream()->index()); - AVPacket* pkt = av_packet_alloc(); AVFrame* frame = av_frame_alloc(); FramePtr output_frame = nullptr; + Instance i; + i.Open(img_filename.toUtf8(), stream()->index()); + int ret = i.GetFrame(pkt, frame); if (ret >= 0) { - output_frame = BuffersToNativeFrame(divider, - is->width(), - is->height(), - 0, - frame->data, - frame->linesize); + // Create frame to return + output_frame = Frame::Create(); + output_frame->set_video_params(VideoParams(frame->width, + frame->height, + native_pix_fmt_, + native_channel_count_, + std::static_pointer_cast(stream())->pixel_aspect_ratio(), + std::static_pointer_cast(stream())->interlacing(), + divider)); + output_frame->set_timestamp(timecode); + output_frame->allocate(); + + uint8_t* copy_data = reinterpret_cast(output_frame->data()); + int copy_linesize = output_frame->linesize_bytes(); + + FFmpegBufferToNativeBuffer(frame->data, frame->linesize, ©_data, ©_linesize); } else { qWarning() << "Failed to retrieve still image from decoder"; } + i.Close(); + av_frame_free(&frame); av_packet_free(&pkt); return output_frame; } -FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode, const int ÷r) +FramePtr FFmpegDecoder::RetrieveVideoInternal(const rational &timecode, const int ÷r) { - if (!open_) { - qWarning() << "Tried to retrieve video on a decoder that's still closed"; - return nullptr; - } - - if (stream()->type() != Stream::kVideo) { - return nullptr; - } - VideoStreamPtr vs = std::static_pointer_cast(stream()); + if (scale_divider_ != divider) { + FreeScaler(); + InitScaler(divider); + } + if (vs->video_type() == VideoStream::kVideoTypeStill || vs->video_type() == VideoStream::kVideoTypeImageSequence) { @@ -188,153 +164,39 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode, const int &divid } else { - FFmpegFramePool::ElementPtr return_frame = nullptr; - int64_t target_ts = vs->get_time_in_timebase_units(timecode); - FFmpegDecoderInstance* working_instance = nullptr; - int divided_width = VideoParams::GetScaledDimension(vs->width(), divider); int divided_height = VideoParams::GetScaledDimension(vs->height(), divider); - // Find instance - do { - QMutexLocker list_locker(&instance_map_lock_); + if (pool_.width() != divided_width || pool_.height() != divided_height) { + // Clear all instance queues + ClearFrameCache(); - const QList& instances = instance_map_.value(stream().get()); - - FFmpegFramePool* pool = frame_pool_map_.value({vs->width(), vs->height(), src_pix_fmt_}).pool; - - if (pool->width() != divided_width || pool->height() != divided_height) { - // Clear all instance queues - foreach (FFmpegDecoderInstance* i, instances) { - i->ClearFrameCache(); - } - - // Set new frame pool parameters - pool->SetParameters(divided_width, divided_height, src_pix_fmt_); - } - - QList non_ideal_contenders; - - foreach (FFmpegDecoderInstance* i, instances) { - - i->cache_lock()->lock(); - - if (i->CacheContainsTime(target_ts)) { - - // Found our instance, allow others to enter the list - - list_locker.unlock(); - - // Get the frame from this cache - return_frame = i->GetFrameFromCache(target_ts); - - // Got our frame, allow cache to continue - i->cache_lock()->unlock(); - break; - - } else if (i->CacheWillContainTime(target_ts) || i->CacheCouldContainTime(target_ts)) { - - // Found our instance, allow others to enter the list - list_locker.unlock(); - - // If the instance is currently in use, enter into a loop of seeing from frames come up next in case one is ours - if (i->IsWorking()) { - - do { - // Allow instance to continue to the next frame - i->cache_wait_cond()->wait(i->cache_lock()); - - // See if the cache now contains this frame, if so we'll exit this loop - if (i->CacheContainsTime(target_ts)) { - - // Grab the frame - return_frame = i->GetFrameFromCache(target_ts); - - // We can release this worker now since we don't need it anymore - i->cache_lock()->unlock(); - - } else if (!i->IsWorking()) { - - // This instance finished and we didn't get our frame, we'll take it and continue it - working_instance = i; - break; - - } - } while (!return_frame); - - } else { - // Otherwise, we'll grab this instance and continue it ourselves - working_instance = i; - } - - break; - - } else if (i->IsWorking()) { - - // Ignore currently working instances - i->cache_lock()->unlock(); - - } else if (i->CacheIsEmpty()) { - - // Prioritize this cache over others (leaves this instance LOCKED in case we end up using it later) - non_ideal_contenders.prepend(i); - - } else { - - // De-prioritize this cache (leaves this instance LOCKED in case we end up using it later) - non_ideal_contenders.append(i); - - } - } - - // If we didn't find a suitable contender, grab the first non-suitable and roll with that - if (!return_frame && !working_instance && !non_ideal_contenders.isEmpty()) { - working_instance = non_ideal_contenders.takeFirst(); - } - - // For all instances we left locked but didn't end up using, lock them now - foreach (FFmpegDecoderInstance* unsuitable_instance, non_ideal_contenders) { - unsuitable_instance->cache_lock()->unlock(); - } - } while (!return_frame && !working_instance); - - if (!return_frame && working_instance) { - - // This instance SHOULD remain locked from our earlier loop, making this operation safe - working_instance->SetWorking(true); - - // Retrieve frame - return_frame = working_instance->RetrieveFrame(target_ts, divider, true); - - // Set working to false and wake any threads waiting - working_instance->cache_lock()->lock(); - working_instance->SetWorking(false); - working_instance->cache_wait_cond()->wakeAll(); - working_instance->cache_lock()->unlock(); + // Set new frame pool parameters + pool_.SetParameters(divided_width, divided_height, native_pix_fmt_, native_channel_count_); } + // Retrieve frame + FFmpegFramePool::ElementPtr return_frame = RetrieveFrame(target_ts, divider); + // We found the frame, we'll return a copy if (return_frame) { - // Align buffer to data/linesize points that can be passed to sws_scale - uint8_t* input_data[4]; - int input_linesize[4]; + FramePtr copy = Frame::Create(); + copy->set_video_params(VideoParams(vs->width(), + vs->height(), + native_pix_fmt_, + native_channel_count_, + std::static_pointer_cast(stream())->pixel_aspect_ratio(), + std::static_pointer_cast(stream())->interlacing(), + divider)); + copy->set_timestamp(timecode); + copy->allocate(); - av_image_fill_arrays(input_data, - input_linesize, - reinterpret_cast(return_frame->data()), - src_pix_fmt_, - divided_width, - divided_height, - 1); + // This data will already match the frame + memcpy(copy->data(), return_frame->data(), copy->allocated_size()); - return BuffersToNativeFrame(divider, - vs->width(), - vs->height(), - timecode, - input_data, - input_linesize); + return copy; } } @@ -342,97 +204,13 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode, const int &divid return nullptr; } -SampleBufferPtr FFmpegDecoder::RetrieveAudio(const rational &timecode, const rational &length, const AudioParams ¶ms) +void FFmpegDecoder::CloseInternal() { - if (!open_) { - qWarning() << "Tried to retrieve audio on a decoder that's still closed"; - return nullptr; - } + ClearFrameCache(); - if (stream()->type() != Stream::kAudio) { - return nullptr; - } + instance_.Close(); - QString wav_fn = GetConformedFilename(params); - WaveInput input(wav_fn); - - if (input.open()) { - const AudioParams& input_params = input.params(); - - // Read bytes from wav - QByteArray packed_data = input.read(input_params.time_to_bytes(timecode), input_params.time_to_bytes(length)); - input.close(); - - // Create sample buffer - SampleBufferPtr sample_buffer = SampleBuffer::CreateFromPackedData(input_params, packed_data); - - return sample_buffer; - } - - qCritical() << "Failed to open cached file" << wav_fn; - - return nullptr; -} - -void FFmpegDecoder::Close() -{ - if (stream() && StreamUsesMultipleInstances(stream())) { - // Clear whichever instance is not in use and is least useful (there are only ever as many instances as there are - // threads so if this thread is closing, an instance MUST be inactive) - QMutexLocker l(&instance_map_lock_); - - QList list = instance_map_.value(stream().get()); - - if (!list.isEmpty()) { - // Rank the instances by least useful (the top one should be one that isn't working and isn't in use) - QList least_useful; - - foreach (FFmpegDecoderInstance* i, list) { - i->cache_lock()->lock(); - - if (i->IsWorking()) { - // Don't bother any currently working instances - i->cache_lock()->unlock(); - continue; - } - - if (i->CacheIsEmpty()) { - least_useful.prepend(i); - } else { - least_useful.append(i); - } - } - - // Remove the least useful from the list and re-insert it into the map - FFmpegDecoderInstance* least_useful_instance = least_useful.first(); - list.removeOne(least_useful_instance); - instance_map_.insert(stream().get(), list); - - // If there are no more instances, destroy frame pool - VideoStreamPtr vs = std::static_pointer_cast(stream()); - FFmpegFramePoolKey frame_pool_key = {vs->width(), vs->height(), src_pix_fmt_}; - FFmpegFramePoolValue& frame_pool_info = frame_pool_map_[frame_pool_key]; - frame_pool_info.handles--; - - if (frame_pool_info.handles == 0) { - delete frame_pool_info.pool; - frame_pool_map_.remove(frame_pool_key); - } - - // We're done with the list now, we can unlock it and allow others to use it - l.unlock(); - - // Unlock all the instances we locked - foreach (FFmpegDecoderInstance* i, least_useful) { - i->cache_lock()->unlock(); - } - - // Delete this least useful instance now that we've definitely taken ownership of it - least_useful_instance->deleteLater(); - } - } - - ClearResources(); + FreeScaler(); } QString FFmpegDecoder::id() @@ -440,16 +218,6 @@ QString FFmpegDecoder::id() return QStringLiteral("ffmpeg"); } -bool FFmpegDecoder::SupportsVideo() -{ - return true; -} - -bool FFmpegDecoder::SupportsAudio() -{ - return true; -} - FootagePtr FFmpegDecoder::Probe(const QString& filename, const QAtomicInt* cancelled) const { // Variable for receiving errors from FFmpeg @@ -472,6 +240,8 @@ FootagePtr FFmpegDecoder::Probe(const QString& filename, const QAtomicInt* cance // Retrieve metadata about the media avformat_find_stream_info(fmt_ctx, nullptr); + int64_t footage_duration = fmt_ctx->duration; + QVector streams(fmt_ctx->nb_streams); // Dump it into the Footage object @@ -484,119 +254,150 @@ FootagePtr FFmpegDecoder::Probe(const QString& filename, const QAtomicInt* cance StreamPtr str; - if (avstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && decoder) { + if (decoder + && (avstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO + || avstream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)) { - bool image_is_still = false; - rational pixel_aspect_ratio; - rational frame_rate; - VideoParams::Interlacing interlacing = VideoParams::kInterlaceNone; + if (avstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - { - // Read at least two frames to get more information about this video stream - AVPacket* pkt = av_packet_alloc(); - AVFrame* frame = av_frame_alloc(); + bool image_is_still = false; + rational pixel_aspect_ratio; + rational frame_rate; + VideoParams::Interlacing interlacing = VideoParams::kInterlaceNone; { - FFmpegDecoderInstance instance(filename_c, i); + // Read at least two frames to get more information about this video stream + AVPacket* pkt = av_packet_alloc(); + AVFrame* frame = av_frame_alloc(); - // Read first frame and retrieve some metadata - if (instance.GetFrame(pkt, frame) >= 0) { - // Check if video is interlaced and what field dominance it has if so - if (frame->interlaced_frame) { - if (frame->top_field_first) { - interlacing = VideoParams::kInterlacedTopFirst; - } else { - interlacing = VideoParams::kInterlacedBottomFirst; + { + Instance instance; + instance.Open(filename.toUtf8(), avstream->index); + + // Read first frame and retrieve some metadata + if (instance.GetFrame(pkt, frame) >= 0) { + // Check if video is interlaced and what field dominance it has if so + if (frame->interlaced_frame) { + if (frame->top_field_first) { + interlacing = VideoParams::kInterlacedTopFirst; + } else { + interlacing = VideoParams::kInterlacedBottomFirst; + } } + + pixel_aspect_ratio = av_guess_sample_aspect_ratio(instance.fmt_ctx(), + instance.avstream(), + frame); + + frame_rate = av_guess_frame_rate(instance.fmt_ctx(), + instance.avstream(), + frame); } - pixel_aspect_ratio = av_guess_sample_aspect_ratio(instance.fmt_ctx(), - instance.stream(), - frame); + // Read second frame + int ret = instance.GetFrame(pkt, frame); - frame_rate = av_guess_frame_rate(instance.fmt_ctx(), - instance.stream(), - frame); + if (ret >= 0) { + // Check if we need a manual duration + if (avstream->duration == AV_NOPTS_VALUE) { + if (footage_duration == AV_NOPTS_VALUE) { + + // Manually read through file for duration + int64_t new_dur; + + do { + new_dur = frame->pts; + } while (instance.GetFrame(pkt, frame) >= 0); + + avstream->duration = new_dur; + + } else { + + // Fallback to footage duration + avstream->duration = Timecode::rescale_timestamp_ceil(footage_duration, rational(1, AV_TIME_BASE), avstream->time_base); + + } + } + } else if (ret == AVERROR_EOF) { + // Video has only one frame in it, treat it like a still image + image_is_still = true; + } + + instance.Close(); } - // Read second frame - int ret = instance.GetFrame(pkt, frame); + av_frame_free(&frame); + av_packet_free(&pkt); + } - if (ret >= 0) { - // Check if we need a manual duration - if (avstream->duration == AV_NOPTS_VALUE) { - int64_t new_dur; + VideoStreamPtr video_stream = std::make_shared(); - do { - new_dur = frame->pts; - } while (instance.GetFrame(pkt, frame) >= 0); + if (image_is_still) { + video_stream->set_video_type(VideoStream::kVideoTypeStill); + } else { + video_stream->set_video_type(VideoStream::kVideoTypeVideo); + + video_stream->set_frame_rate(frame_rate); + video_stream->set_start_time(avstream->start_time); + } + + video_stream->set_width(avstream->codecpar->width); + video_stream->set_height(avstream->codecpar->height); + video_stream->set_interlacing(interlacing); + video_stream->set_pixel_aspect_ratio(pixel_aspect_ratio); + + AVPixelFormat compatible_pix_fmt = FFmpegUtils::GetCompatiblePixelFormat(static_cast(avstream->codecpar->format)); + video_stream->set_format(GetNativePixelFormat(compatible_pix_fmt)); + video_stream->set_channel_count(GetNativeChannelCount(compatible_pix_fmt)); + + str = video_stream; + + } else { + + // Create an audio stream object + AudioStreamPtr audio_stream = std::make_shared(); + + uint64_t channel_layout = avstream->codecpar->channel_layout; + if (!channel_layout) { + channel_layout = static_cast(av_get_default_channel_layout(avstream->codecpar->channels)); + } + + audio_stream->set_channel_layout(channel_layout); + audio_stream->set_channels(avstream->codecpar->channels); + audio_stream->set_sample_rate(avstream->codecpar->sample_rate); + + if (avstream->duration == AV_NOPTS_VALUE) { + // Loop through stream until we get the whole duration + if (footage_duration == AV_NOPTS_VALUE) { + Instance instance; + instance.Open(filename.toUtf8(), avstream->index); + + AVPacket* pkt = av_packet_alloc(); + AVFrame* frame = av_frame_alloc(); + + int64_t new_dur; + + do { + new_dur = frame->pts; + } while (instance.GetFrame(pkt, frame) >= 0); + + avstream->duration = new_dur; + + av_frame_free(&frame); + av_packet_free(&pkt); + + instance.Close(); + } else { + + avstream->duration = Timecode::rescale_timestamp_ceil(footage_duration, rational(1, AV_TIME_BASE), avstream->time_base); - avstream->duration = new_dur; - } - } else if (ret == AVERROR_EOF) { - // Video has only one frame in it, treat it like a still image - image_is_still = true; } } - av_frame_free(&frame); - av_packet_free(&pkt); + str = audio_stream; + } - VideoStreamPtr video_stream = std::make_shared(); - - if (image_is_still) { - video_stream->set_video_type(VideoStream::kVideoTypeStill); - } else { - video_stream->set_video_type(VideoStream::kVideoTypeVideo); - - video_stream->set_frame_rate(frame_rate); - video_stream->set_start_time(avstream->start_time); - } - - video_stream->set_width(avstream->codecpar->width); - video_stream->set_height(avstream->codecpar->height); - video_stream->set_format(GetNativePixelFormat(FFmpegCommon::GetCompatiblePixelFormat(static_cast(avstream->codecpar->format)))); - video_stream->set_interlacing(interlacing); - video_stream->set_pixel_aspect_ratio(pixel_aspect_ratio); - - str = video_stream; - - } else if (avstream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && decoder) { - - // Create an audio stream object - AudioStreamPtr audio_stream = std::make_shared(); - - uint64_t channel_layout = avstream->codecpar->channel_layout; - if (!channel_layout) { - channel_layout = static_cast(av_get_default_channel_layout(avstream->codecpar->channels)); - } - - audio_stream->set_channel_layout(channel_layout); - audio_stream->set_channels(avstream->codecpar->channels); - audio_stream->set_sample_rate(avstream->codecpar->sample_rate); - - if (avstream->duration == AV_NOPTS_VALUE) { - // Loop through stream until we get the whole duration - FFmpegDecoderInstance instance(filename_c, i); - - AVPacket* pkt = av_packet_alloc(); - AVFrame* frame = av_frame_alloc(); - - int64_t new_dur; - - do { - new_dur = frame->pts; - } while (instance.GetFrame(pkt, frame) >= 0); - - avstream->duration = new_dur; - - av_frame_free(&frame); - av_packet_free(&pkt); - } - - str = audio_stream; - } else { // This is data we can't utilize at the moment, but we make a Stream object anyway to keep parity with the file @@ -658,50 +459,23 @@ FootagePtr FFmpegDecoder::Probe(const QString& filename, const QAtomicInt* cance return footage; } -void FFmpegDecoder::FFmpegError(int error_code) +QString FFmpegDecoder::FFmpegError(int error_code) { char err[1024]; av_strerror(error_code, err, 1024); - - Error(QStringLiteral("Error decoding %1 - %2 %3").arg(stream()->footage()->filename(), - QString::number(error_code), - err)); + return QStringLiteral("%1 %2").arg(QString::number(error_code), err); } -void FFmpegDecoder::Error(const QString &s) -{ - qWarning() << s; - - ClearResources(); -} - -bool FFmpegDecoder::ConformAudio(const QAtomicInt *cancelled, const AudioParams &p) +bool FFmpegDecoder::ConformAudioInternal(const QString &filename, const AudioParams ¶ms, const QAtomicInt *cancelled) { // Iterate through each audio frame and extract the PCM data AudioStreamPtr audio_stream = std::static_pointer_cast(stream()); - // Check if we already have a conform of this type - QString conformed_fn = GetConformedFilename(p); - - if (QFileInfo::exists(conformed_fn)) { - - // If we have one, and we can open it correctly, we can use it as-is - WaveInput input(conformed_fn); - if (input.open()) { - audio_stream->append_conformed_version(p); - - input.close(); - - return true; - } - } - - // Conform doesn't exist, we'll have to produce one - FFmpegDecoderInstance index_instance(stream()->footage()->filename().toUtf8(), - stream()->index()); + // Seek to starting point + instance_.Seek(0); // Handle NULL channel layout - uint64_t channel_layout = ValidateChannelLayout(index_instance.stream()); + uint64_t channel_layout = ValidateChannelLayout(instance_.avstream()); if (!channel_layout) { qCritical() << "Failed to determine channel layout of audio file, could not conform"; return false; @@ -709,18 +483,18 @@ bool FFmpegDecoder::ConformAudio(const QAtomicInt *cancelled, const AudioParams // Create resampling context SwrContext* resampler = swr_alloc_set_opts(nullptr, - p.channel_layout(), - FFmpegCommon::GetFFmpegSampleFormat(p.format()), - p.sample_rate(), + params.channel_layout(), + FFmpegUtils::GetFFmpegSampleFormat(params.format()), + params.sample_rate(), channel_layout, - static_cast(index_instance.stream()->codecpar->format), - index_instance.stream()->codecpar->sample_rate, + static_cast(instance_.avstream()->codecpar->format), + instance_.avstream()->codecpar->sample_rate, 0, nullptr); swr_init(resampler); - WaveOutput wave_out(conformed_fn, p); + WaveOutput wave_out(filename, params); AVPacket* pkt = av_packet_alloc(); AVFrame* frame = av_frame_alloc(); @@ -735,7 +509,7 @@ bool FFmpegDecoder::ConformAudio(const QAtomicInt *cancelled, const AudioParams break; } - ret = index_instance.GetFrame(pkt, frame); + ret = instance_.GetFrame(pkt, frame); if (ret < 0) { @@ -752,7 +526,7 @@ bool FFmpegDecoder::ConformAudio(const QAtomicInt *cancelled, const AudioParams // Allocate buffers int nb_samples = swr_get_out_samples(resampler, frame->nb_samples); - char* data = new char[p.samples_to_bytes(nb_samples)]; + char* data = new char[params.samples_to_bytes(nb_samples)]; // Resample audio to our destination parameters nb_samples = swr_convert(resampler, @@ -769,7 +543,7 @@ bool FFmpegDecoder::ConformAudio(const QAtomicInt *cancelled, const AudioParams } // Write packed WAV data to the disk cache - wave_out.write(data, p.samples_to_bytes(nb_samples)); + wave_out.write(data, params.samples_to_bytes(nb_samples)); // If we allocated an output for the resampler, delete it here if (data != reinterpret_cast(frame->data[0])) { @@ -780,18 +554,6 @@ bool FFmpegDecoder::ConformAudio(const QAtomicInt *cancelled, const AudioParams } wave_out.close(); - - if (success) { - - // If our conform succeeded, add it - audio_stream->append_conformed_version(p); - - } else { - - // Audio index didn't complete, delete it - QFile(conformed_fn).remove(); - - } } else { qWarning() << "Failed to open WAVE output for indexing"; } @@ -804,19 +566,31 @@ bool FFmpegDecoder::ConformAudio(const QAtomicInt *cancelled, const AudioParams return success; } -PixelFormat::Format FFmpegDecoder::GetNativePixelFormat(AVPixelFormat pix_fmt) +VideoParams::Format FFmpegDecoder::GetNativePixelFormat(AVPixelFormat pix_fmt) { switch (pix_fmt) { case AV_PIX_FMT_RGB24: - return PixelFormat::PIX_FMT_RGB8; case AV_PIX_FMT_RGBA: - return PixelFormat::PIX_FMT_RGBA8; + return VideoParams::kFormatUnsigned8; case AV_PIX_FMT_RGB48: - return PixelFormat::PIX_FMT_RGB16U; case AV_PIX_FMT_RGBA64: - return PixelFormat::PIX_FMT_RGBA16U; + return VideoParams::kFormatUnsigned16; default: - return PixelFormat::PIX_FMT_INVALID; + return VideoParams::kFormatInvalid; + } +} + +int FFmpegDecoder::GetNativeChannelCount(AVPixelFormat pix_fmt) +{ + switch (pix_fmt) { + case AV_PIX_FMT_RGB24: + case AV_PIX_FMT_RGB48: + return VideoParams::kRGBChannelCount; + case AV_PIX_FMT_RGBA: + case AV_PIX_FMT_RGBA64: + return VideoParams::kRGBAChannelCount; + default: + return 0; } } @@ -829,116 +603,15 @@ uint64_t FFmpegDecoder::ValidateChannelLayout(AVStream* stream) return av_get_default_channel_layout(stream->codecpar->channels); } -bool FFmpegDecoder::StreamUsesMultipleInstances(StreamPtr stream) +void FFmpegDecoder::FFmpegBufferToNativeBuffer(uint8_t **input_data, int *input_linesize, uint8_t** output_buffer, int* output_linesize) { - return stream->type() == Stream::kVideo - && std::static_pointer_cast(stream)->video_type() != VideoStream::kVideoTypeStill; -} - -FramePtr FFmpegDecoder::BuffersToNativeFrame(int divider, int width, int height, const rational& ts, uint8_t** input_data, int* input_linesize) -{ - if (divider != scale_divider_) { - FreeScaler(); - InitScaler(divider); - } - - // Create frame to return - FramePtr copy = Frame::Create(); - copy->set_video_params(VideoParams(width, - height, - native_pix_fmt_, - std::static_pointer_cast(stream())->pixel_aspect_ratio(), - std::static_pointer_cast(stream())->interlacing(), - divider)); - copy->set_timestamp(ts); - copy->allocate(); - - // Convert frame to RGB/A for the rest of the pipeline - uint8_t* output_data = reinterpret_cast(copy->data()); - int output_linesize = copy->linesize_bytes(); - sws_scale(scale_ctx_, input_data, input_linesize, 0, - VideoParams::GetScaledDimension(height, divider), - &output_data, - &output_linesize); - - return copy; -} - -int FFmpegDecoderInstance::GetFrame(AVPacket *pkt, AVFrame *frame) -{ - bool eof = false; - - int ret; - - // Clear any previous frames - av_frame_unref(frame); - - while ((ret = avcodec_receive_frame(codec_ctx_, frame)) == AVERROR(EAGAIN) && !eof) { - - // Find next packet in the correct stream index - do { - // Free buffer in packet if there is one - av_packet_unref(pkt); - - // Read packet from file - ret = av_read_frame(fmt_ctx_, pkt); - } while (pkt->stream_index != avstream_->index && ret >= 0); - - if (ret == AVERROR_EOF) { - // Don't break so that receive gets called again, but don't try to read again - eof = true; - - // Send a null packet to signal end of - avcodec_send_packet(codec_ctx_, nullptr); - } else if (ret < 0) { - // Handle other error by breaking loop and returning the code we received - break; - } else { - // Successful read, send the packet - ret = avcodec_send_packet(codec_ctx_, pkt); - - // We don't need the packet anymore, so free it - av_packet_unref(pkt); - - if (ret < 0) { - break; - } - } - } - - return ret; -} - -QMutex *FFmpegDecoderInstance::cache_lock() -{ - return &cache_lock_; -} - -QWaitCondition *FFmpegDecoderInstance::cache_wait_cond() -{ - return &cache_wait_cond_; -} - -bool FFmpegDecoderInstance::IsWorking() -{ - QMutexLocker locker(&is_working_mutex_); - return is_working_; -} - -void FFmpegDecoderInstance::SetWorking(bool working) -{ - QMutexLocker locker(&is_working_mutex_); - is_working_ = working; -} - -void FFmpegDecoderInstance::Seek(int64_t timestamp) -{ - avcodec_flush_buffers(codec_ctx_); - av_seek_frame(fmt_ctx_, avstream_->index, timestamp, AVSEEK_FLAG_BACKWARD); + instance_.avstream()->codecpar->height, + output_buffer, + output_linesize); } /* OLD UNUSED CODE: Keeping this around in case the code proves useful @@ -998,63 +671,51 @@ void FFmpegDecoder::CacheFrameToDisk(AVFrame *f) } */ -void FFmpegDecoderInstance::ClearFrameCache() +void FFmpegDecoder::ClearFrameCache() { cached_frames_.clear(); cache_at_eof_ = false; cache_at_zero_ = false; } -FFmpegFramePool::ElementPtr FFmpegDecoderInstance::RetrieveFrame(const int64_t& target_ts, int divider, bool cache_is_locked) +FFmpegFramePool::ElementPtr FFmpegDecoder::RetrieveFrame(const int64_t& target_ts, int divider) { - if (!cache_is_locked) { - cache_lock_.lock(); - } - - if (scale_divider_ != divider) { - FreeScaler(); - InitScaler(divider); - } - int64_t seek_ts = target_ts; bool still_seeking = false; - // CacheCouldContainTime uses cache_target_time_, so we'll temporarily set it to the last frame's TS - if (!cached_frames_.isEmpty()) { - cache_target_time_ = cached_frames_.last()->timestamp(); - } - // If the frame wasn't in the frame cache, see if this frame cache is too old to use - if (!CacheCouldContainTime(target_ts)) { + if (cached_frames_.isEmpty() + || (target_ts < cached_frames_.first()->timestamp() || target_ts > cached_frames_.last()->timestamp() + 2*second_ts_)) { ClearFrameCache(); - Seek(seek_ts); + instance_.Seek(seek_ts); if (seek_ts == 0) { cache_at_zero_ = true; } still_seeking = true; + } else { + // Search cache for frame + FFmpegFramePool::ElementPtr cached_frame = GetFrameFromCache(target_ts); + if (cached_frame) { + return cached_frame; + } } - cache_target_time_ = target_ts; - int ret; AVPacket* pkt = av_packet_alloc(); FFmpegFramePool::ElementPtr return_frame = nullptr; // Allocate a new frame - AVFrameWrapper working_frame; - - bool unlocked = false; + AVFrame* working_frame = av_frame_alloc(); while (true) { // Pull from the decoder - ret = GetFrame(pkt, working_frame.frame()); + ret = instance_.GetFrame(pkt, working_frame); // Handle any errors that aren't EOF (EOF is handled later on) if (ret < 0 && ret != AVERROR_EOF) { - cache_lock_.unlock(); qCritical() << "Failed to retrieve frame:" << ret; break; } @@ -1062,10 +723,10 @@ FFmpegFramePool::ElementPtr FFmpegDecoderInstance::RetrieveFrame(const int64_t& if (still_seeking) { // Handle a failure to seek (occurs on some media) // We'll only be here if the frame cache was emptied earlier - if (!cache_at_zero_ && (ret == AVERROR_EOF || working_frame.frame()->pts > target_ts)) { + if (!cache_at_zero_ && (ret == AVERROR_EOF || working_frame->pts > target_ts)) { seek_ts = qMax(static_cast(0), seek_ts - second_ts_); - Seek(seek_ts); + instance_.Seek(seek_ts); if (seek_ts == 0) { cache_at_zero_ = true; } @@ -1078,11 +739,6 @@ FFmpegFramePool::ElementPtr FFmpegDecoderInstance::RetrieveFrame(const int64_t& } } - if (cache_is_locked) { - cache_is_locked = false; - } else if (unlocked) { - cache_lock_.lock(); - } if (ret == AVERROR_EOF) { @@ -1095,53 +751,29 @@ FFmpegFramePool::ElementPtr FFmpegDecoderInstance::RetrieveFrame(const int64_t& return_frame = cached_frames_.last(); } - cache_wait_cond_.wakeAll(); - cache_lock_.unlock(); break; } else { - // Whatever it is, keep this frame in memory for the time being just in case - if (!frame_pool_) { - qCritical() << "Cannot retrieve video without a valid frame pool"; - cache_lock_.unlock(); - break; + // Cut down to thread count - 1 before we acquire a new frame + if (cached_frames_.size() == QThread::idealThreadCount()) { + RemoveFirstFrame(); } - // Cut down to thread count - 1 before we acquire a new frame - TruncateCacheRangeToFrames(QThread::idealThreadCount() -1); - - FFmpegFramePool::ElementPtr cached = frame_pool_->Get(); + FFmpegFramePool::ElementPtr cached = pool_.Get(); if (!cached) { qCritical() << "Frame pool failed to return a valid frame - out of memory?"; - cache_lock_.unlock(); break; } - { - uint8_t* scale_data[4]; - int scale_linesize[4]; - - av_image_fill_arrays(scale_data, - scale_linesize, - cached->data(), - static_cast(working_frame.frame()->format), - VideoParams::GetScaledDimension(working_frame.frame()->width, divider), - VideoParams::GetScaledDimension(working_frame.frame()->height, divider), - 1); - - sws_scale(scale_ctx_, - working_frame.frame()->data, - working_frame.frame()->linesize, - 0, - working_frame.frame()->height, - scale_data, - scale_linesize); - } + // Store in queue, converting to native format + uint8_t* destination_data = cached->data(); + int destination_linesize = Frame::generate_linesize_bytes(VideoParams::GetScaledDimension(instance_.avstream()->codecpar->width, divider), native_pix_fmt_, native_channel_count_); + FFmpegBufferToNativeBuffer(working_frame->data, working_frame->linesize, &destination_data, &destination_linesize); // Set timestamp so this frame can be identified later - cached->set_timestamp(working_frame.frame()->pts); + cached->set_timestamp(working_frame->pts); // Store frame before just in case FFmpegFramePool::ElementPtr previous; @@ -1154,10 +786,6 @@ FFmpegFramePool::ElementPtr FFmpegDecoderInstance::RetrieveFrame(const int64_t& // Append this frame and signal to other threads that a new frame has arrived cached_frames_.append(cached); - cache_wait_cond_.wakeAll(); - cache_lock_.unlock(); - unlocked = true; - // If this is a valid frame, see if this or the frame before it are the one we need if (cached->timestamp() == target_ts) { return_frame = cached; @@ -1174,18 +802,12 @@ FFmpegFramePool::ElementPtr FFmpegDecoderInstance::RetrieveFrame(const int64_t& } } + av_frame_free(&working_frame); av_packet_free(&pkt); return return_frame; } -void FFmpegDecoder::ClearResources() -{ - FreeScaler(); - - open_ = false; -} - void FFmpegDecoder::InitScaler(int divider) { VideoStream* vs = static_cast(stream().get()); @@ -1193,9 +815,9 @@ void FFmpegDecoder::InitScaler(int divider) int scaled_width = VideoParams::GetScaledDimension(vs->width(), divider); int scaled_height = VideoParams::GetScaledDimension(vs->height(), divider); - scale_ctx_ = sws_getContext(scaled_width, - scaled_height, - src_pix_fmt_, + scale_ctx_ = sws_getContext(vs->width(), + vs->height(), + static_cast(instance_.avstream()->codecpar->format), scaled_width, scaled_height, ideal_pix_fmt_, @@ -1221,40 +843,7 @@ void FFmpegDecoder::FreeScaler() } } -void FFmpegDecoderInstance::InitScaler(int divider) -{ - int scaled_width = VideoParams::GetScaledDimension(avstream_->codecpar->width, divider); - int scaled_height = VideoParams::GetScaledDimension(avstream_->codecpar->height, divider); - - scale_ctx_ = sws_getContext(avstream_->codecpar->width, - avstream_->codecpar->height, - static_cast(avstream_->codecpar->format), - scaled_width, - scaled_height, - static_cast(avstream_->codecpar->format), - SWS_FAST_BILINEAR, - nullptr, - nullptr, - nullptr); - - if (scale_ctx_) { - scale_divider_ = divider; - } else { - scale_divider_ = 0; - } -} - -void FFmpegDecoderInstance::FreeScaler() -{ - if (scale_ctx_) { - sws_freeContext(scale_ctx_); - scale_ctx_ = nullptr; - - scale_divider_ = 0; - } -} - -int64_t FFmpegDecoderInstance::RangeStart() const +/*int64_t FFmpegDecoder::RangeStart() const { if (cached_frames_.isEmpty()) { return AV_NOPTS_VALUE; @@ -1262,7 +851,7 @@ int64_t FFmpegDecoderInstance::RangeStart() const return cached_frames_.first()->timestamp(); } -int64_t FFmpegDecoderInstance::RangeEnd() const +int64_t FFmpegDecoder::RangeEnd() const { if (cached_frames_.isEmpty()) { return AV_NOPTS_VALUE; @@ -1270,7 +859,7 @@ int64_t FFmpegDecoderInstance::RangeEnd() const return cached_frames_.last()->timestamp(); } -bool FFmpegDecoderInstance::CacheContainsTime(const int64_t &t) const +bool FFmpegDecoder::CacheContainsTime(const int64_t &t) const { return !cached_frames_.isEmpty() && ((RangeStart() <= t && RangeEnd() >= t) @@ -1278,22 +867,22 @@ bool FFmpegDecoderInstance::CacheContainsTime(const int64_t &t) const || (cache_at_eof_ && t > cached_frames_.last()->timestamp())); } -bool FFmpegDecoderInstance::CacheWillContainTime(const int64_t &t) const +bool FFmpegDecoder::CacheWillContainTime(const int64_t &t) const { return !cached_frames_.isEmpty() && t >= cached_frames_.first()->timestamp() && t <= cache_target_time_; } -bool FFmpegDecoderInstance::CacheCouldContainTime(const int64_t &t) const +bool FFmpegDecoder::CacheCouldContainTime(const int64_t &t) const { return !cached_frames_.isEmpty() && t >= cached_frames_.first()->timestamp() && t <= (cache_target_time_ + 2*second_ts_); } -bool FFmpegDecoderInstance::CacheIsEmpty() const +bool FFmpegDecoder::CacheIsEmpty() const { return cached_frames_.isEmpty(); -} +}*/ -FFmpegFramePool::ElementPtr FFmpegDecoderInstance::GetFrameFromCache(const int64_t &t) const +FFmpegFramePool::ElementPtr FFmpegDecoder::GetFrameFromCache(const int64_t &t) const { if (t < cached_frames_.first()->timestamp()) { @@ -1328,17 +917,14 @@ FFmpegFramePool::ElementPtr FFmpegDecoderInstance::GetFrameFromCache(const int64 return nullptr; } -void FFmpegDecoderInstance::RemoveFramesBefore(const qint64 &t) +/*void FFmpegDecoder::RemoveFramesBefore(const qint64 &t) { - // We keep one frame in memory as an identifier for what pts the decoder is up to - int min_frames = (MemoryPoolLimitReached() && !IsWorking()) ? 0 : 1; - - while (cached_frames_.size() > min_frames && cached_frames_.first()->last_accessed() < t) { + while (!cached_frames_.isEmpty() && cached_frames_.first()->last_accessed() < t) { RemoveFirstFrame(); } } -int FFmpegDecoderInstance::TruncateCacheRangeToTime(const qint64 &t) +int FFmpegDecoder::TruncateCacheRangeToTime(const qint64 &t) { int counter = 0; @@ -1351,7 +937,7 @@ int FFmpegDecoderInstance::TruncateCacheRangeToTime(const qint64 &t) return counter; } -int FFmpegDecoderInstance::TruncateCacheRangeToFrames(int nb_frames) +int FFmpegDecoder::TruncateCacheRangeToFrames(int nb_frames) { int counter = 0; @@ -1362,34 +948,30 @@ int FFmpegDecoderInstance::TruncateCacheRangeToFrames(int nb_frames) } return counter; -} +}*/ -void FFmpegDecoderInstance::RemoveFirstFrame() +void FFmpegDecoder::RemoveFirstFrame() { cached_frames_.removeFirst(); cache_at_zero_ = false; } -FFmpegDecoderInstance::FFmpegDecoderInstance(const char *filename, int stream_index) : +FFmpegDecoder::Instance::Instance() : fmt_ctx_(nullptr), codec_ctx_(nullptr), - opts_(nullptr), - scale_ctx_(nullptr), - scale_divider_(0), - frame_pool_(nullptr), - is_working_(false), - cache_at_zero_(false), - cache_at_eof_(false), - clear_timer_(nullptr) + opts_(nullptr) +{ +} + +bool FFmpegDecoder::Instance::Open(const char *filename, int stream_index) { // Open file in a format context int error_code = avformat_open_input(&fmt_ctx_, filename, nullptr, nullptr); // Handle format context error if (error_code != 0) { - qCritical() << "Failed to open input:" << filename << error_code; - ClearResources(); - return; + qCritical() << "Failed to open input:" << filename << FFmpegError(error_code); + return false; } // Get stream information from format @@ -1397,9 +979,8 @@ FFmpegDecoderInstance::FFmpegDecoderInstance(const char *filename, int stream_in // Handle get stream information error if (error_code < 0) { - qCritical() << "Failed to find stream info:" << error_code; - ClearResources(); - return; + qCritical() << "Failed to find stream info:" << FFmpegError(error_code); + return false; } // Get reference to correct AVStream @@ -1410,17 +991,18 @@ FFmpegDecoderInstance::FFmpegDecoderInstance(const char *filename, int stream_in // Handle failure to find decoder if (codec == nullptr) { - qCritical() << "Failed to find appropriate decoder for this codec:" << filename << stream_index << avstream_->codecpar->codec_id; - ClearResources(); - return; + qCritical() << "Failed to find appropriate decoder for this codec:" + << filename + << stream_index + << avstream_->codecpar->codec_id; + return false; } // Allocate context for the decoder codec_ctx_ = avcodec_alloc_context3(codec); if (codec_ctx_ == nullptr) { qCritical() << "Failed to allocate codec context"; - ClearResources(); - return; + return false; } // Copy parameters from the AVStream to the AVCodecContext @@ -1429,8 +1011,7 @@ FFmpegDecoderInstance::FFmpegDecoderInstance(const char *filename, int stream_in // Handle failure to copy parameters if (error_code < 0) { qCritical() << "Failed to copy parameters from AVStream to AVCodecContext"; - ClearResources(); - return; + return false; } // Set multithreading setting @@ -1447,50 +1028,14 @@ FFmpegDecoderInstance::FFmpegDecoderInstance(const char *filename, int stream_in char buf[50]; av_strerror(error_code, buf, 50); qCritical() << "Failed to open codec" << codec->id << error_code << buf; - ClearResources(); - return; + return false; } - // Create frame pool - if (avstream_->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - // Start clear timer - clear_timer_ = new QTimer(); - clear_timer_->setInterval(kMaxFrameLife); - clear_timer_->moveToThread(qApp->thread()); - connect(clear_timer_, &QTimer::timeout, this, &FFmpegDecoderInstance::ClearTimerEvent, Qt::DirectConnection); - QMetaObject::invokeMethod(clear_timer_, "start", Qt::QueuedConnection); - } - - // Store one second in the source's timebase - second_ts_ = qRound64(av_q2d(av_inv_q(avstream_->time_base))); + return true; } -FFmpegDecoderInstance::~FFmpegDecoderInstance() +void FFmpegDecoder::Instance::Close() { - ClearResources(); -} - -bool FFmpegDecoderInstance::IsValid() const -{ - return codec_ctx_; -} - -void FFmpegDecoderInstance::SetFramePool(FFmpegFramePool *frame_pool) -{ - frame_pool_ = frame_pool; -} - -void FFmpegDecoderInstance::ClearResources() -{ - ClearFrameCache(); - - // Stop timer - if (clear_timer_) { - QMetaObject::invokeMethod(clear_timer_, "stop", Qt::QueuedConnection); - clear_timer_->deleteLater(); - clear_timer_ = nullptr; - } - if (opts_) { av_dict_free(&opts_); opts_ = nullptr; @@ -1505,20 +1050,57 @@ void FFmpegDecoderInstance::ClearResources() avformat_close_input(&fmt_ctx_); fmt_ctx_ = nullptr; } - - FreeScaler(); } -void FFmpegDecoderInstance::ClearTimerEvent() +int FFmpegDecoder::Instance::GetFrame(AVPacket *pkt, AVFrame *frame) { - cache_lock()->lock(); - RemoveFramesBefore(QDateTime::currentMSecsSinceEpoch() - kMaxFrameLife); - cache_lock()->unlock(); + bool eof = false; + + int ret; + + // Clear any previous frames + av_frame_unref(frame); + + while ((ret = avcodec_receive_frame(codec_ctx_, frame)) == AVERROR(EAGAIN) && !eof) { + + // Find next packet in the correct stream index + do { + // Free buffer in packet if there is one + av_packet_unref(pkt); + + // Read packet from file + ret = av_read_frame(fmt_ctx_, pkt); + } while (pkt->stream_index != avstream_->index && ret >= 0); + + if (ret == AVERROR_EOF) { + // Don't break so that receive gets called again, but don't try to read again + eof = true; + + // Send a null packet to signal end of + avcodec_send_packet(codec_ctx_, nullptr); + } else if (ret < 0) { + // Handle other error by breaking loop and returning the code we received + break; + } else { + // Successful read, send the packet + ret = avcodec_send_packet(codec_ctx_, pkt); + + // We don't need the packet anymore, so free it + av_packet_unref(pkt); + + if (ret < 0) { + break; + } + } + } + + return ret; } -uint qHash(const FFmpegDecoder::FFmpegFramePoolKey &r) +void FFmpegDecoder::Instance::Seek(int64_t timestamp) { - return ::qHash(r.width) ^ ::qHash(r.height) ^ ::qHash(r.format); + avcodec_flush_buffers(codec_ctx_); + av_seek_frame(fmt_ctx_, avstream_->index, timestamp, AVSEEK_FLAG_BACKWARD); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/codec/ffmpeg/ffmpegdecoder.h b/app/codec/ffmpeg/ffmpegdecoder.h index b2d91800f..6bbf80b1e 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.h +++ b/app/codec/ffmpeg/ffmpegdecoder.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -32,107 +32,12 @@ extern "C" { #include #include -#include "audio/sampleformat.h" -#include "avframeptr.h" #include "codec/decoder.h" #include "codec/waveoutput.h" #include "ffmpegframepool.h" #include "project/item/footage/videostream.h" -OLIVE_NAMESPACE_ENTER - -class FFmpegDecoderInstance : public QObject { - Q_OBJECT -public: - FFmpegDecoderInstance(const char* filename, int stream_index); - virtual ~FFmpegDecoderInstance(); - - DISABLE_COPY_MOVE(FFmpegDecoderInstance) - - bool IsValid() const; - - void SetFramePool(FFmpegFramePool* frame_pool); - - int64_t RangeStart() const; - int64_t RangeEnd() const; - bool CacheContainsTime(const int64_t& t) const; - bool CacheWillContainTime(const int64_t& t) const; - bool CacheCouldContainTime(const int64_t& t) const; - bool CacheIsEmpty() const; - FFmpegFramePool::ElementPtr GetFrameFromCache(const int64_t& t) const; - - void RemoveFramesBefore(const qint64& t); - int TruncateCacheRangeToTime(const qint64& t); - int TruncateCacheRangeToFrames(int nb_frames); - void RemoveFirstFrame(); - - AVFormatContext* fmt_ctx() const - { - return fmt_ctx_; - } - - AVStream* stream() const - { - return avstream_; - } - - void ClearFrameCache(); - - FFmpegFramePool::ElementPtr RetrieveFrame(const int64_t &target_ts, int divider, bool cache_is_locked); - - /** - * @brief Uses the FFmpeg API to retrieve a packet (stored in pkt_) and decode it (stored in frame_) - * - * @return - * - * An FFmpeg error code, or >= 0 on success - */ - int GetFrame(AVPacket* pkt, AVFrame* frame); - - QMutex* cache_lock(); - QWaitCondition* cache_wait_cond(); - - bool IsWorking(); - void SetWorking(bool working); - -private: - void ClearResources(); - - void Seek(int64_t timestamp); - - void InitScaler(int divider); - void FreeScaler(); - - AVFormatContext* fmt_ctx_; - AVCodecContext* codec_ctx_; - AVStream* avstream_; - AVDictionary* opts_; - - SwsContext* scale_ctx_; - int scale_divider_; - - int64_t second_ts_; - - QWaitCondition cache_wait_cond_; - QMutex cache_lock_; - QList cached_frames_; - FFmpegFramePool* frame_pool_; - - int64_t cache_target_time_; - - bool is_working_; - QMutex is_working_mutex_; - - bool cache_at_zero_; - bool cache_at_eof_; - - QTimer* clear_timer_; - static const int kMaxFrameLife; - -private slots: - void ClearTimerEvent(); - -}; +namespace olive { /** * @brief A Decoder derivative that wraps FFmpeg functions as on Olive decoder @@ -147,40 +52,62 @@ public: // Destructor virtual ~FFmpegDecoder() override; - virtual FootagePtr Probe(const QString& filename, const QAtomicInt* cancelled) const override; - - virtual bool Open() override; - virtual FramePtr RetrieveVideo(const rational &timecode, const int& divider) override; - virtual SampleBufferPtr RetrieveAudio(const rational &timecode, const rational &length, const AudioParams& params) override; - virtual void Close() override; - virtual QString id() override; - virtual bool SupportsVideo() override; - virtual bool SupportsAudio() override; + virtual bool SupportsVideo() override{return true;} + virtual bool SupportsAudio() override{return true;} - virtual bool ConformAudio(const QAtomicInt* cancelled, const AudioParams& p) override; + virtual FootagePtr Probe(const QString& filename, const QAtomicInt* cancelled) const override; - struct FFmpegFramePoolKey { - int width; - int height; - AVPixelFormat format; - - bool operator==(const FFmpegFramePoolKey& k) const - { - return width == k.width && height == k.height && format == k.format; - } - }; +protected: + virtual bool OpenInternal() override; + virtual FramePtr RetrieveVideoInternal(const rational &timecode, const int& divider) override; + virtual bool ConformAudioInternal(const QString& filename, const AudioParams ¶ms, const QAtomicInt* cancelled) override; + virtual void CloseInternal() override; private: - /** - * @brief Handle an error - * - * Immediately closes the Decoder (freeing memory resources) and sends the string provided to the warning stream. - * As this function closes the Decoder, no further Decoder functions should be performed after this is called - * (unless the Decoder is opened again first). - */ - void Error(const QString& s); + class Instance + { + public: + Instance(); + + ~Instance() + { + Close(); + } + + bool Open(const char* filename, int stream_index); + + void Close(); + + /** + * @brief Uses the FFmpeg API to retrieve a packet (stored in pkt_) and decode it (stored in frame_) + * + * @return + * + * An FFmpeg error code, or >= 0 on success + */ + int GetFrame(AVPacket* pkt, AVFrame* frame); + + void Seek(int64_t timestamp); + + AVFormatContext* fmt_ctx() const + { + return fmt_ctx_; + } + + AVStream* avstream() const + { + return avstream_; + } + + private: + AVFormatContext* fmt_ctx_; + AVCodecContext* codec_ctx_; + AVStream* avstream_; + AVDictionary* opts_; + + }; /** * @brief Handle an FFmpeg error code @@ -190,42 +117,50 @@ private: * * @param error_code */ - void FFmpegError(int error_code); - - void ClearResources(); + static QString FFmpegError(int error_code); void InitScaler(int divider); void FreeScaler(); FramePtr RetrieveStillImage(const rational& timecode, const int& divider); - static PixelFormat::Format GetNativePixelFormat(AVPixelFormat pix_fmt); + static VideoParams::Format GetNativePixelFormat(AVPixelFormat pix_fmt); + static int GetNativeChannelCount(AVPixelFormat pix_fmt); static uint64_t ValidateChannelLayout(AVStream *stream); - static bool StreamUsesMultipleInstances(StreamPtr stream); + void FFmpegBufferToNativeBuffer(uint8_t** input_data, int* input_linesize, uint8_t **output_buffer, int *output_linesize); - FramePtr BuffersToNativeFrame(int divider, int width, int height, const rational &ts, uint8_t **input_data, int* input_linesize); + FFmpegFramePool::ElementPtr GetFrameFromCache(const int64_t& t) const; + + void ClearFrameCache(); + + FFmpegFramePool::ElementPtr RetrieveFrame(const int64_t &target_ts, int divider); + + void RemoveFirstFrame(); SwsContext* scale_ctx_; int scale_divider_; - AVPixelFormat src_pix_fmt_; AVPixelFormat ideal_pix_fmt_; - PixelFormat::Format native_pix_fmt_; + VideoParams::Format native_pix_fmt_; + int native_channel_count_; - struct FFmpegFramePoolValue { - FFmpegFramePool* pool = nullptr; - int handles = 0; - }; + FFmpegFramePool pool_; - static QHash< Stream*, QList > instance_map_; - static QHash< FFmpegFramePoolKey, FFmpegFramePoolValue > frame_pool_map_; - static QMutex instance_map_lock_; + int64_t second_ts_; + + QList cached_frames_; + + bool is_working_; + QMutex is_working_mutex_; + + bool cache_at_zero_; + bool cache_at_eof_; + + Instance instance_; }; -uint qHash(const FFmpegDecoder::FFmpegFramePoolKey& r); - -OLIVE_NAMESPACE_EXIT +} #endif // FFMPEGDECODER_H diff --git a/app/codec/ffmpeg/ffmpegencoder.cpp b/app/codec/ffmpeg/ffmpegencoder.cpp index c31ac6b5a..7b28558e1 100644 --- a/app/codec/ffmpeg/ffmpegencoder.cpp +++ b/app/codec/ffmpeg/ffmpegencoder.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,17 +26,17 @@ extern "C" { #include -#include "ffmpegcommon.h" -#include "render/pixelformat.h" +#include "common/ffmpegutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { FFmpegEncoder::FFmpegEncoder(const EncodingParams ¶ms) : Encoder(params), fmt_ctx_(nullptr), video_stream_(nullptr), video_codec_ctx_(nullptr), - video_scale_ctx_(nullptr), + video_alpha_scale_ctx_(nullptr), + video_noalpha_scale_ctx_(nullptr), audio_stream_(nullptr), audio_codec_ctx_(nullptr), audio_resample_ctx_(nullptr), @@ -72,29 +72,49 @@ bool FFmpegEncoder::Open() } // This is the format we will expect frames received in Write() to be in - PixelFormat::Format native_pixel_fmt = params().video_params().format(); + VideoParams::Format native_pixel_fmt = params().video_params().format(); // This is the format we will need to convert the frame to for swscale to understand it - video_conversion_fmt_ = FFmpegCommon::GetCompatiblePixelFormat(native_pixel_fmt); + video_conversion_fmt_ = FFmpegUtils::GetCompatiblePixelFormat(native_pixel_fmt); // This is the equivalent pixel format above as an AVPixelFormat that swscale can understand - AVPixelFormat src_pix_fmt = FFmpegCommon::GetFFmpegPixelFormat(video_conversion_fmt_); + AVPixelFormat src_alpha_pix_fmt = FFmpegUtils::GetFFmpegPixelFormat(video_conversion_fmt_, + VideoParams::kRGBAChannelCount); + + AVPixelFormat src_noalpha_pix_fmt = FFmpegUtils::GetFFmpegPixelFormat(video_conversion_fmt_, + VideoParams::kRGBChannelCount); + + if (src_alpha_pix_fmt == AV_PIX_FMT_NONE || src_noalpha_pix_fmt == AV_PIX_FMT_NONE) { + Error(QStringLiteral("Failed to find suitable pixel format for this buffer")); + return false; + } // This is the pixel format the encoder wants to encode to AVPixelFormat encoder_pix_fmt = video_codec_ctx_->pix_fmt; // Set up a scaling context - if the native pixel format is not equal to the encoder's, we'll need to convert it // before encoding. Even if we don't, this may be useful for converting between linesizes, etc. - video_scale_ctx_ = sws_getContext(params().video_params().width(), - params().video_params().height(), - src_pix_fmt, - params().video_params().width(), - params().video_params().height(), - encoder_pix_fmt, - 0, - nullptr, - nullptr, - nullptr); + video_alpha_scale_ctx_ = sws_getContext(params().video_params().width(), + params().video_params().height(), + src_alpha_pix_fmt, + params().video_params().width(), + params().video_params().height(), + encoder_pix_fmt, + 0, + nullptr, + nullptr, + nullptr); + + video_noalpha_scale_ctx_ = sws_getContext(params().video_params().width(), + params().video_params().height(), + src_noalpha_pix_fmt, + params().video_params().width(), + params().video_params().height(), + encoder_pix_fmt, + 0, + nullptr, + nullptr, + nullptr); } // Initialize an audio stream if it's enabled @@ -157,19 +177,22 @@ bool FFmpegEncoder::WriteFrame(FramePtr frame, rational time) // We may need to convert this frame to a frame that swscale will understand if (frame->format() != video_conversion_fmt_) { - frame = PixelFormat::ConvertPixelFormat(frame, video_conversion_fmt_); + frame = frame->convert(video_conversion_fmt_); } // Use swscale context to convert formats/linesizes input_data = frame->const_data(); input_linesize = frame->linesize_bytes(); - error_code = sws_scale(video_scale_ctx_, + + error_code = sws_scale((frame->channel_count() == VideoParams::kRGBAChannelCount) ? video_alpha_scale_ctx_ : video_noalpha_scale_ctx_, reinterpret_cast(&input_data), &input_linesize, 0, frame->height(), encoded_frame->data, encoded_frame->linesize); + + if (error_code < 0) { FFmpegError("Failed to scale frame", error_code); goto fail; @@ -208,7 +231,7 @@ void FFmpegEncoder::WriteAudio(AudioParams pcm_info, QIODevice* file) audio_codec_ctx_->sample_fmt, audio_codec_ctx_->sample_rate, static_cast(pcm_info.channel_layout()), - FFmpegCommon::GetFFmpegSampleFormat(pcm_info.format()), + FFmpegUtils::GetFFmpegSampleFormat(pcm_info.format()), pcm_info.sample_rate(), 0, nullptr); @@ -300,9 +323,14 @@ void FFmpegEncoder::Close() open_ = false; } - if (video_scale_ctx_) { - sws_freeContext(video_scale_ctx_); - video_scale_ctx_ = nullptr; + if (video_alpha_scale_ctx_) { + sws_freeContext(video_alpha_scale_ctx_); + video_alpha_scale_ctx_ = nullptr; + } + + if (video_noalpha_scale_ctx_) { + sws_freeContext(video_noalpha_scale_ctx_); + video_noalpha_scale_ctx_ = nullptr; } if (video_codec_ctx_) { @@ -606,4 +634,4 @@ void FFmpegEncoder::Error(const QString &s) Close(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/codec/ffmpeg/ffmpegencoder.h b/app/codec/ffmpeg/ffmpegencoder.h index 4efc76754..75e5b25bd 100644 --- a/app/codec/ffmpeg/ffmpegencoder.h +++ b/app/codec/ffmpeg/ffmpegencoder.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ extern "C" { #include "codec/encoder.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class FFmpegEncoder : public Encoder { @@ -40,13 +40,18 @@ public: virtual bool Open() override; - virtual bool WriteFrame(OLIVE_NAMESPACE::FramePtr frame, OLIVE_NAMESPACE::rational time) override; + virtual bool WriteFrame(olive::FramePtr frame, olive::rational time) override; - virtual void WriteAudio(OLIVE_NAMESPACE::AudioParams pcm_info, + virtual void WriteAudio(olive::AudioParams pcm_info, QIODevice *file) override; virtual void Close() override; + virtual VideoParams::Format GetDesiredPixelFormat() const override + { + return video_conversion_fmt_; + } + private: /** * @brief Handle an error @@ -80,8 +85,9 @@ private: AVStream* video_stream_; AVCodecContext* video_codec_ctx_; - SwsContext* video_scale_ctx_; - PixelFormat::Format video_conversion_fmt_; + SwsContext* video_alpha_scale_ctx_; + SwsContext* video_noalpha_scale_ctx_; + VideoParams::Format video_conversion_fmt_; AVStream* audio_stream_; AVCodecContext* audio_codec_ctx_; @@ -91,6 +97,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // FFMPEGENCODER_H diff --git a/app/codec/ffmpeg/ffmpegframepool.cpp b/app/codec/ffmpeg/ffmpegframepool.cpp index cca05aed4..c4cfb3412 100644 --- a/app/codec/ffmpeg/ffmpegframepool.cpp +++ b/app/codec/ffmpeg/ffmpegframepool.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,42 +20,32 @@ #include "ffmpegframepool.h" -extern "C" { -#include -} +#include "codec/frame.h" -OLIVE_NAMESPACE_ENTER +namespace olive { FFmpegFramePool::FFmpegFramePool(int element_count) : MemoryPool(element_count), width_(0), height_(0), - format_(AV_PIX_FMT_NONE) + format_(VideoParams::kFormatInvalid), + channel_count_(0) { } -void FFmpegFramePool::SetParameters(int width, int height, AVPixelFormat format) +void FFmpegFramePool::SetParameters(int width, int height, VideoParams::Format format, int channel_count) { Clear(); width_ = width; height_ = height; format_ = format; + channel_count_ = channel_count; } size_t FFmpegFramePool::GetElementSize() { - int buf_sz = av_image_get_buffer_size(static_cast(format_), - width_, - height_, - 1); - - if (buf_sz < 0) { - qDebug() << "Failed to find buffer size:" << buf_sz; - return 0; - } - - return buf_sz; + return Frame::generate_linesize_bytes(width_, format_, channel_count_) * height_; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/codec/ffmpeg/ffmpegframepool.h b/app/codec/ffmpeg/ffmpegframepool.h index 81a31312e..cffe58ab6 100644 --- a/app/codec/ffmpeg/ffmpegframepool.h +++ b/app/codec/ffmpeg/ffmpegframepool.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,17 +22,16 @@ #define FFMPEGFRAMEPOOL_H #include "common/memorypool.h" -#include "render/pixelformat.h" #include "render/videoparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class FFmpegFramePool : public MemoryPool { public: FFmpegFramePool(int element_count); - void SetParameters(int width, int height, AVPixelFormat format); + void SetParameters(int width, int height, VideoParams::Format format, int channel_count); const int& width() const { @@ -52,10 +51,12 @@ private: int height_; - AVPixelFormat format_; + VideoParams::Format format_; + + int channel_count_; }; -OLIVE_NAMESPACE_EXIT +} #endif // FFMPEGFRAMEPOOL_H diff --git a/app/codec/frame.cpp b/app/codec/frame.cpp index 8cd0a53bd..5bcb6041c 100644 --- a/app/codec/frame.cpp +++ b/app/codec/frame.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,11 +20,14 @@ #include "frame.h" +#include #include #include #include -OLIVE_NAMESPACE_ENTER +#include "common/oiioutils.h" + +namespace olive { Frame::Frame() : timestamp_(0) @@ -45,33 +48,14 @@ void Frame::set_video_params(const VideoParams ¶ms) { params_ = params; - // Align linesize to 32 - linesize_ = qCeil(static_cast(width()) / 32.0) * 32; + linesize_ = generate_linesize_bytes(width(), params_.format(), params_.channel_count()); + linesize_pixels_ = linesize_ / params_.GetBytesPerPixel(); } -int Frame::linesize_pixels() const +int Frame::generate_linesize_bytes(int width, VideoParams::Format format, int channel_count) { - return linesize_; -} - -int Frame::linesize_bytes() const -{ - return linesize_pixels() * PixelFormat::BytesPerPixel(params_.format()); -} - -const int &Frame::width() const -{ - return params_.effective_width(); -} - -const int &Frame::height() const -{ - return params_.effective_height(); -} - -const PixelFormat::Format &Frame::format() const -{ - return params_.format(); + // Align to 32 bytes (not sure if this is necessary?) + return VideoParams::GetBytesPerPixel(format, channel_count) * ((width + 31) & ~31); } Color Frame::get_pixel(int x, int y) const @@ -80,11 +64,9 @@ Color Frame::get_pixel(int x, int y) const return Color(); } - int pixel_index = y * linesize_pixels() + x; + int byte_offset = y * linesize_bytes() + x * video_params().GetBytesPerPixel(); - int byte_offset = PixelFormat::GetBufferSize(video_params().format(), pixel_index, 1); - - return Color(data_.data() + byte_offset, video_params().format()); + return Color(data_.data() + byte_offset, video_params().format(), video_params().channel_count()); } bool Frame::contains_pixel(int x, int y) const @@ -98,57 +80,53 @@ void Frame::set_pixel(int x, int y, const Color &c) return; } - int pixel_index = y * linesize_pixels() + x; + int byte_offset = y * linesize_bytes() + x * video_params().GetBytesPerPixel(); - int byte_offset = PixelFormat::GetBufferSize(video_params().format(), pixel_index, 1); - - c.toData(data_.data() + byte_offset, video_params().format()); + c.toData(data_.data() + byte_offset, video_params().format(), video_params().channel_count()); } -const rational &Frame::timestamp() const -{ - return timestamp_; -} - -void Frame::set_timestamp(const rational ×tamp) -{ - timestamp_ = timestamp; -} - -char *Frame::data() -{ - return data_.data(); -} - -const char *Frame::const_data() const -{ - return data_.constData(); -} - -void Frame::allocate() +bool Frame::allocate() { // Assume this frame is intended to be a video frame if (!params_.is_valid()) { qWarning() << "Tried to allocate a frame with invalid parameters"; - return; + return false; } - data_.resize(PixelFormat::GetBufferSize(params_.format(), linesize_, params_.height())); + data_.resize(VideoParams::GetBufferSize(linesize_, height(), params_.format(), params_.channel_count())); + + return true; } -bool Frame::is_allocated() const +FramePtr Frame::convert(VideoParams::Format format) const { - return !data_.isEmpty(); + // Create new params with destination format + VideoParams params = params_; + params.set_format(format); + + // Create new frame + FramePtr converted = Frame::Create(); + converted->set_video_params(params); + converted->set_timestamp(timestamp_); + converted->allocate(); + + // Do the conversion through OIIO for convenience + OIIO::ImageBuf src(OIIO::ImageSpec(width(), height(), + channel_count(), + OIIOUtils::GetOIIOBaseTypeFromFormat(this->format()))); + + OIIOUtils::FrameToBuffer(this, &src); + + OIIO::ImageBuf dst(OIIO::ImageSpec(converted->width(), converted->height(), + channel_count(), + OIIOUtils::GetOIIOBaseTypeFromFormat(format))); + + if (dst.copy_pixels(src)) { + OIIOUtils::BufferToFrame(&dst, converted.get()); + return converted; + } else { + return nullptr; + } } -void Frame::destroy() -{ - data_.clear(); } - -int Frame::allocated_size() const -{ - return data_.size(); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/codec/frame.h b/app/codec/frame.h index 7618ad622..b9f7e3cb0 100644 --- a/app/codec/frame.h +++ b/app/codec/frame.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,10 +26,9 @@ #include "common/rational.h" #include "render/color.h" -#include "render/pixelformat.h" #include "render/videoparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Frame; using FramePtr = std::shared_ptr; @@ -47,11 +46,37 @@ public: const VideoParams& video_params() const; void set_video_params(const VideoParams& params); - int linesize_pixels() const; - int linesize_bytes() const; - const int& width() const; - const int& height() const; - const PixelFormat::Format& format() const; + static int generate_linesize_bytes(int width, VideoParams::Format format, int channel_count); + + int linesize_pixels() const + { + return linesize_pixels_; + } + + int linesize_bytes() const + { + return linesize_; + } + + int width() const + { + return params_.effective_width(); + } + + int height() const + { + return params_.effective_height(); + } + + VideoParams::Format format() const + { + return params_.format(); + } + + int channel_count() const + { + return params_.channel_count(); + } Color get_pixel(int x, int y) const; bool contains_pixel(int x, int y) const; @@ -62,18 +87,31 @@ public: * * This timestamp is always a rational that will equate to the time in seconds. */ - const rational& timestamp() const; - void set_timestamp(const rational& timestamp); + const rational& timestamp() const + { + return timestamp_; + } + + void set_timestamp(const rational& timestamp) + { + timestamp_ = timestamp; + } /** * @brief Get the data buffer of this frame */ - char* data(); + char* data() + { + return data_.data(); + } /** * @brief Get the const data buffer of this frame */ - const char* const_data() const; + const char* const_data() const + { + return data_.constData(); + } /** * @brief Allocate memory buffer to store data based on parameters @@ -82,24 +120,35 @@ public: * * If a memory buffer has been previously allocated without destroying, this function will destroy it. */ - void allocate(); + bool allocate(); /** * @brief Return whether the frame is allocated or not */ - bool is_allocated() const; + bool is_allocated() const + { + return !data_.isEmpty(); + } /** * @brief Destroy a memory buffer allocated with allocate() */ - void destroy(); + void destroy() + { + data_.clear(); + } /** * @brief Returns the size of the array returned in data() in bytes * * Returns 0 if nothing is allocated. */ - int allocated_size() const; + int allocated_size() const + { + return data_.size(); + } + + FramePtr convert(VideoParams::Format format) const; private: VideoParams params_; @@ -110,10 +159,12 @@ private: int linesize_; + int linesize_pixels_; + }; -OLIVE_NAMESPACE_EXIT +} -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::FramePtr) +Q_DECLARE_METATYPE(olive::FramePtr) #endif // FRAME_H diff --git a/app/codec/oiio/CMakeLists.txt b/app/codec/oiio/CMakeLists.txt index 19103a192..671e6a33e 100644 --- a/app/codec/oiio/CMakeLists.txt +++ b/app/codec/oiio/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -16,7 +16,7 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} - codec/oiio/oiiodecoder.h codec/oiio/oiiodecoder.cpp + codec/oiio/oiiodecoder.h PARENT_SCOPE ) diff --git a/app/codec/oiio/oiiodecoder.cpp b/app/codec/oiio/oiiodecoder.cpp index 4ddbf0ca5..f3fc5eb6c 100644 --- a/app/codec/oiio/oiiodecoder.cpp +++ b/app/codec/oiio/oiiodecoder.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,10 +27,11 @@ #include #include "common/define.h" +#include "common/oiioutils.h" #include "config/config.h" #include "core.h" -OLIVE_NAMESPACE_ENTER +namespace olive { QStringList OIIODecoder::supported_formats_; @@ -40,6 +41,11 @@ OIIODecoder::OIIODecoder() : { } +OIIODecoder::~OIIODecoder() +{ + CloseInternal(); +} + QString OIIODecoder::id() { return QStringLiteral("oiio"); @@ -47,6 +53,10 @@ QString OIIODecoder::id() FootagePtr OIIODecoder::Probe(const QString& filename, const QAtomicInt* cancelled) const { + Q_UNUSED(cancelled) + + // Filter out any file extensions that aren't expected to work - sometimes OIIO will crash trying + // to open a file that it can't if it's given one if (!FileTypeIsSupported(filename)) { return nullptr; } @@ -59,8 +69,9 @@ FootagePtr OIIODecoder::Probe(const QString& filename, const QAtomicInt* cancell return nullptr; } + // Filter out OIIO detecting an "FFmpeg movie", we have a native FFmpeg decoder that can handle + // it better if (!strcmp(in->format_name(), "FFmpeg movie")) { - // If this is FFmpeg via OIIO, fall-through to our native FFmpeg decoder return nullptr; } @@ -70,8 +81,9 @@ FootagePtr OIIODecoder::Probe(const QString& filename, const QAtomicInt* cancell image_stream->set_width(in->spec().width); image_stream->set_height(in->spec().height); - image_stream->set_format(GetFormatFromOIIOBasetype(in->spec())); - image_stream->set_pixel_aspect_ratio(GetPixelAspectRatioFromOIIO(in->spec())); + image_stream->set_format(OIIOUtils::GetFormatFromOIIOBasetype(static_cast(in->spec().format.basetype))); + image_stream->set_channel_count(in->spec().nchannels); + image_stream->set_pixel_aspect_ratio(OIIOUtils::GetPixelAspectRatioFromOIIO(in->spec())); image_stream->set_video_type(VideoStream::kVideoTypeStill); // Images will always have just one stream @@ -88,54 +100,47 @@ FootagePtr OIIODecoder::Probe(const QString& filename, const QAtomicInt* cancell // If we're here, we have a successful image open in->close(); -#if OIIO_VERSION < 10903 - OIIO::ImageInput::destroy(in); -#endif - return footage; } -bool OIIODecoder::Open() +bool OIIODecoder::OpenInternal() { - Q_ASSERT(stream()); + // If we can open the filename provided, assume everything is working (even if this is an image + // sequence with potentially missing frame) + if (OpenImageHandler(stream()->footage()->filename())) { + VideoStreamPtr video_stream = std::static_pointer_cast(stream()); - if (stream()->type() != Stream::kVideo) { - // Guard against non-video types - return false; + if (video_stream->video_type() == VideoStream::kVideoTypeStill) { + last_sequence_index_ = 0; + } else { + last_sequence_index_ = GetImageSequenceIndex(stream()->footage()->filename()); + } + + return true; } - - VideoStreamPtr video_stream = std::static_pointer_cast(stream()); - - if (video_stream->video_type() == VideoStream::kVideoTypeVideo) { - // This decoder only handles kVideoTypeImageSequence and kVideoTypeStill - return false; - } - - if (video_stream->video_type() == VideoStream::kVideoTypeStill - && !OpenImageHandler(stream()->footage()->filename())) { - return false; - } - - open_ = true; - - return true; + return false; } -FramePtr OIIODecoder::RetrieveVideo(const rational &timecode, const int& divider) +FramePtr OIIODecoder::RetrieveVideoInternal(const rational &timecode, const int& divider) { - if (!open_) { - qWarning() << "Tried to retrieve video on a decoder that's still closed"; - return nullptr; - } - VideoStreamPtr video_stream = std::static_pointer_cast(stream()); - if (video_stream->video_type() == VideoStream::kVideoTypeImageSequence) { - int64_t ts = video_stream->get_time_in_timebase_units(timecode); + int64_t sequence_index; - if (!OpenImageHandler(TransformImageSequenceFileName(stream()->footage()->filename(), ts))) { + if (video_stream->video_type() == VideoStream::kVideoTypeStill) { + sequence_index = 0; + } else { + sequence_index = video_stream->get_time_in_timebase_units(timecode); + } + + if (last_sequence_index_ != sequence_index) { + CloseImageHandle(); + + if (!OpenImageHandler(TransformImageSequenceFileName(stream()->footage()->filename(), sequence_index))) { return nullptr; } + + last_sequence_index_ = sequence_index; } FramePtr frame = Frame::Create(); @@ -143,14 +148,15 @@ FramePtr OIIODecoder::RetrieveVideo(const rational &timecode, const int& divider frame->set_video_params(VideoParams(buffer_->spec().width, buffer_->spec().height, pix_fmt_, - GetPixelAspectRatioFromOIIO(buffer_->spec()), + channel_count_, + OIIOUtils::GetPixelAspectRatioFromOIIO(buffer_->spec()), VideoParams::kInterlaceNone, // FIXME: Does OIIO deinterlace for us? divider)); frame->allocate(); if (divider == 1) { - BufferToFrame(buffer_, frame); + OIIOUtils::BufferToFrame(buffer_, frame.get()); } else { @@ -161,106 +167,18 @@ FramePtr OIIODecoder::RetrieveVideo(const rational &timecode, const int& divider qWarning() << "OIIO resize failed"; } - BufferToFrame(&dst, frame); + OIIOUtils::BufferToFrame(&dst, frame.get()); } - if (video_stream->video_type() == VideoStream::kVideoTypeImageSequence) { - CloseImageHandle(); - } - return frame; } -void OIIODecoder::Close() +void OIIODecoder::CloseInternal() { CloseImageHandle(); } -bool OIIODecoder::SupportsVideo() -{ - return true; -} - -void OIIODecoder::FrameToBuffer(FramePtr frame, OIIO::ImageBuf *buf) -{ -#if OIIO_VERSION < 20112 - // - // Workaround for OIIO bug that ignores destination stride in versions OLDER than 2.1.12 - // - // See more: https://github.com/OpenImageIO/oiio/pull/2487 - // - int width_in_bytes = frame->width() * PixelFormat::BytesPerPixel(frame->format()); - - for (int i=0;ispec().height;i++) { - memcpy( -#if OIIO_VERSION < 10903 - reinterpret_cast(buf->localpixels()) + i * width_in_bytes, -#else - reinterpret_cast(buf->localpixels()) + i * buf->scanline_stride(), -#endif - frame->data() + i * frame->linesize_bytes(), - width_in_bytes); - } -#else - buf->set_pixels(OIIO::ROI(), - buf->spec().format, - frame->data(), - OIIO::AutoStride, - frame->linesize_bytes()); -#endif -} - -void OIIODecoder::BufferToFrame(OIIO::ImageBuf *buf, FramePtr frame) -{ -#if OIIO_VERSION < 20112 - // - // Workaround for OIIO bug that ignores destination stride in versions OLDER than 2.1.12 - // - // See more: https://github.com/OpenImageIO/oiio/pull/2487 - // - int width_in_bytes = frame->width() * PixelFormat::BytesPerPixel(frame->format()); - - for (int i=0;ispec().height;i++) { - memcpy(frame->data() + i * frame->linesize_bytes(), -#if OIIO_VERSION < 10903 - reinterpret_cast(buf->localpixels()) + i * width_in_bytes, -#else - reinterpret_cast(buf->localpixels()) + i * buf->scanline_stride(), -#endif - width_in_bytes); - } -#else - buf->get_pixels(OIIO::ROI(), - buf->spec().format, - frame->data(), - OIIO::AutoStride, - frame->linesize_bytes()); -#endif -} - -PixelFormat::Format OIIODecoder::GetFormatFromOIIOBasetype(const OIIO::ImageSpec& spec) -{ - bool has_alpha = (spec.nchannels == kRGBAChannels); - - if (spec.format == OIIO::TypeDesc::UINT8) { - return has_alpha ? PixelFormat::PIX_FMT_RGBA8 : PixelFormat::PIX_FMT_RGB8; - } else if (spec.format == OIIO::TypeDesc::UINT16) { - return has_alpha ? PixelFormat::PIX_FMT_RGBA16U : PixelFormat::PIX_FMT_RGB16U; - } else if (spec.format == OIIO::TypeDesc::HALF) { - return has_alpha ? PixelFormat::PIX_FMT_RGBA16F : PixelFormat::PIX_FMT_RGB16F; - } else if (spec.format == OIIO::TypeDesc::FLOAT) { - return has_alpha ? PixelFormat::PIX_FMT_RGBA32F : PixelFormat::PIX_FMT_RGB32F; - } else { - return PixelFormat::PIX_FMT_INVALID; - } -} - -rational OIIODecoder::GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec &spec) -{ - return rational::fromDouble(spec.get_float_attribute("PixelAspectRatio", 1)); -} - bool OIIODecoder::FileTypeIsSupported(const QString& fn) { // We prioritize OIIO over FFmpeg to pick up still images more effectively, but some OIIO decoders (notably OpenJPEG) @@ -297,23 +215,27 @@ bool OIIODecoder::OpenImageHandler(const QString &fn) // Check if we can work with this pixel format const OIIO::ImageSpec& spec = image_->spec(); - is_rgba_ = (spec.nchannels == kRGBAChannels); + // Store channel count + channel_count_ = spec.nchannels; - pix_fmt_ = GetFormatFromOIIOBasetype(spec); + // We use RGBA frames because that tends to be the native format of GPUs + pix_fmt_ = OIIOUtils::GetFormatFromOIIOBasetype(static_cast(spec.format.basetype)); - if (pix_fmt_ == PixelFormat::PIX_FMT_INVALID) { + if (pix_fmt_ == VideoParams::kFormatInvalid) { qWarning() << "Failed to convert OIIO::ImageDesc to native pixel format"; return false; } - // FIXME: Many OIIO pixel formats are not handled here - OIIO::TypeDesc type = PixelFormat::GetOIIOTypeDesc(pix_fmt_); + OIIO::TypeDesc::BASETYPE type = OIIOUtils::GetOIIOBaseTypeFromFormat(pix_fmt_); + + if (type == OIIO::TypeDesc::UNKNOWN) { + qCritical() << "Failed to determine appropriate OIIO basetype from native format"; + return false; + } + + buffer_ = new OIIO::ImageBuf(OIIO::ImageSpec(spec.width, spec.height, spec.nchannels, type), + OIIO::InitializePixels::No); -#if OIIO_VERSION < 20100 - buffer_ = new OIIO::ImageBuf(OIIO::ImageSpec(spec.width, spec.height, spec.nchannels, type)); -#else - buffer_ = new OIIO::ImageBuf(OIIO::ImageSpec(spec.width, spec.height, spec.nchannels, type), OIIO::InitializePixels::No); -#endif image_->read_image(type, buffer_->localpixels()); return true; @@ -323,9 +245,6 @@ void OIIODecoder::CloseImageHandle() { if (image_) { image_->close(); -#if OIIO_VERSION < 10903 - OIIO::ImageInput::destroy(image_); -#endif image_ = nullptr; } @@ -335,4 +254,4 @@ void OIIODecoder::CloseImageHandle() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/codec/oiio/oiiodecoder.h b/app/codec/oiio/oiiodecoder.h index 11e7638ab..9b06df1d6 100644 --- a/app/codec/oiio/oiiodecoder.h +++ b/app/codec/oiio/oiiodecoder.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,9 +25,8 @@ #include #include "codec/decoder.h" -#include "render/pixelformat.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class OIIODecoder : public Decoder { @@ -35,30 +34,21 @@ class OIIODecoder : public Decoder public: OIIODecoder(); + virtual ~OIIODecoder() override; + virtual QString id() override; + virtual bool SupportsVideo() override{return true;} + virtual FootagePtr Probe(const QString& filename, const QAtomicInt* cancelled) const override; - virtual bool Open() override; - virtual FramePtr RetrieveVideo(const rational &timecode, const int& divider) override; - virtual void Close() override; - - virtual bool SupportsVideo() override; - - static void FrameToBuffer(FramePtr frame, OIIO::ImageBuf* buf); - - static void BufferToFrame(OIIO::ImageBuf* buf, FramePtr frame); - - static PixelFormat::Format GetFormatFromOIIOBasetype(const OIIO::ImageSpec& spec); - - static rational GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec& spec); +protected: + virtual bool OpenInternal() override; + virtual FramePtr RetrieveVideoInternal(const rational &timecode, const int& divider) override; + virtual void CloseInternal() override; private: -#if OIIO_VERSION < 10903 - OIIO::ImageInput* image_; -#else std::unique_ptr image_; -#endif static bool FileTypeIsSupported(const QString& fn); @@ -66,9 +56,11 @@ private: void CloseImageHandle(); - PixelFormat::Format pix_fmt_; + int64_t last_sequence_index_; - bool is_rgba_; + VideoParams::Format pix_fmt_; + + int channel_count_; OIIO::ImageBuf* buffer_; @@ -76,6 +68,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // OIIODECODER_H diff --git a/app/codec/samplebuffer.cpp b/app/codec/samplebuffer.cpp index fdd25b825..dc5f3ffb8 100644 --- a/app/codec/samplebuffer.cpp +++ b/app/codec/samplebuffer.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "samplebuffer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { SampleBuffer::SampleBuffer() : sample_count_per_channel_(0), @@ -38,6 +38,11 @@ SampleBufferPtr SampleBuffer::Create() return std::make_shared(); } +SampleBufferPtr SampleBuffer::CreateAllocated(const AudioParams &audio_params, const rational &length) +{ + return CreateAllocated(audio_params, audio_params.time_to_samples(length)); +} + SampleBufferPtr SampleBuffer::CreateAllocated(const AudioParams &audio_params, int samples_per_channel) { SampleBufferPtr buffer = Create(); @@ -305,4 +310,4 @@ void SampleBuffer::destroy_sample_buffer(float ***data, int nb_channels) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/codec/samplebuffer.h b/app/codec/samplebuffer.h index 891e9156d..984959788 100644 --- a/app/codec/samplebuffer.h +++ b/app/codec/samplebuffer.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "render/audioparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SampleBuffer; using SampleBufferPtr = std::shared_ptr; @@ -46,6 +46,7 @@ public: virtual ~SampleBuffer(); static SampleBufferPtr Create(); + static SampleBufferPtr CreateAllocated(const AudioParams& audio_params, const rational& length); static SampleBufferPtr CreateAllocated(const AudioParams& audio_params, int samples_per_channel); static SampleBufferPtr CreateFromPackedData(const AudioParams& audio_params, const QByteArray& bytes); @@ -93,8 +94,8 @@ private: }; -OLIVE_NAMESPACE_EXIT +} -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::SampleBufferPtr) +Q_DECLARE_METATYPE(olive::SampleBufferPtr) #endif // SAMPLEBUFFER_H diff --git a/app/codec/waveinput.cpp b/app/codec/waveinput.cpp index 275bea1f2..49de1eb59 100644 --- a/app/codec/waveinput.cpp +++ b/app/codec/waveinput.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ extern "C" { #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { WaveInput::WaveInput(const QString &f) : file_(f) @@ -108,27 +108,27 @@ bool WaveInput::open() uint16_t bits_per_sample; data_stream >> bits_per_sample; - SampleFormat::Format format; + AudioParams::Format format; switch (bits_per_sample) { case 8: - format = SampleFormat::SAMPLE_FMT_U8; + format = AudioParams::kFormatUnsigned8; break; case 16: - format = SampleFormat::SAMPLE_FMT_S16; + format = AudioParams::kFormatSigned16; break; case 32: if (data_is_float) { - format = SampleFormat::SAMPLE_FMT_FLT; + format = AudioParams::kFormatFloat32; } else { - format = SampleFormat::SAMPLE_FMT_S32; + format = AudioParams::kFormatSigned32; } break; case 64: if (data_is_float) { - format = SampleFormat::SAMPLE_FMT_DBL; + format = AudioParams::kFormatFloat64; } else { - format = SampleFormat::SAMPLE_FMT_S64; + format = AudioParams::kFormatSigned64; } break; default: @@ -239,4 +239,4 @@ qint64 WaveInput::calculate_max_read() const return data_size_ - (file_.pos() - data_position_ ); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/codec/waveinput.h b/app/codec/waveinput.h index 5aefead27..51131891e 100644 --- a/app/codec/waveinput.h +++ b/app/codec/waveinput.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "render/audioparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class WaveInput { @@ -70,6 +70,6 @@ private: quint32 data_size_; }; -OLIVE_NAMESPACE_EXIT +} #endif // WAVEINPUT_H diff --git a/app/codec/waveoutput.cpp b/app/codec/waveoutput.cpp index 844b3ad8f..b6b858957 100644 --- a/app/codec/waveoutput.cpp +++ b/app/codec/waveoutput.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,9 @@ #include "waveoutput.h" -OLIVE_NAMESPACE_ENTER +#include "render/audioparams.h" + +namespace olive { const int16_t kWAVIntegerFormat = 1; const int16_t kWAVFloatFormat = 3; @@ -60,18 +62,18 @@ bool WaveOutput::open() // Type of format switch (params_.format()) { - case SampleFormat::SAMPLE_FMT_U8: - case SampleFormat::SAMPLE_FMT_S16: - case SampleFormat::SAMPLE_FMT_S32: - case SampleFormat::SAMPLE_FMT_S64: + case AudioParams::kFormatUnsigned8: + case AudioParams::kFormatSigned16: + case AudioParams::kFormatSigned32: + case AudioParams::kFormatSigned64: write_int(&file_, kWAVIntegerFormat); break; - case SampleFormat::SAMPLE_FMT_FLT: - case SampleFormat::SAMPLE_FMT_DBL: + case AudioParams::kFormatFloat32: + case AudioParams::kFormatFloat64: write_int(&file_, kWAVFloatFormat); break; - case SampleFormat::SAMPLE_FMT_INVALID: - case SampleFormat::SAMPLE_FMT_COUNT: + case AudioParams::kFormatInvalid: + case AudioParams::kFormatCount: qWarning() << "Invalid sample format for WAVE audio"; file_.close(); return false; @@ -175,4 +177,4 @@ void WaveOutput::write_int(QFile *file, T integer) file->write(bytes); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/codec/waveoutput.h b/app/codec/waveoutput.h index a42f103e0..54ef72ed0 100644 --- a/app/codec/waveoutput.h +++ b/app/codec/waveoutput.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,10 +24,9 @@ #include #include -#include "audio/sampleformat.h" #include "render/audioparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class WaveOutput { @@ -64,6 +63,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // WAVEAUDIO_H diff --git a/app/common/CMakeLists.txt b/app/common/CMakeLists.txt index 5c2daad49..83880359c 100644 --- a/app/common/CMakeLists.txt +++ b/app/common/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -16,43 +16,50 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} - common/bezier.h common/bezier.cpp + common/bezier.h common/cancelableobject.h common/channellayout.h common/clamp.h - common/commandlineparser.h common/commandlineparser.cpp - common/crashpadinterface.h + common/commandlineparser.h common/crashpadinterface.cpp + common/crashpadinterface.h common/crashpadutils.h - common/debug.h common/debug.cpp + common/debug.h common/define.h - common/filefunctions.h + common/ffmpegutils.cpp + common/ffmpegutils.h common/filefunctions.cpp - common/flipmodifiers.h + common/filefunctions.h common/flipmodifiers.cpp + common/flipmodifiers.h common/functiontimer.h common/lerp.h - common/memorypool.h common/memorypool.cpp common/otioutils.h - common/qtutils.h + common/memorypool.h + common/ocioutils.cpp + common/ocioutils.h + common/oiioutils.cpp + common/oiioutils.h common/qtutils.cpp + common/qtutils.h common/range.h - common/ratiodialog.h common/ratiodialog.cpp + common/ratiodialog.h common/rational.h common/rational.cpp - common/threadedobject.h + common/threadsafemap.h common/threadedobject.cpp - common/timecodefunctions.h + common/threadedobject.h common/timecodefunctions.cpp - common/timerange.h + common/timecodefunctions.h common/timerange.cpp + common/timerange.h common/tohex.h - common/xmlutils.h common/xmlutils.cpp + common/xmlutils.h PARENT_SCOPE ) diff --git a/app/common/autoscroll.h b/app/common/autoscroll.h index b4e8e34ef..9d21a5df4 100644 --- a/app/common/autoscroll.h +++ b/app/common/autoscroll.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class AutoScroll { public: @@ -34,6 +34,6 @@ public: }; }; -OLIVE_NAMESPACE_EXIT +} #endif // AUTOSCROLL_H diff --git a/app/common/bezier.cpp b/app/common/bezier.cpp index 46d5b8e3e..9f59252e2 100644 --- a/app/common/bezier.cpp +++ b/app/common/bezier.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,9 @@ #include -OLIVE_NAMESPACE_ENTER +#include "common/clamp.h" + +namespace olive { double Bezier::QuadraticXtoT(double x, double a, double b, double c) { @@ -36,7 +38,10 @@ double Bezier::QuadraticTtoY(double a, double b, double c, double t) double Bezier::CubicXtoT(double x_target, double a, double b, double c, double d) { - double tolerance = 0.0001; + const double tolerance = 0.0001; + + // Clamp to prevent deadlocks + x_target = clamp(x_target, a, d); double lower = 0.0; double upper = 1.0; @@ -51,7 +56,7 @@ double Bezier::CubicXtoT(double x_target, double a, double b, double c, double d upper = percent; } - percent = (upper + lower) / 2.0; + percent = (upper + lower) * 0.5; x = CubicTtoY(a, b, c, d, percent); } @@ -63,4 +68,4 @@ double Bezier::CubicTtoY(double a, double b, double c, double d, double t) return qPow(1.0 - t, 3)*a + 3*qPow(1.0 - t, 2)*t*b + 3*(1.0 - t)*qPow(t, 2)*c + qPow(t, 3)*d; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/common/bezier.h b/app/common/bezier.h index b353fba95..55cb7dd0f 100644 --- a/app/common/bezier.h +++ b/app/common/bezier.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Bezier { @@ -37,6 +37,6 @@ public: static double CubicTtoY(double a, double b, double c, double d, double t); }; -OLIVE_NAMESPACE_EXIT +} #endif // BEZIER_H diff --git a/app/common/cancelableobject.h b/app/common/cancelableobject.h index 19364a521..25b42f143 100644 --- a/app/common/cancelableobject.h +++ b/app/common/cancelableobject.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class CancelableObject { public: @@ -34,19 +34,25 @@ public: { } - void Cancel() { + void Cancel() + { cancelled_ = true; + CancelEvent(); } - const QAtomicInt& IsCancelled() const { + const QAtomicInt& IsCancelled() const + { return cancelled_; } +protected: + virtual void CancelEvent(){} + private: QAtomicInt cancelled_; }; -OLIVE_NAMESPACE_EXIT +} #endif // CANCELABLEOBJECT_H diff --git a/app/common/channellayout.h b/app/common/channellayout.h index 0273925a4..bceace650 100644 --- a/app/common/channellayout.h +++ b/app/common/channellayout.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 diff --git a/app/common/clamp.h b/app/common/clamp.h index dda706505..636ecb7e6 100644 --- a/app/common/clamp.h +++ b/app/common/clamp.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 diff --git a/app/common/commandlineparser.cpp b/app/common/commandlineparser.cpp index 9585a0c69..7013276cd 100644 --- a/app/common/commandlineparser.cpp +++ b/app/common/commandlineparser.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -34,11 +34,11 @@ CommandLineParser::~CommandLineParser() } } -const CommandLineParser::Option *CommandLineParser::AddOption(const QStringList &strings, const QString &description) +const CommandLineParser::Option *CommandLineParser::AddOption(const QStringList &strings, const QString &description, bool takes_arg, const QString &arg_placeholder) { Option* o = new Option(); - options_.append({strings, description, o}); + options_.append({strings, description, o, takes_arg, arg_placeholder}); return o; } @@ -72,6 +72,12 @@ void CommandLineParser::Process(int argc, char **argv) if (!s.compare(arg_basename, Qt::CaseInsensitive)) { // Flag discovered! o.option->Set(); + + if (o.takes_arg && i+1 < argc) { + o.option->SetSetting(argv[i+1]); + i++; + } + matched_known = true; goto found_flag; } @@ -147,7 +153,11 @@ void CommandLineParser::PrintHelp(const char* filename) all_args.append(this_arg); } - printf(" %s\n", all_args.toUtf8().constData()); + if (o.arg_placeholder.isEmpty()) { + printf(" %s\n", all_args.toUtf8().constData()); + } else { + printf(" %s <%s>\n", all_args.toUtf8().constData(), o.arg_placeholder.toUtf8().constData()); + } printf(" %s\n\n", o.description.toUtf8().constData()); } diff --git a/app/common/commandlineparser.h b/app/common/commandlineparser.h index 10114d86a..5ae867c68 100644 --- a/app/common/commandlineparser.h +++ b/app/common/commandlineparser.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -33,7 +33,27 @@ public: DISABLE_COPY_MOVE(CommandLineParser) - class Option { + class PositionalArgument + { + public: + PositionalArgument() = default; + + const QString& GetSetting() const + { + return setting_; + } + + void SetSetting(const QString& s) + { + setting_ = s; + } + + private: + QString setting_; + + }; + + class Option : public PositionalArgument { public: Option() { @@ -55,29 +75,9 @@ public: }; - class PositionalArgument - { - public: - PositionalArgument() = default; - - const QString& GetSetting() const - { - return setting_; - } - - void SetSetting(const QString& s) - { - setting_ = s; - } - - private: - QString setting_; - - }; - CommandLineParser() = default; - const Option* AddOption(const QStringList& strings, const QString& description); + const Option* AddOption(const QStringList& strings, const QString& description, bool takes_arg = false, const QString& arg_placeholder = QString()); const PositionalArgument* AddPositionalArgument(const QString& name, const QString& description, bool required = false); @@ -90,6 +90,8 @@ private: QStringList args; QString description; Option* option; + bool takes_arg; + QString arg_placeholder; }; struct KnownPositionalArgument { diff --git a/app/common/crashpadinterface.cpp b/app/common/crashpadinterface.cpp index adc954e49..6014bd493 100644 --- a/app/common/crashpadinterface.cpp +++ b/app/common/crashpadinterface.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -40,7 +40,7 @@ crashpad::CrashpadClient *client; QString GenerateReportPath() { - return QDir(OLIVE_NAMESPACE::FileFunctions::GetTempFilePath()).filePath(QStringLiteral("reports")); + return QDir(olive::FileFunctions::GetTempFilePath()).filePath(QStringLiteral("reports")); } base::FilePath GenerateReportPathForCrashpad() @@ -90,7 +90,7 @@ bool InitializeCrashpad() base::FilePath reports_dir = GenerateReportPathForCrashpad(); - base::FilePath metrics_dir(QSTRING_TO_BASE_STRING(QDir(OLIVE_NAMESPACE::FileFunctions::GetTempFilePath()).filePath(QStringLiteral("metrics")))); + base::FilePath metrics_dir(QSTRING_TO_BASE_STRING(QDir(olive::FileFunctions::GetTempFilePath()).filePath(QStringLiteral("metrics")))); // Metadata that will be posted to the server with the crash report map std::map annotations; diff --git a/app/common/crashpadinterface.h b/app/common/crashpadinterface.h index 2388ece96..8e3a8181f 100644 --- a/app/common/crashpadinterface.h +++ b/app/common/crashpadinterface.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 diff --git a/app/common/crashpadutils.h b/app/common/crashpadutils.h index a2a36e49d..9b164939e 100644 --- a/app/common/crashpadutils.h +++ b/app/common/crashpadutils.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 diff --git a/app/common/debug.cpp b/app/common/debug.cpp index b2e79ab6e..195f74f4d 100644 --- a/app/common/debug.cpp +++ b/app/common/debug.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "debug.h" -OLIVE_NAMESPACE_ENTER +namespace olive { void DebugHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { @@ -54,4 +54,4 @@ void DebugHandler(QtMsgType type, const QMessageLogContext &context, const QStri #endif } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/common/debug.h b/app/common/debug.h index a916e1857..edb2aeb68 100644 --- a/app/common/debug.h +++ b/app/common/debug.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,10 +25,10 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { void DebugHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg); -OLIVE_NAMESPACE_EXIT +} #endif // DEBUG_H diff --git a/app/common/define.h b/app/common/define.h index aa968fcf7..6bc08b3a1 100644 --- a/app/common/define.h +++ b/app/common/define.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,17 +21,7 @@ #ifndef OLIVECOMMONDEFINE_H #define OLIVECOMMONDEFINE_H -#define OLIVE_NAMESPACE olive - -#define OLIVE_NAMESPACE_ENTER namespace OLIVE_NAMESPACE { - -#define OLIVE_NAMESPACE_EXIT } - -OLIVE_NAMESPACE_ENTER - -const int kHSVChannels = 3; -const int kRGBChannels = 3; -const int kRGBAChannels = 4; +namespace olive { /// The minimum size an icon in ProjectExplorer can be const int kProjectIconSizeMinimum = 16; @@ -44,14 +34,14 @@ const int kProjectIconSizeDefault = 64; const int kBytesInGigabyte = 1073741824; -OLIVE_NAMESPACE_EXIT +} #define MACRO_NAME_AS_STR(s) #s #define MACRO_VAL_AS_STR(s) MACRO_NAME_AS_STR(s) -#define OLIVE_NS_CONST_ARG(x, y) QArgument("const " MACRO_VAL_AS_STR(OLIVE_NAMESPACE) "::" #x, y) -#define OLIVE_NS_ARG(x, y) QArgument(MACRO_VAL_AS_STR(OLIVE_NAMESPACE) "::" #x, y) -#define OLIVE_NS_RETURN_ARG(x, y) QReturnArgument(MACRO_VAL_AS_STR(OLIVE_NAMESPACE) "::" #x, y) +#define OLIVE_NS_CONST_ARG(x, y) QArgument("const " MACRO_VAL_AS_STR(olive) "::" #x, y) +#define OLIVE_NS_ARG(x, y) QArgument(MACRO_VAL_AS_STR(olive) "::" #x, y) +#define OLIVE_NS_RETURN_ARG(x, y) QReturnArgument(MACRO_VAL_AS_STR(olive) "::" #x, y) /** * Copy/move deleters. Similar to Q_DISABLE_COPY_MOVE, et al. but those functions are not present in Qt < 5.13 so we diff --git a/app/common/ffmpegutils.cpp b/app/common/ffmpegutils.cpp new file mode 100644 index 000000000..46723e915 --- /dev/null +++ b/app/common/ffmpegutils.cpp @@ -0,0 +1,141 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 "common/ffmpegutils.h" + +namespace olive { + +AVPixelFormat FFmpegUtils::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt) +{ + AVPixelFormat possible_pix_fmts[] = { + AV_PIX_FMT_RGB24, + AV_PIX_FMT_RGBA, + AV_PIX_FMT_RGB48, + AV_PIX_FMT_RGBA64, + AV_PIX_FMT_NONE + }; + + return avcodec_find_best_pix_fmt_of_list(possible_pix_fmts, + pix_fmt, + 1, + nullptr); +} + +AudioParams::Format FFmpegUtils::GetNativeSampleFormat(const AVSampleFormat &smp_fmt) +{ + switch (smp_fmt) { + case AV_SAMPLE_FMT_U8: + return AudioParams::kFormatUnsigned8; + case AV_SAMPLE_FMT_S16: + return AudioParams::kFormatSigned16; + case AV_SAMPLE_FMT_S32: + return AudioParams::kFormatSigned32; + case AV_SAMPLE_FMT_S64: + return AudioParams::kFormatSigned64; + case AV_SAMPLE_FMT_FLT: + return AudioParams::kFormatFloat32; + case AV_SAMPLE_FMT_DBL: + return AudioParams::kFormatFloat64; + case AV_SAMPLE_FMT_U8P : + case AV_SAMPLE_FMT_S16P: + case AV_SAMPLE_FMT_S32P: + case AV_SAMPLE_FMT_S64P: + case AV_SAMPLE_FMT_FLTP: + case AV_SAMPLE_FMT_DBLP: + case AV_SAMPLE_FMT_NONE: + case AV_SAMPLE_FMT_NB: + break; + } + + return AudioParams::kFormatInvalid; +} + +AVSampleFormat FFmpegUtils::GetFFmpegSampleFormat(const AudioParams::Format &smp_fmt) +{ + switch (smp_fmt) { + case AudioParams::kFormatUnsigned8: + return AV_SAMPLE_FMT_U8; + case AudioParams::kFormatSigned16: + return AV_SAMPLE_FMT_S16; + case AudioParams::kFormatSigned32: + return AV_SAMPLE_FMT_S32; + case AudioParams::kFormatSigned64: + return AV_SAMPLE_FMT_S64; + case AudioParams::kFormatFloat32: + return AV_SAMPLE_FMT_FLT; + case AudioParams::kFormatFloat64: + return AV_SAMPLE_FMT_DBL; + case AudioParams::kFormatInvalid: + case AudioParams::kFormatCount: + break; + } + + return AV_SAMPLE_FMT_NONE; +} + +AVPixelFormat FFmpegUtils::GetFFmpegPixelFormat(const VideoParams::Format &pix_fmt, int channel_layout) +{ + if (channel_layout == VideoParams::kRGBChannelCount) { + switch (pix_fmt) { + case VideoParams::kFormatUnsigned8: + return AV_PIX_FMT_RGB24; + case VideoParams::kFormatUnsigned16: + return AV_PIX_FMT_RGB48; + case VideoParams::kFormatFloat16: + case VideoParams::kFormatFloat32: + case VideoParams::kFormatInvalid: + case VideoParams::kFormatCount: + break; + } + } else if (channel_layout == VideoParams::kRGBAChannelCount) { + switch (pix_fmt) { + case VideoParams::kFormatUnsigned8: + return AV_PIX_FMT_RGBA; + case VideoParams::kFormatUnsigned16: + return AV_PIX_FMT_RGBA64; + case VideoParams::kFormatFloat16: + case VideoParams::kFormatFloat32: + case VideoParams::kFormatInvalid: + case VideoParams::kFormatCount: + break; + } + } + + return AV_PIX_FMT_NONE; +} + +VideoParams::Format FFmpegUtils::GetCompatiblePixelFormat(const VideoParams::Format &pix_fmt) +{ + switch (pix_fmt) { + case VideoParams::kFormatUnsigned8: + return VideoParams::kFormatUnsigned8; + case VideoParams::kFormatUnsigned16: + case VideoParams::kFormatFloat16: + case VideoParams::kFormatFloat32: + return VideoParams::kFormatUnsigned16; + case VideoParams::kFormatInvalid: + case VideoParams::kFormatCount: + break; + } + + return VideoParams::kFormatInvalid; +} + +} diff --git a/app/codec/ffmpeg/ffmpegcommon.h b/app/common/ffmpegutils.h similarity index 74% rename from app/codec/ffmpeg/ffmpegcommon.h rename to app/common/ffmpegutils.h index 106452fad..e40cf1c6d 100644 --- a/app/codec/ffmpeg/ffmpegcommon.h +++ b/app/common/ffmpegutils.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,12 +25,12 @@ extern "C" { #include } -#include "audio/sampleformat.h" -#include "render/pixelformat.h" +#include "render/audioparams.h" +#include "render/videoparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -class FFmpegCommon { +class FFmpegUtils { public: /** * @brief Returns an AVPixelFormat that can be used to convert a frame to a data type Olive supports with minimal data loss @@ -40,24 +40,24 @@ public: /** * @brief Returns a native pixel format that can be used to convert from a native frame to an AVFrame with minimal data loss */ - static PixelFormat::Format GetCompatiblePixelFormat(const PixelFormat::Format& pix_fmt); + static VideoParams::Format GetCompatiblePixelFormat(const VideoParams::Format& pix_fmt); /** * @brief Returns an FFmpeg pixel format for a given native pixel format */ - static AVPixelFormat GetFFmpegPixelFormat(const PixelFormat::Format& pix_fmt); + static AVPixelFormat GetFFmpegPixelFormat(const VideoParams::Format& pix_fmt, int channel_layout); /** * @brief Returns a native sample format type for a given AVSampleFormat */ - static SampleFormat::Format GetNativeSampleFormat(const AVSampleFormat& smp_fmt); + static AudioParams::Format GetNativeSampleFormat(const AVSampleFormat& smp_fmt); /** * @brief Returns an FFmpeg sample format type for a given native type */ - static AVSampleFormat GetFFmpegSampleFormat(const SampleFormat::Format &smp_fmt); + static AVSampleFormat GetFFmpegSampleFormat(const AudioParams::Format &smp_fmt); }; -OLIVE_NAMESPACE_EXIT +} #endif // FFMPEGABSTRACTION_H diff --git a/app/common/filefunctions.cpp b/app/common/filefunctions.cpp index 23f3abf99..8314acb4c 100644 --- a/app/common/filefunctions.cpp +++ b/app/common/filefunctions.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,7 +29,7 @@ #include "config/config.h" -OLIVE_NAMESPACE_ENTER +namespace olive { QString FileFunctions::GetUniqueFileIdentifier(const QString &filename) { @@ -75,7 +75,7 @@ QString FileFunctions::GetTempFilePath() { QString temp_path = QDir(QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation)) .filePath(QCoreApplication::organizationName())) - .filePath(QCoreApplication::applicationName()); + .filePath(QCoreApplication::applicationName()); // Ensure it exists QDir(temp_path).mkpath("."); @@ -187,4 +187,57 @@ QString FileFunctions::EnsureFilenameExtension(QString fn, const QString &extens return fn; } -OLIVE_NAMESPACE_EXIT +QString FileFunctions::ReadFileAsString(const QString &filename) +{ + QFile f(filename); + QString file_data; + if (f.open(QFile::ReadOnly | QFile::Text)) { + QTextStream text_stream(&f); + file_data = text_stream.readAll(); + f.close(); + } + return file_data; +} + +QString FileFunctions::GetSafeTemporaryFilename(const QString &original) +{ + int counter = 0; + + QFileInfo original_info(original); + QString basename = original_info.baseName(); + QString complete_suffix = original_info.completeSuffix(); + + // If we have a complete suffix, make sure there's a period in it + if (!complete_suffix.isEmpty()) { + complete_suffix.prepend('.'); + } + + QString temp_abs_path; + do { + temp_abs_path = original_info.dir().filePath( + QStringLiteral("%1.tmp%2%3").arg(basename, + QString::number(counter), + complete_suffix)); + counter++; + } while (QFileInfo::exists(temp_abs_path)); + + return temp_abs_path; +} + +bool FileFunctions::RenameFileAllowOverwrite(const QString &from, const QString &to) +{ + if (QFileInfo::exists(to) && !QFile::remove(to)) { + qCritical() << "Couldn't remove existing file" << to << "for overwrite"; + return false; + } + + // By this point, we can assume `to` either never existed or has now been deleted + if (!QFile::rename(from, to)) { + qCritical() << "Failed to rename file" << from << "to" << to; + return false; + } + + return true; +} + +} diff --git a/app/common/filefunctions.h b/app/common/filefunctions.h index 87bcc6375..124d42b17 100644 --- a/app/common/filefunctions.h +++ b/app/common/filefunctions.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A collection of static file and directory functions @@ -65,10 +65,29 @@ public: */ static QString EnsureFilenameExtension(QString fn, const QString& extension); + static QString ReadFileAsString(const QString& filename); + + /** + * @brief Returns a temporary filename that can be used while writing rather than the original + * + * If overwriting a file, it's safest to write to a new file first and then only replace it at + * the end so that if the program crashes or the user cancels the save half way through, the + * original file is still intact. + * + * This function returns a slight variant of the filename provided that's guaranteed to not exist + * and therefore won't overwrite anything important. + */ + static QString GetSafeTemporaryFilename(const QString& original); + + /** + * @brief Renames a file from `from` to `to`, deleting `to` if such a file already exists first + */ + static bool RenameFileAllowOverwrite(const QString& from, const QString& to); + }; -OLIVE_NAMESPACE_EXIT +} #endif // FILEFUNCTIONS_H diff --git a/app/common/flipmodifiers.cpp b/app/common/flipmodifiers.cpp index d7314fd11..e126bae16 100644 --- a/app/common/flipmodifiers.cpp +++ b/app/common/flipmodifiers.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "flipmodifiers.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Qt::KeyboardModifiers FlipControlAndShiftModifiers(Qt::KeyboardModifiers e) { if (e & Qt::ControlModifier & Qt::ShiftModifier) { @@ -38,4 +38,4 @@ Qt::KeyboardModifiers FlipControlAndShiftModifiers(Qt::KeyboardModifiers e) { return e; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/common/flipmodifiers.h b/app/common/flipmodifiers.h index b34727327..010b13058 100644 --- a/app/common/flipmodifiers.h +++ b/app/common/flipmodifiers.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,10 +25,10 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Qt::KeyboardModifiers FlipControlAndShiftModifiers(Qt::KeyboardModifiers e); -OLIVE_NAMESPACE_EXIT +} #endif // FLIPMODIFIERS_H diff --git a/app/common/functiontimer.h b/app/common/functiontimer.h index 87735bd6e..678cccfab 100644 --- a/app/common/functiontimer.h +++ b/app/common/functiontimer.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 diff --git a/app/common/lerp.h b/app/common/lerp.h index da1f95b8a..e0aa166fa 100644 --- a/app/common/lerp.h +++ b/app/common/lerp.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 diff --git a/app/common/memorypool.cpp b/app/common/memorypool.cpp index f88ba8d46..31e987e73 100644 --- a/app/common/memorypool.cpp +++ b/app/common/memorypool.cpp @@ -1,6 +1,6 @@ #include "memorypool.h" -OLIVE_NAMESPACE_ENTER +namespace olive { size_t memory_pool_consumption = 0; QMutex memory_pool_consumption_lock; @@ -11,4 +11,4 @@ bool MemoryPoolLimitReached() return (memory_pool_consumption >= 2147483648); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/common/memorypool.h b/app/common/memorypool.h index d52d24b46..cc54db121 100644 --- a/app/common/memorypool.h +++ b/app/common/memorypool.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { extern size_t memory_pool_consumption; extern QMutex memory_pool_consumption_lock; @@ -397,6 +397,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // MEMORYPOOL_H diff --git a/app/codec/ffmpeg/avframeptr.h b/app/common/ocioutils.cpp similarity index 52% rename from app/codec/ffmpeg/avframeptr.h rename to app/common/ocioutils.cpp index 2e7716d52..4b7a8a306 100644 --- a/app/codec/ffmpeg/avframeptr.h +++ b/app/common/ocioutils.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -18,43 +18,30 @@ ***/ -#ifndef AVFRAMEPTR_H -#define AVFRAMEPTR_H +#include "ocioutils.h" -extern "C" { -#include +namespace olive { + +OCIO::BitDepth OCIOUtils::GetOCIOBitDepthFromPixelFormat(VideoParams::Format format) +{ + switch (format) { + case VideoParams::kFormatUnsigned8: + return OCIO::BIT_DEPTH_UINT8; + case VideoParams::kFormatUnsigned16: + return OCIO::BIT_DEPTH_UINT16; + break; + case VideoParams::kFormatFloat16: + return OCIO::BIT_DEPTH_F16; + break; + case VideoParams::kFormatFloat32: + return OCIO::BIT_DEPTH_F32; + break; + case VideoParams::kFormatInvalid: + case VideoParams::kFormatCount: + break; + } + + return OCIO::BIT_DEPTH_UNKNOWN; } -#include -#include - -#include "common/define.h" - -OLIVE_NAMESPACE_ENTER - -class AVFrameWrapper { -public: - AVFrameWrapper() { - frame_ = av_frame_alloc(); - } - - virtual ~AVFrameWrapper() { - av_frame_free(&frame_); - } - - DISABLE_COPY_MOVE(AVFrameWrapper) - - inline AVFrame* frame() const { - return frame_; - } - -private: - AVFrame* frame_; - -}; - -using AVFramePtr = std::shared_ptr; - -OLIVE_NAMESPACE_EXIT - -#endif // AVFRAMEPTR_H +} diff --git a/app/render/backend/opengl/openglbackend.cpp b/app/common/ocioutils.h similarity index 67% rename from app/render/backend/opengl/openglbackend.cpp rename to app/common/ocioutils.h index 60e81f914..ea906839f 100644 --- a/app/render/backend/opengl/openglbackend.cpp +++ b/app/common/ocioutils.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -18,26 +18,22 @@ ***/ -#include "openglbackend.h" +#ifndef OCIOUTILS_H +#define OCIOUTILS_H -#include "openglworker.h" +#include +namespace OCIO = OCIO_NAMESPACE; -OLIVE_NAMESPACE_ENTER +#include "render/videoparams.h" -OpenGLBackend::OpenGLBackend(QObject* parent) : - RenderBackend(parent) +namespace olive { + +class OCIOUtils { +public: + static OCIO::BitDepth GetOCIOBitDepthFromPixelFormat(VideoParams::Format format); +}; } -OpenGLBackend::~OpenGLBackend() -{ - Close(); -} - -RenderWorker *OpenGLBackend::CreateNewWorker() -{ - return new OpenGLWorker(this); -} - -OLIVE_NAMESPACE_EXIT +#endif // OCIOUTILS_H diff --git a/app/common/oiioutils.cpp b/app/common/oiioutils.cpp new file mode 100644 index 000000000..c2d3eb738 --- /dev/null +++ b/app/common/oiioutils.cpp @@ -0,0 +1,81 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 "oiioutils.h" + +namespace olive { + +void OIIOUtils::FrameToBuffer(const Frame* frame, OIIO::ImageBuf *buf) +{ + buf->set_pixels(OIIO::ROI(), + buf->spec().format, + frame->const_data(), + OIIO::AutoStride, + frame->linesize_bytes()); +} + +void OIIOUtils::BufferToFrame(OIIO::ImageBuf *buf, Frame* frame) +{ + buf->get_pixels(OIIO::ROI(), + buf->spec().format, + frame->data(), + OIIO::AutoStride, + frame->linesize_bytes()); +} + +rational OIIOUtils::GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec &spec) +{ + return rational::fromDouble(spec.get_float_attribute("PixelAspectRatio", 1)); +} + +VideoParams::Format OIIOUtils::GetFormatFromOIIOBasetype(OIIO::TypeDesc::BASETYPE type) +{ + switch (type) { + case OIIO::TypeDesc::UNKNOWN: + case OIIO::TypeDesc::NONE: + break; + + case OIIO::TypeDesc::INT8: + case OIIO::TypeDesc::INT16: + case OIIO::TypeDesc::INT32: + case OIIO::TypeDesc::UINT32: + case OIIO::TypeDesc::INT64: + case OIIO::TypeDesc::UINT64: + case OIIO::TypeDesc::STRING: + case OIIO::TypeDesc::PTR: + case OIIO::TypeDesc::LASTBASE: + case OIIO::TypeDesc::DOUBLE: + qDebug() << "Tried to use unknown OIIO base type"; + break; + + case OIIO::TypeDesc::UINT8: + return VideoParams::kFormatUnsigned8; + case OIIO::TypeDesc::UINT16: + return VideoParams::kFormatUnsigned16; + case OIIO::TypeDesc::HALF: + return VideoParams::kFormatFloat16; + case OIIO::TypeDesc::FLOAT: + return VideoParams::kFormatFloat32; + } + + return VideoParams::kFormatInvalid; +} + +} diff --git a/app/common/oiioutils.h b/app/common/oiioutils.h new file mode 100644 index 000000000..68677df8f --- /dev/null +++ b/app/common/oiioutils.h @@ -0,0 +1,65 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 OIIOUTILS_H +#define OIIOUTILS_H + +#include +#include + +#include "codec/frame.h" +#include "render/videoparams.h" + +namespace olive { + +class OIIOUtils { +public: + static OIIO::TypeDesc::BASETYPE GetOIIOBaseTypeFromFormat(VideoParams::Format format) + { + switch (format) { + case VideoParams::kFormatUnsigned8: + return OIIO::TypeDesc::UINT8; + case VideoParams::kFormatUnsigned16: + return OIIO::TypeDesc::UINT16; + case VideoParams::kFormatFloat16: + return OIIO::TypeDesc::HALF; + case VideoParams::kFormatFloat32: + return OIIO::TypeDesc::FLOAT; + case VideoParams::kFormatInvalid: + case VideoParams::kFormatCount: + break; + } + + return OIIO::TypeDesc::UNKNOWN; + } + + static void FrameToBuffer(const Frame *frame, OIIO::ImageBuf* buf); + + static void BufferToFrame(OIIO::ImageBuf* buf, Frame* frame); + + static VideoParams::Format GetFormatFromOIIOBasetype(OIIO::TypeDesc::BASETYPE type); + + static rational GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec& spec); + +}; + +} + +#endif // OIIOUTILS_H diff --git a/app/common/power.h b/app/common/power.h index 8e574b8c3..6ecebaf62 100644 --- a/app/common/power.h +++ b/app/common/power.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { uint32_t ceil_to_power_of_2(uint32_t v) { @@ -51,6 +51,6 @@ uint32_t floor_to_power_of_2(uint32_t x) return x - (x >> 1); } -OLIVE_NAMESPACE_EXIT +} #endif // POWER_H diff --git a/app/common/qtutils.cpp b/app/common/qtutils.cpp index a745d5443..225a7b7e3 100644 --- a/app/common/qtutils.cpp +++ b/app/common/qtutils.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,9 +20,9 @@ #include "qtutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -int QFontMetricsWidth(QFontMetrics fm, const QString& s) { +int QtUtils::QFontMetricsWidth(QFontMetrics fm, const QString& s) { #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) return fm.width(s); #else @@ -30,4 +30,12 @@ int QFontMetricsWidth(QFontMetrics fm, const QString& s) { #endif } -OLIVE_NAMESPACE_EXIT +QFrame *QtUtils::CreateHorizontalLine() +{ + QFrame* horizontal_line = new QFrame(); + horizontal_line->setFrameShape(QFrame::HLine); + horizontal_line->setFrameShadow(QFrame::Sunken); + return horizontal_line; +} + +} diff --git a/app/common/qtutils.h b/app/common/qtutils.h index fb405b6b7..d01ba1f03 100644 --- a/app/common/qtutils.h +++ b/app/common/qtutils.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,20 +28,27 @@ */ #include +#include #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -/** - * @brief Retrieves the width of a string according to certain QFontMetrics - * - * QFontMetrics::width() has been deprecatd in favor of QFontMetrics::horizontalAdvance(), but the - * latter was only introduced in 5.11+. This function wraps the latter for 5.11+ and the former for - * earlier. - */ -int QFontMetricsWidth(QFontMetrics fm, const QString& s); +class QtUtils { +public: + /** + * @brief Retrieves the width of a string according to certain QFontMetrics + * + * QFontMetrics::width() has been deprecatd in favor of QFontMetrics::horizontalAdvance(), but the + * latter was only introduced in 5.11+. This function wraps the latter for 5.11+ and the former for + * earlier. + */ + static int QFontMetricsWidth(QFontMetrics fm, const QString& s); -OLIVE_NAMESPACE_EXIT + static QFrame* CreateHorizontalLine(); + +}; + +} #endif // QTVERSIONABSTRACTION_H diff --git a/app/common/range.h b/app/common/range.h index 96de47c74..1f40d3b22 100644 --- a/app/common/range.h +++ b/app/common/range.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 diff --git a/app/common/ratiodialog.cpp b/app/common/ratiodialog.cpp index cb01147e3..20e64bc43 100644 --- a/app/common/ratiodialog.cpp +++ b/app/common/ratiodialog.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { double GetFloatRatioFromUser(QWidget* parent, const QString& title, @@ -88,4 +88,4 @@ double GetFloatRatioFromUser(QWidget* parent, } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/common/ratiodialog.h b/app/common/ratiodialog.h index 306e36d22..8d09b583b 100644 --- a/app/common/ratiodialog.h +++ b/app/common/ratiodialog.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,12 +25,12 @@ #include "common/rational.h" -OLIVE_NAMESPACE_ENTER +namespace olive { double GetFloatRatioFromUser(QWidget* parent, const QString& title, bool* ok_in); -OLIVE_NAMESPACE_EXIT +} #endif // RATIODIALOG_H diff --git a/app/common/rational.cpp b/app/common/rational.cpp index ff44bbd89..62c9af3e0 100644 --- a/app/common/rational.cpp +++ b/app/common/rational.cpp @@ -3,7 +3,7 @@ #include "rational.h" -OLIVE_NAMESPACE_ENTER +namespace olive { rational rational::fromDouble(const double &flt) { @@ -393,9 +393,9 @@ uint qHash(const rational &r, uint seed) return ::qHash(r.toDouble(), seed); } -OLIVE_NAMESPACE_EXIT +} -QDebug operator<<(QDebug debug, const OLIVE_NAMESPACE::rational &r) +QDebug operator<<(QDebug debug, const olive::rational &r) { return debug.space() << r.toDouble(); /* diff --git a/app/common/rational.h b/app/common/rational.h index 8074c9b07..2b1e60784 100644 --- a/app/common/rational.h +++ b/app/common/rational.h @@ -20,7 +20,7 @@ extern "C" { #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { typedef int64_t intType; /* @@ -141,10 +141,10 @@ private: uint qHash(const rational& r, uint seed); -OLIVE_NAMESPACE_EXIT +} -QDebug operator<<(QDebug debug, const OLIVE_NAMESPACE::rational& r); +QDebug operator<<(QDebug debug, const olive::rational& r); -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::rational) +Q_DECLARE_METATYPE(olive::rational) #endif // RATIONAL_H diff --git a/app/common/threadedobject.cpp b/app/common/threadedobject.cpp index 4f331c710..38efd7d8a 100644 --- a/app/common/threadedobject.cpp +++ b/app/common/threadedobject.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "threadedobject.h" -OLIVE_NAMESPACE_ENTER +namespace olive { void ThreadedObject::LockDeletes() { @@ -54,4 +54,4 @@ bool ThreadedObject::TryLockMutex(int timeout) return threadobj_main_lock_.tryLock(timeout); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/common/threadedobject.h b/app/common/threadedobject.h index 3210378fa..7340433b9 100644 --- a/app/common/threadedobject.h +++ b/app/common/threadedobject.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ThreadedObject { @@ -45,6 +45,6 @@ private: QAtomicInt threadobj_delete_lock_; }; -OLIVE_NAMESPACE_EXIT +} #endif // THREADEDOBJECT_H diff --git a/app/common/threadsafemap.h b/app/common/threadsafemap.h new file mode 100644 index 000000000..0d4a6bc7e --- /dev/null +++ b/app/common/threadsafemap.h @@ -0,0 +1,27 @@ +#ifndef THREADSAFEMAP_H +#define THREADSAFEMAP_H + +#include +#include + +template +class ThreadSafeMap +{ +public: + ThreadSafeMap() = default; + + void insert(K key, V value) + { + mutex_.lock(); + map_.insert(key, value); + mutex_.unlock(); + } + +private: + QMutex mutex_; + + QMap map_; + +}; + +#endif // THREADSAFEMAP_H diff --git a/app/common/timecodefunctions.cpp b/app/common/timecodefunctions.cpp index 952601832..613fe8aa9 100644 --- a/app/common/timecodefunctions.cpp +++ b/app/common/timecodefunctions.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "config/config.h" -OLIVE_NAMESPACE_ENTER +namespace olive { QString padded(int64_t arg, int padding) { return QStringLiteral("%1").arg(arg, padding, 10, QChar('0')); @@ -289,4 +289,4 @@ int64_t Timecode::rescale_timestamp_ceil(const int64_t &ts, const rational &sour return qCeil(static_cast(ts) * source.toDouble() / dest.toDouble()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/common/timecodefunctions.h b/app/common/timecodefunctions.h index afaa263f3..872b9f823 100644 --- a/app/common/timecodefunctions.h +++ b/app/common/timecodefunctions.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/rational.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief Functions for converting times/timecodes/timestamps @@ -72,6 +72,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMECODEFUNCTIONS_H diff --git a/app/common/timerange.cpp b/app/common/timerange.cpp index d8b2a5b6b..b71d3e6b4 100644 --- a/app/common/timerange.cpp +++ b/app/common/timerange.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,9 +20,10 @@ #include "timerange.h" +#include #include -OLIVE_NAMESPACE_ENTER +namespace olive { TimeRange::TimeRange(const rational &in, const rational &out) : in_(in), @@ -77,11 +78,11 @@ bool TimeRange::operator!=(const TimeRange &r) const bool TimeRange::OverlapsWith(const TimeRange &a, bool in_inclusive, bool out_inclusive) const { - bool overlaps_in = (in_inclusive) ? (a.out() < in()) : (a.out() <= in()); + bool doesnt_overlap_in = (in_inclusive) ? (a.out() < in()) : (a.out() <= in()); - bool overlaps_out = (out_inclusive) ? (a.in() > out()) : (a.in() >= out()); + bool doesnt_overlap_out = (out_inclusive) ? (a.in() > out()) : (a.in() >= out()); - return !(overlaps_in || overlaps_out); + return !doesnt_overlap_in && !doesnt_overlap_out; } TimeRange TimeRange::Combined(const TimeRange &a) const @@ -148,6 +149,21 @@ const TimeRange &TimeRange::operator-=(const rational &rhs) return *this; } +std::list TimeRange::Split(const int &chunk_size) const +{ + std::list split_ranges; + + int start_time = qFloor(this->in().toDouble() / static_cast(chunk_size)) * chunk_size; + int end_time = qCeil(this->out().toDouble() / static_cast(chunk_size)) * chunk_size; + + for (int i=start_time; iin(), rational(i)), + qMin(this->out(), rational(i + chunk_size)))); + } + + return split_ranges; +} + void TimeRange::normalize() { // If `out` is earlier than `in`, swap them @@ -160,43 +176,45 @@ void TimeRange::normalize() length_ = out_ - in_; } -void TimeRangeList::InsertTimeRange(TimeRange range_to_add) +void TimeRangeList::insert(TimeRange range_to_add) { // See if list contains this range - if (ContainsTimeRange(range_to_add)) { + if (contains(range_to_add)) { return; } // Does not contain range, so we'll almost certainly be adding it in some way for (int i=0;isize(); for (int i=0;iremoveAt(i); + array_.removeAt(i); i--; sz--; } else if (compare.Contains(remove, false, false)) { // The remove range is within this element, only choice is to split the element into two - this->append(TimeRange(remove.out(), compare.out())); + TimeRange new_range(remove.out(), compare.out()); compare.set_out(remove.in()); + insert(new_range); + break; } else if (compare.in() < remove.in() && compare.out() > remove.in()) { // This element's out point overlaps the range's in, we'll trim it compare.set_out(remove.in()); @@ -207,10 +225,10 @@ void TimeRangeList::RemoveTimeRange(const TimeRange &remove) } } -bool TimeRangeList::ContainsTimeRange(const TimeRange &range, bool in_inclusive, bool out_inclusive) const +bool TimeRangeList::contains(const TimeRange &range, bool in_inclusive, bool out_inclusive) const { for (int i=0;i= range.out()) { // No intersect @@ -233,31 +284,28 @@ TimeRangeList TimeRangeList::Intersects(const TimeRange &range) const TimeRange cropped(qMax(range.in(), compare.in()), qMin(range.out(), compare.out())); - intersect_list.append(cropped); + intersect_list.insert(cropped); } } return intersect_list; } -void TimeRangeList::PrintTimeList() -{ - qDebug() << "TimeRangeList now contains:"; - - for (int i=0;i Split(const int &chunk_size) const; + private: void normalize(); @@ -65,34 +67,83 @@ private: }; -class TimeRangeList : public QList { +class TimeRangeList { public: TimeRangeList() = default; TimeRangeList(std::initializer_list r) : - QList(r) + array_(r) { } - void InsertTimeRange(TimeRange range_to_add); + void insert(TimeRange range_to_add); - void RemoveTimeRange(const TimeRange& remove); + void remove(const TimeRange& remove); - bool ContainsTimeRange(const TimeRange& range, bool in_inclusive = true, bool out_inclusive = true) const; + bool contains(const TimeRange& range, bool in_inclusive = true, bool out_inclusive = true) const; + + bool isEmpty() const + { + return array_.isEmpty(); + } + + void clear() + { + array_.clear(); + } + + int size() const + { + return array_.size(); + } + + void shift(const rational& diff); + + void trim_in(const rational& diff); + + void trim_out(const rational& diff); TimeRangeList Intersects(const TimeRange& range) const; + using const_iterator = QVector::const_iterator; + + const_iterator begin() const + { + return array_.constBegin(); + } + + const_iterator end() const + { + return array_.constEnd(); + } + + const TimeRange& first() const + { + return array_.first(); + } + + const TimeRange& last() const + { + return array_.last(); + } + + const QVector& internal_array() const + { + return array_; + } + private: - void PrintTimeList(); + QVector array_; }; uint qHash(const TimeRange& r, uint seed); -OLIVE_NAMESPACE_EXIT +} -QDebug operator<<(QDebug debug, const OLIVE_NAMESPACE::TimeRange& r); +QDebug operator<<(QDebug debug, const olive::TimeRange& r); +QDebug operator<<(QDebug debug, const olive::TimeRangeList& r); -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::TimeRange) +Q_DECLARE_METATYPE(olive::TimeRange) #endif // TIMERANGE_H diff --git a/app/common/tohex.h b/app/common/tohex.h index 3843ebf84..0e7eff7dd 100644 --- a/app/common/tohex.h +++ b/app/common/tohex.h @@ -5,12 +5,12 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { inline QString ToHex(quint64 t) { return QStringLiteral("%1").arg(t, 0, 16); } -OLIVE_NAMESPACE_EXIT +} #endif // TOHEX_H diff --git a/app/common/xmlutils.cpp b/app/common/xmlutils.cpp index ed5f8f735..0ff66750a 100644 --- a/app/common/xmlutils.cpp +++ b/app/common/xmlutils.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "node/factory.h" #include "widget/nodeview/nodeviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { void XMLConnectNodes(const XMLNodeData &xml_node_data, QUndoCommand *command) { @@ -64,4 +64,4 @@ void XMLLinkBlocks(const XMLNodeData &xml_node_data) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/common/xmlutils.h b/app/common/xmlutils.h index 334508111..40a029732 100644 --- a/app/common/xmlutils.h +++ b/app/common/xmlutils.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "project/item/footage/stream.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Block; class Node; @@ -71,6 +71,6 @@ bool XMLReadNextStartElement(QXmlStreamReader* reader); void XMLLinkBlocks(const XMLNodeData& xml_node_data); -OLIVE_NAMESPACE_EXIT +} #endif // XMLREADLOOP_H diff --git a/app/config/CMakeLists.txt b/app/config/CMakeLists.txt index 755e1d3dd..a8b684886 100644 --- a/app/config/CMakeLists.txt +++ b/app/config/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/config/config.cpp b/app/config/config.cpp index f2db463d7..4efa8bc54 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -34,7 +34,7 @@ #include "ui/style/style.h" #include "window/mainwindow/mainwindow.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Config Config::current_config_; @@ -68,7 +68,7 @@ void Config::SetDefaults() SetEntryInternal(QStringLiteral("AudioScrubbing"), NodeParam::kBoolean, true); SetEntryInternal(QStringLiteral("AutorecoveryInterval"), NodeParam::kInt, 1); SetEntryInternal(QStringLiteral("DiskCacheSaveInterval"), NodeParam::kInt, 10000); - SetEntryInternal(QStringLiteral("Language"), NodeParam::kString, QLocale::system().name()); + SetEntryInternal(QStringLiteral("Language"), NodeParam::kString, QString()); SetEntryInternal(QStringLiteral("ScrollZooms"), NodeParam::kBoolean, false); SetEntryInternal(QStringLiteral("EnableSeekToImport"), NodeParam::kBoolean, false); SetEntryInternal(QStringLiteral("EditToolAlsoSeeks"), NodeParam::kBoolean, false); @@ -89,19 +89,21 @@ void Config::SetDefaults() SetEntryInternal(QStringLiteral("RectifiedWaveforms"), NodeParam::kBoolean, false); SetEntryInternal(QStringLiteral("DropWithoutSequenceBehavior"), NodeParam::kInt, ImportTool::kDWSAsk); SetEntryInternal(QStringLiteral("Loop"), NodeParam::kBoolean, false); + SetEntryInternal(QStringLiteral("SplitClipsCopyNodes"), NodeParam::kBoolean, true); - SetEntryInternal(QStringLiteral("AutoCacheInterval"), NodeParam::kInt, 250); + SetEntryInternal(QStringLiteral("AutoCacheDelay"), NodeParam::kInt, 1000); - SetEntryInternal(QStringLiteral("NodeCatColor0"), NodeParam::kColor, QVariant::fromValue(Color(0.75f, 0.75f, 0.75f))); - SetEntryInternal(QStringLiteral("NodeCatColor1"), NodeParam::kColor, QVariant::fromValue(Color(0.25f, 0.25f, 0.25f))); - SetEntryInternal(QStringLiteral("NodeCatColor2"), NodeParam::kColor, QVariant::fromValue(Color(0.75f, 0.75f, 0.25f))); - SetEntryInternal(QStringLiteral("NodeCatColor3"), NodeParam::kColor, QVariant::fromValue(Color(0.75f, 0.25f, 0.75f))); - SetEntryInternal(QStringLiteral("NodeCatColor4"), NodeParam::kColor, QVariant::fromValue(Color(0.25f, 0.75f, 0.75f))); - SetEntryInternal(QStringLiteral("NodeCatColor5"), NodeParam::kColor, QVariant::fromValue(Color(0.50f, 0.50f, 0.50f))); - SetEntryInternal(QStringLiteral("NodeCatColor6"), NodeParam::kColor, QVariant::fromValue(Color(0.25f, 0.75f, 0.25f))); - SetEntryInternal(QStringLiteral("NodeCatColor7"), NodeParam::kColor, QVariant::fromValue(Color(0.25f, 0.25f, 0.75f))); - SetEntryInternal(QStringLiteral("NodeCatColor8"), NodeParam::kColor, QVariant::fromValue(Color(0.75f, 0.25f, 0.25f))); - SetEntryInternal(QStringLiteral("NodeCatColor9"), NodeParam::kColor, QVariant::fromValue(Color(0.55f, 0.55f, 0.75f))); + SetEntryInternal(QStringLiteral("NodeCatColor0"), NodeParam::kColor, QVariant::fromValue(Color(0.75, 0.75, 0.75))); + SetEntryInternal(QStringLiteral("NodeCatColor1"), NodeParam::kColor, QVariant::fromValue(Color(0.25, 0.25, 0.25))); + SetEntryInternal(QStringLiteral("NodeCatColor2"), NodeParam::kColor, QVariant::fromValue(Color(0.75, 0.75, 0.25))); + SetEntryInternal(QStringLiteral("NodeCatColor3"), NodeParam::kColor, QVariant::fromValue(Color(0.75, 0.25, 0.75))); + SetEntryInternal(QStringLiteral("NodeCatColor4"), NodeParam::kColor, QVariant::fromValue(Color(0.25, 0.75, 0.75))); + SetEntryInternal(QStringLiteral("NodeCatColor5"), NodeParam::kColor, QVariant::fromValue(Color(0.50, 0.50, 0.50))); + SetEntryInternal(QStringLiteral("NodeCatColor6"), NodeParam::kColor, QVariant::fromValue(Color(0.25, 0.75, 0.25))); + SetEntryInternal(QStringLiteral("NodeCatColor7"), NodeParam::kColor, QVariant::fromValue(Color(0.25, 0.25, 0.75))); + SetEntryInternal(QStringLiteral("NodeCatColor8"), NodeParam::kColor, QVariant::fromValue(Color(0.75, 0.25, 0.25))); + SetEntryInternal(QStringLiteral("NodeCatColor9"), NodeParam::kColor, QVariant::fromValue(Color(0.55, 0.55, 0.75))); + SetEntryInternal(QStringLiteral("NodeCatColor10"), NodeParam::kColor, QVariant::fromValue(Color(0.75, 0.55, 0.25))); SetEntryInternal(QStringLiteral("AudioOutput"), NodeParam::kString, QString()); SetEntryInternal(QStringLiteral("AudioInput"), NodeParam::kString, QString()); @@ -116,13 +118,10 @@ void Config::SetDefaults() SetEntryInternal(QStringLiteral("DefaultSequenceInterlacing"), NodeParam::kInt, VideoParams::kInterlaceNone); SetEntryInternal(QStringLiteral("DefaultSequenceAudioFrequency"), NodeParam::kInt, 48000); SetEntryInternal(QStringLiteral("DefaultSequenceAudioLayout"), NodeParam::kInt, QVariant::fromValue(static_cast(AV_CH_LAYOUT_STEREO))); - SetEntryInternal(QStringLiteral("DefaultSequencePreviewFormat"), NodeParam::kInt, PixelFormat::PIX_FMT_RGBA16F); // Online/offline settings - SetEntryInternal(QStringLiteral("OnlinePixelFormat"), NodeParam::kInt, PixelFormat::PIX_FMT_RGBA32F); - SetEntryInternal(QStringLiteral("OfflinePixelFormat"), NodeParam::kInt, PixelFormat::PIX_FMT_RGBA16F); - SetEntryInternal(QStringLiteral("OnlineOCIOMethod"), NodeParam::kInt, ColorManager::kOCIOAccurate); - SetEntryInternal(QStringLiteral("OfflineOCIOMethod"), NodeParam::kInt, ColorManager::kOCIOFast); + SetEntryInternal(QStringLiteral("OnlinePixelFormat"), NodeParam::kInt, VideoParams::kFormatFloat32); + SetEntryInternal(QStringLiteral("OfflinePixelFormat"), NodeParam::kInt, VideoParams::kFormatFloat16); } void Config::Load() @@ -206,13 +205,16 @@ void Config::Load() void Config::Save() { - QFile config_file(GetConfigFilePath()); + QString real_filename = GetConfigFilePath(); + QString temp_filename = FileFunctions::GetSafeTemporaryFilename(real_filename); + + QFile config_file(temp_filename); if (!config_file.open(QFile::WriteOnly)) { QMessageBox::critical(Core::instance()->main_window(), QCoreApplication::translate("Config", "Error saving settings"), QCoreApplication::translate("Config", "Failed to save application settings. The application " - "may lack write permissions to this location."), + "may lack write permissions for this location."), QMessageBox::Ok); return; } @@ -233,10 +235,10 @@ void Config::Save() QString value = NodeInput::ValueToString(iterator.value().type, iterator.value().data, false); - writer.writeTextElement(iterator.key(), value); - if (iterator.value().type == NodeParam::kNone) { - qWarning() << "Config key" << iterator.key() << "had null type"; + qWarning() << "Config key" << iterator.key() << "had null type and was discarded"; + } else { + writer.writeTextElement(iterator.key(), value); } } @@ -245,6 +247,11 @@ void Config::Save() writer.writeEndDocument(); config_file.close(); + + if (!FileFunctions::RenameFileAllowOverwrite(temp_filename, real_filename)) { + qWarning() << QStringLiteral("Failed to overwrite \"%1\". Config has been saved as \"%2\" instead.") + .arg(real_filename, temp_filename); + } } QVariant Config::operator[](const QString &key) const @@ -262,4 +269,4 @@ NodeParam::DataType Config::GetConfigEntryType(const QString &key) const return config_map_[key].type; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/config/config.h b/app/config/config.h index dfed5a23d..5fedcdbd1 100644 --- a/app/config/config.h +++ b/app/config/config.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "common/timecodefunctions.h" #include "node/param.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Config { public: @@ -63,6 +63,6 @@ private: static QString GetConfigFilePath(); }; -OLIVE_NAMESPACE_EXIT +} #endif // CONFIG_H diff --git a/app/core.cpp b/app/core.cpp index c070bac7e..937a48c72 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -49,11 +49,9 @@ #include "panel/panelmanager.h" #include "panel/project/project.h" #include "panel/viewer/viewer.h" -#include "render/backend/opengl/opengltexturecache.h" #include "render/colormanager.h" #include "render/diskmanager.h" -#include "render/pixelformat.h" -#include "render/shaderinfo.h" +#include "render/rendermanager.h" #ifdef USE_OTIO #include "task/project/loadotio/loadotio.h" #include "task/project/saveotio/saveotio.h" @@ -70,10 +68,10 @@ #include "widget/viewer/viewer.h" #include "window/mainwindow/mainwindow.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Core* Core::instance_ = nullptr; -const uint Core::kProjectVersion = 201003; +const uint Core::kProjectVersion = 201122; Core::Core(const CoreParams& params) : main_window_(nullptr), @@ -85,6 +83,8 @@ Core::Core(const CoreParams& params) : // Store reference to this object, making the assumption that Core will only ever be made in // main(). This will obviously break if not. instance_ = this; + + translator_ = new QTranslator(this); } Core *Core::instance() @@ -95,8 +95,6 @@ Core *Core::instance() void Core::DeclareTypesForQt() { qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); @@ -105,17 +103,16 @@ void Core::DeclareTypesForQt() qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); - qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); } void Core::Start() @@ -123,6 +120,9 @@ void Core::Start() // Load application config Config::Load(); + // Set locale based on either startup arg, config, or auto-detect + SetStartupLocale(); + // Declare custom types for Qt signal/slot system DeclareTypesForQt(); @@ -135,8 +135,8 @@ void Core::Start() // Initialize task manager TaskManager::CreateInstance(); - // Initialize OpenGL service - OpenGLProxy::CreateInstance(); + // Initialize RenderManager + RenderManager::CreateInstance(); // // Start application @@ -172,15 +172,13 @@ void Core::Stop() if (recent_projects_file.open(QFile::WriteOnly | QFile::Text)) { QTextStream ts(&recent_projects_file); - foreach (const QString& s, recent_projects_) { - ts << s << "\n"; - } + ts << recent_projects_.join('\n'); recent_projects_file.close(); } } - OpenGLProxy::DestroyInstance(); + RenderManager::DestroyInstance(); MenuShared::DestroyInstance(); @@ -192,11 +190,10 @@ void Core::Stop() DiskManager::DestroyInstance(); - PixelFormat::DestroyInstance(); - NodeFactory::Destroy(); delete main_window_; + main_window_ = nullptr; } MainWindow *Core::main_window() @@ -259,19 +256,20 @@ void Core::SetSelectedTransitionObject(const QString &obj) void Core::ClearOpenRecentList() { recent_projects_.clear(); + emit OpenRecentListChanged(); } void Core::CreateNewProject() { // If we already have an empty/new project, switch to it - foreach (ProjectPtr already_open, open_projects_) { + foreach (Project* already_open, open_projects_) { if (already_open->is_new()) { AddOpenProject(already_open); return; } } - AddOpenProject(std::make_shared()); + AddOpenProject(new Project()); } const bool &Core::snapping() const @@ -284,17 +282,6 @@ const QStringList &Core::GetRecentProjects() const return recent_projects_; } -ProjectPtr Core::GetSharedPtrFromProject(Project *project) const -{ - foreach (ProjectPtr p, open_projects_) { - if (p.get() == project) { - return p; - } - } - - return nullptr; -} - void Core::SetTool(const Tool::Item &tool) { tool_ = tool; @@ -349,10 +336,10 @@ void Core::DialogPreferencesShow() void Core::DialogProjectPropertiesShow() { - ProjectPtr proj = GetActiveProject(); + Project* proj = GetActiveProject(); if (proj) { - ProjectPropertiesDialog ppd(proj.get(), main_window_); + ProjectPropertiesDialog ppd(proj, main_window_); ppd.exec(); } else { QMessageBox::critical(main_window_, @@ -364,11 +351,14 @@ void Core::DialogProjectPropertiesShow() void Core::DialogExportShow() { - ViewerOutput* sequence = GetSequenceToExport(); + ViewerOutput* viewer = GetSequenceToExport(); - if (sequence) { - ExportDialog ed(sequence, main_window_); - ed.exec(); + if (viewer) { + Sequence* sequence = dynamic_cast(viewer->parent()); + + ExportDialog* ed = new ExportDialog(viewer, sequence, main_window_); + connect(ed, &ExportDialog::finished, ed, &ExportDialog::deleteLater); + ed->open(); } } @@ -406,7 +396,7 @@ void Core::CreateNewFolder() void Core::CreateNewSequence() { - ProjectPtr active_project = GetActiveProject(); + Project* active_project = GetActiveProject(); if (!active_project) { QMessageBox::critical(main_window_, tr("Failed to create new sequence"), tr("Failed to find active project")); @@ -414,7 +404,7 @@ void Core::CreateNewSequence() } // Create new sequence - SequencePtr new_sequence = CreateNewSequenceForProject(active_project.get()); + SequencePtr new_sequence = CreateNewSequenceForProject(active_project); // Set all defaults for the sequence new_sequence->set_default_parameters(); @@ -439,13 +429,13 @@ void Core::CreateNewSequence() } } -void Core::AddOpenProject(ProjectPtr p) +void Core::AddOpenProject(Project* p) { // Ensure project is not open at the moment - foreach (ProjectPtr already_open, open_projects_) { + foreach (Project* already_open, open_projects_) { if (already_open == p) { // Signal UI to switch to this project - emit ProjectOpened(p.get()); + emit ProjectOpened(p); return; } } @@ -455,24 +445,26 @@ void Core::AddOpenProject(ProjectPtr p) CloseProject(open_projects_.last(), false); } - connect(p.get(), &Project::ModifiedChanged, this, &Core::ProjectWasModified); + connect(p, &Project::ModifiedChanged, this, &Core::ProjectWasModified); open_projects_.append(p); PushRecentlyOpenedProject(p->filename()); - emit ProjectOpened(p.get()); + emit ProjectOpened(p); } void Core::AddOpenProjectFromTask(Task *task) { ProjectLoadBaseTask* load_task = static_cast(task); - ProjectPtr project = load_task->GetLoadedProject(); + Project* project = load_task->GetLoadedProject(); MainWindowLayoutInfo layout = load_task->GetLoadedLayout(); if (ValidateFootageInLoadedProject(project, load_task->GetFilenameProjectWasSavedAs())) { AddOpenProject(project); main_window_->LoadLayout(layout); + } else { + delete project; } } @@ -515,7 +507,7 @@ void Core::ProjectWasModified(bool e) } else { // If we just set this project to "not modified", see if all projects are not modified in which case we can hide // the modified flag - foreach (ProjectPtr open, open_projects_) { + foreach (Project* open, open_projects_) { if (open->is_modified()) { main_window_->setWindowModified(true); return; @@ -545,7 +537,7 @@ bool Core::StartHeadlessExport() CLITaskDialog task_dialog(&plm); if (task_dialog.Run()) { - ProjectPtr p = plm.GetLoadedProject(); + std::unique_ptr p = std::unique_ptr(plm.GetLoadedProject()); QList items = p->get_items_of_type(Item::kSequence); // Check if this project contains sequences @@ -648,9 +640,6 @@ void Core::StartGUI(bool full_screen) // Initialize disk service DiskManager::CreateInstance(); - // Initialize pixel service - PixelFormat::CreateInstance(); - // Connect the PanelFocusManager to the application's focus change signal connect(qApp, &QApplication::focusChanged, @@ -686,16 +675,19 @@ void Core::StartGUI(bool full_screen) if (recent_projects_file.open(QFile::ReadOnly | QFile::Text)) { QTextStream ts(&recent_projects_file); - while (!ts.atEnd()) { - recent_projects_.append(ts.readLine()); + QString s; + while (!(s = ts.readLine()).isEmpty()) { + recent_projects_.append(s); } recent_projects_file.close(); } + + emit OpenRecentListChanged(); } } -void Core::SaveProjectInternal(ProjectPtr project) +void Core::SaveProjectInternal(Project* project) { // Create save manager Task* psm; @@ -753,7 +745,7 @@ ViewerOutput *Core::GetSequenceToExport() void Core::SaveAutorecovery() { - foreach (ProjectPtr p, open_projects_) { + foreach (Project* p, open_projects_) { if (!p->has_autorecovery_been_saved()) { // FIXME: SAVE AN AUTORECOVERY PROJECT p->set_autorecovery_saved(true); @@ -763,19 +755,19 @@ void Core::SaveAutorecovery() void Core::ProjectSaveSucceeded(Task* task) { - ProjectPtr p = static_cast(task)->GetProject(); + Project* p = static_cast(task)->GetProject(); PushRecentlyOpenedProject(p->filename()); p->set_modified(false); } -ProjectPtr Core::GetActiveProject() const +Project* Core::GetActiveProject() const { ProjectPanel* active_project_panel = PanelManager::instance()->MostRecentlyFocused(); if (active_project_panel && active_project_panel->project()) { - return GetSharedPtrFromProject(active_project_panel->project()); + return active_project_panel->project(); } return nullptr; @@ -833,7 +825,7 @@ QString Core::PasteStringFromClipboard() bool Core::SaveActiveProject() { - ProjectPtr active_project = GetActiveProject(); + Project* active_project = GetActiveProject(); if (active_project) { return SaveProject(active_project); @@ -844,7 +836,7 @@ bool Core::SaveActiveProject() bool Core::SaveActiveProjectAs() { - ProjectPtr active_project = GetActiveProject(); + Project* active_project = GetActiveProject(); if (active_project) { return SaveProjectAs(active_project); @@ -855,7 +847,7 @@ bool Core::SaveActiveProjectAs() bool Core::SaveAllProjects() { - foreach (ProjectPtr p, open_projects_) { + foreach (Project* p, open_projects_) { if (!SaveProject(p)) { return false; } @@ -871,10 +863,10 @@ bool Core::CloseActiveProject() bool Core::CloseAllExceptActiveProject() { - ProjectPtr active_proj = GetActiveProject(); - QList copy = open_projects_; + Project* active_proj = GetActiveProject(); + QList copy = open_projects_; - foreach (ProjectPtr p, copy) { + foreach (Project* p, copy) { if (p != active_proj) { if (!CloseProject(p, true)) { return false; @@ -910,7 +902,30 @@ QString Core::GetRecentProjectsFilePath() return QDir(FileFunctions::GetConfigurationLocation()).filePath(QStringLiteral("recent")); } -bool Core::SaveProject(ProjectPtr p) +void Core::SetStartupLocale() +{ + // Set language + if (!core_params_.startup_language().isEmpty()) { + if (translator_->load(core_params_.startup_language()) && QApplication::installTranslator(translator_)) { + return; + } else { + qWarning() << "Failed to load translation file. Falling back to defaults."; + } + } + + QString use_locale = Config::Current()[QStringLiteral("Language")].toString(); + + if (use_locale.isEmpty()) { + // No configured locale, auto-detect the system's locale + use_locale = QLocale::system().name(); + } + + if (!SetLanguage(use_locale)) { + qWarning() << "Trying to use locale" << use_locale << "but couldn't find a translation for it"; + } +} + +bool Core::SaveProject(Project* p) { if (p->filename().isEmpty()) { return SaveProjectAs(p); @@ -921,7 +936,7 @@ bool Core::SaveProject(ProjectPtr p) } } -bool Core::SaveProjectAs(ProjectPtr p) +bool Core::SaveProjectAs(Project* p) { QFileDialog fd(main_window_, tr("Save Project As")); @@ -961,12 +976,14 @@ void Core::PushRecentlyOpenedProject(const QString& s) } else { recent_projects_.prepend(s); } + + emit OpenRecentListChanged(); } void Core::OpenProjectInternal(const QString &filename) { // See if this project is open already - foreach (ProjectPtr p, open_projects_) { + foreach (Project* p, open_projects_) { if (p->filename() == filename) { // This project is already open AddOpenProject(p); @@ -1038,7 +1055,7 @@ void Core::SetPreferenceForRenderMode(RenderMode::Mode mode, const QString &pref Config::Current()[GetRenderModePreferencePrefix(mode, preference)] = value; } -void Core::LabelNodes(const QList &nodes) const +void Core::LabelNodes(const QVector &nodes) const { if (nodes.isEmpty()) { return; @@ -1097,16 +1114,18 @@ void Core::OpenProjectFromRecentList(int index) tr("The project \"%1\" doesn't exist. Would you like to remove this file from the recent list?").arg(open_fn), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { recent_projects_.removeAt(index); + + emit OpenRecentListChanged(); } } -bool Core::CloseProject(ProjectPtr p, bool auto_open_new) +bool Core::CloseProject(Project *p, bool auto_open_new) { CloseProjectBehavior b = kCloseProjectOnlyOne; return CloseProject(p, auto_open_new, b); } -bool Core::CloseProject(ProjectPtr p, bool auto_open_new, CloseProjectBehavior &confirm_behavior) +bool Core::CloseProject(Project* p, bool auto_open_new, CloseProjectBehavior &confirm_behavior) { for (int i=0;i copy = open_projects_; + QList copy = open_projects_; // See how many projects are modified so we can set "behavior" correctly // (i.e. whether to show "Yes/No To All" buttons or not) int modified_count = 0; - foreach (ProjectPtr p, copy) { + foreach (Project* p, copy) { if (p->is_modified()) { modified_count++; } @@ -1210,7 +1230,7 @@ bool Core::CloseAllProjects(bool auto_open_new) behavior = kCloseProjectOnlyOne; } - foreach (ProjectPtr p, copy) { + foreach (Project* p, copy) { // If this is the only remaining project and the user hasn't chose "yes/no to all", hide those buttons if (modified_count == 1 && behavior == kCloseProjectAsk) { behavior = kCloseProjectOnlyOne; @@ -1260,7 +1280,7 @@ void Core::CacheActiveSequence(bool in_out_only) } } -bool Core::ValidateFootageInLoadedProject(ProjectPtr project, const QString& project_saved_url) +bool Core::ValidateFootageInLoadedProject(Project* project, const QString& project_saved_url) { QList footage_we_couldnt_validate; @@ -1307,6 +1327,18 @@ bool Core::ValidateFootageInLoadedProject(ProjectPtr project, const QString& pro return true; } +bool Core::SetLanguage(const QString &locale) +{ + QApplication::removeTranslator(translator_); + + QString resource_path = QStringLiteral(":/ts/%1").arg(locale); + if (translator_->load(resource_path) && QApplication::installTranslator(translator_)) { + return true; + } + + return false; +} + bool Core::CloseAllProjects() { return CloseAllProjects(true); @@ -1330,4 +1362,4 @@ Core::CoreParams::CoreParams() : { } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/core.h b/app/core.h index 8e3b45db1..da6c2d9d2 100644 --- a/app/core.h +++ b/app/core.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,6 +24,7 @@ #include #include #include +#include #include "common/rational.h" #include "common/timecodefunctions.h" @@ -35,7 +36,7 @@ #include "tool/tool.h" #include "undo/undostack.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class MainWindow; @@ -93,11 +94,23 @@ public: startup_project_ = p; } + const QString& startup_language() const + { + return startup_language_; + } + + void set_startup_language(const QString& s) + { + startup_language_ = s; + } + private: RunMode mode_; QString startup_project_; + QString startup_language_; + bool run_fullscreen_; }; @@ -184,11 +197,6 @@ public: */ const QStringList& GetRecentProjects() const; - /** - * @brief Convenience function to retrieve a Project's shared pointer - */ - ProjectPtr GetSharedPtrFromProject(Project* project) const; - /** * @brief Get the currently active project * @@ -199,7 +207,7 @@ public: * * The active Project file, or nullptr if the heuristic couldn't find one. */ - ProjectPtr GetActiveProject() const; + Project* GetActiveProject() const; ProjectViewModel* GetActiveProjectModel() const; Folder* GetSelectedFolderInActiveProject() const; @@ -233,7 +241,7 @@ public: /** * @brief Show a dialog to the user to rename a set of nodes */ - void LabelNodes(const QList& nodes) const; + void LabelNodes(const QVector &nodes) const; /** * @brief Create a new sequence named appropriately for the active project @@ -255,8 +263,8 @@ public: /** * @brief Closes a project */ - bool CloseProject(ProjectPtr p, bool auto_open_new, CloseProjectBehavior& confirm_behavior); - bool CloseProject(ProjectPtr p, bool auto_open_new); + bool CloseProject(Project* p, bool auto_open_new, CloseProjectBehavior& confirm_behavior); + bool CloseProject(Project* p, bool auto_open_new); /** * @brief Closes all open projects @@ -271,7 +279,17 @@ public: /** * @brief Check each footage object for whether it still exists or has changed */ - bool ValidateFootageInLoadedProject(ProjectPtr project, const QString &project_saved_url); + bool ValidateFootageInLoadedProject(Project* project, const QString &project_saved_url); + + /** + * @brief Changes the current language + */ + bool SetLanguage(const QString& locale); + + /** + * @brief Saves a specific project + */ + bool SaveProject(Project *p); static const uint kProjectVersion; @@ -415,6 +433,11 @@ signals: */ void TimecodeDisplayChanged(Timecode::Display d); + /** + * @brief Signal emitted when a change is made to the open recent list + */ + void OpenRecentListChanged(); + private: /** * @brief Get the file filter than can be used with QFileDialog to open and save compatible projects @@ -427,14 +450,14 @@ private: static QString GetRecentProjectsFilePath(); /** - * @brief Saves a specific project + * @brief Called only on startup to set the locale */ - bool SaveProject(ProjectPtr p); + void SetStartupLocale(); /** * @brief Performs a "save as" on a specific project */ - bool SaveProjectAs(ProjectPtr p); + bool SaveProjectAs(Project *p); /** * @brief Adds a filename to the top of the recently opened projects list (or moves it if it already exists) @@ -460,7 +483,7 @@ private: /** * @brief Internal function for saving a project to a file */ - void SaveProjectInternal(ProjectPtr project); + void SaveProjectInternal(Project *project); /** * @brief Retrieves the currently most active sequence for exporting @@ -475,7 +498,7 @@ private: /** * @brief List of currently open projects */ - QList open_projects_; + QList open_projects_; /** * @brief Currently active tool @@ -522,6 +545,11 @@ private: */ static Core* instance_; + /** + * @brief Internal translator + */ + QTranslator* translator_; + private slots: void SaveAutorecovery(); @@ -530,7 +558,7 @@ private slots: /** * @brief Adds a project to the "open projects" list */ - void AddOpenProject(OLIVE_NAMESPACE::ProjectPtr p); + void AddOpenProject(olive::Project* p); void AddOpenProjectFromTask(Task* task); @@ -551,6 +579,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // CORE_H diff --git a/app/dialog/CMakeLists.txt b/app/dialog/CMakeLists.txt index 61e5eada9..239e46b8f 100644 --- a/app/dialog/CMakeLists.txt +++ b/app/dialog/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/about/CMakeLists.txt b/app/dialog/about/CMakeLists.txt index c4a932e77..61b668baa 100644 --- a/app/dialog/about/CMakeLists.txt +++ b/app/dialog/about/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/about/about.cpp b/app/dialog/about/about.cpp index a37229a93..aa3f8f9be 100644 --- a/app/dialog/about/about.cpp +++ b/app/dialog/about/about.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent) @@ -38,7 +38,7 @@ AboutDialog::AboutDialog(QWidget *parent) : // Construct About text QLabel* label = new QLabel(QStringLiteral("" - "

" + "

" "

" "" "https://www.olivevideoeditor.org/" @@ -67,4 +67,4 @@ AboutDialog::AboutDialog(QWidget *parent) : connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/about/about.h b/app/dialog/about/about.h index c430d9ee7..53557ebec 100644 --- a/app/dialog/about/about.h +++ b/app/dialog/about/about.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief The AboutDialog class @@ -49,6 +49,6 @@ public: explicit AboutDialog(QWidget *parent = nullptr); }; -OLIVE_NAMESPACE_EXIT +} #endif // ABOUTDIALOG_H diff --git a/app/dialog/actionsearch/CMakeLists.txt b/app/dialog/actionsearch/CMakeLists.txt index 16d7e7a68..2aa104524 100644 --- a/app/dialog/actionsearch/CMakeLists.txt +++ b/app/dialog/actionsearch/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/actionsearch/actionsearch.cpp b/app/dialog/actionsearch/actionsearch.cpp index 57c1cd2dc..ac632f415 100644 --- a/app/dialog/actionsearch/actionsearch.cpp +++ b/app/dialog/actionsearch/actionsearch.cpp @@ -25,7 +25,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { ActionSearch::ActionSearch(QWidget *parent) : QDialog(parent), @@ -254,4 +254,4 @@ void ActionSearchList::mouseDoubleClickEvent(QMouseEvent *) { } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/actionsearch/actionsearch.h b/app/dialog/actionsearch/actionsearch.h index 386a0cd07..ecb446955 100644 --- a/app/dialog/actionsearch/actionsearch.h +++ b/app/dialog/actionsearch/actionsearch.h @@ -29,7 +29,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ActionSearchList; @@ -182,6 +182,6 @@ signals: void moveSelectionDown(); }; -OLIVE_NAMESPACE_EXIT +} #endif // ACTIONSEARCH_H diff --git a/app/dialog/color/CMakeLists.txt b/app/dialog/color/CMakeLists.txt index f36cd6b5d..a50056c0b 100644 --- a/app/dialog/color/CMakeLists.txt +++ b/app/dialog/color/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/color/colordialog.cpp b/app/dialog/color/colordialog.cpp index e578cfdd2..e838ce982 100644 --- a/app/dialog/color/colordialog.cpp +++ b/app/dialog/color/colordialog.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/qtutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ColorDialog::ColorDialog(ColorManager* color_manager, const ManagedColor& start, QWidget *parent) : QDialog(parent), @@ -48,7 +48,7 @@ ColorDialog::ColorDialog(ColorManager* color_manager, const ManagedColor& start, wheel_layout->addWidget(color_wheel_); hsv_value_gradient_ = new ColorGradientWidget(Qt::Vertical); - hsv_value_gradient_->setFixedWidth(QFontMetricsWidth(fontMetrics(), QStringLiteral("HHH"))); + hsv_value_gradient_->setFixedWidth(QtUtils::QFontMetricsWidth(fontMetrics(), QStringLiteral("HHH"))); wheel_layout->addWidget(hsv_value_gradient_); QWidget* value_area = new QWidget(); @@ -160,4 +160,4 @@ void ColorDialog::ColorSpaceChanged(const QString &input, const ColorTransform & color_values_widget_->SetColorProcessor(input_to_ref_processor_, ref_to_display, nullptr, ref_to_input); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/color/colordialog.h b/app/dialog/color/colordialog.h index 356924c5b..ccba97c18 100644 --- a/app/dialog/color/colordialog.h +++ b/app/dialog/color/colordialog.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -31,7 +31,7 @@ #include "widget/colorwheel/colorvalueswidget.h" #include "widget/colorwheel/colorwheelwidget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ColorDialog : public QDialog { @@ -87,6 +87,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // COLORDIALOG_H diff --git a/app/dialog/crashhandler/crashhandler.cpp b/app/dialog/crashhandler/crashhandler.cpp index 2b21293f9..61f8c276b 100644 --- a/app/dialog/crashhandler/crashhandler.cpp +++ b/app/dialog/crashhandler/crashhandler.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -36,7 +36,7 @@ #include "common/crashpadutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { CrashHandlerDialog::CrashHandlerDialog(const char *report_dir, const char* crash_time) { @@ -208,4 +208,4 @@ void CrashHandlerDialog::SendErrorReport() manager->post(request, multipart); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/crashhandler/crashhandler.h b/app/dialog/crashhandler/crashhandler.h index 7ec91669b..f93be9dfa 100644 --- a/app/dialog/crashhandler/crashhandler.h +++ b/app/dialog/crashhandler/crashhandler.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class CrashHandlerDialog : public QDialog { @@ -72,6 +72,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // CRASHHANDLERDIALOG_H diff --git a/app/dialog/crashhandler/crashhandlermain.cpp b/app/dialog/crashhandler/crashhandlermain.cpp index d0fe76368..7142fc244 100644 --- a/app/dialog/crashhandler/crashhandlermain.cpp +++ b/app/dialog/crashhandler/crashhandlermain.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ int main(int argc, char *argv[]) QApplication a(argc, argv); - OLIVE_NAMESPACE::CrashHandlerDialog chd(argv[1], argv[2]); + olive::CrashHandlerDialog chd(argv[1], argv[2]); chd.open(); return a.exec(); diff --git a/app/dialog/diskcache/CMakeLists.txt b/app/dialog/diskcache/CMakeLists.txt index 6ca59d549..077c712ca 100644 --- a/app/dialog/diskcache/CMakeLists.txt +++ b/app/dialog/diskcache/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/diskcache/diskcachedialog.cpp b/app/dialog/diskcache/diskcachedialog.cpp index 6e542b7c3..3e8831f49 100644 --- a/app/dialog/diskcache/diskcachedialog.cpp +++ b/app/dialog/diskcache/diskcachedialog.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "config/config.h" -OLIVE_NAMESPACE_ENTER +namespace olive { DiskCacheDialog::DiskCacheDialog(DiskCacheFolder *folder, QWidget* parent) : QDialog(parent), @@ -104,4 +104,4 @@ void DiskCacheDialog::ClearDiskCache() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/diskcache/diskcachedialog.h b/app/dialog/diskcache/diskcachedialog.h index 69c3a20f3..b1ea61395 100644 --- a/app/dialog/diskcache/diskcachedialog.h +++ b/app/dialog/diskcache/diskcachedialog.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "render/diskmanager.h" #include "widget/slider/floatslider.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class DiskCacheDialog : public QDialog { @@ -53,6 +53,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // DISKCACHEDIALOG_H diff --git a/app/dialog/export/CMakeLists.txt b/app/dialog/export/CMakeLists.txt index ef122e43d..e13b45686 100644 --- a/app/dialog/export/CMakeLists.txt +++ b/app/dialog/export/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/export/codec/CMakeLists.txt b/app/dialog/export/codec/CMakeLists.txt index cb8d22213..b7ccf6c22 100644 --- a/app/dialog/export/codec/CMakeLists.txt +++ b/app/dialog/export/codec/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/export/codec/codecsection.cpp b/app/dialog/export/codec/codecsection.cpp index 309facaba..9847bb697 100644 --- a/app/dialog/export/codec/codecsection.cpp +++ b/app/dialog/export/codec/codecsection.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,11 +20,11 @@ #include "codecsection.h" -OLIVE_NAMESPACE_ENTER +namespace olive { CodecSection::CodecSection(QWidget *parent) : QWidget(parent) { } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/export/codec/codecsection.h b/app/dialog/export/codec/codecsection.h index e187b0df7..82f70b69e 100644 --- a/app/dialog/export/codec/codecsection.h +++ b/app/dialog/export/codec/codecsection.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,10 +25,11 @@ #include "codec/encoder.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class CodecSection : public QWidget { + Q_OBJECT public: CodecSection(QWidget* parent = nullptr); @@ -36,6 +37,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // CODECSECTION_H diff --git a/app/dialog/export/codec/h264section.cpp b/app/dialog/export/codec/h264section.cpp index e0e50fb55..ac4dcda78 100644 --- a/app/dialog/export/codec/h264section.cpp +++ b/app/dialog/export/codec/h264section.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "common/qtutils.h" #include "widget/slider/integerslider.h" -OLIVE_NAMESPACE_ENTER +namespace olive { H264Section::H264Section(QWidget *parent) : CodecSection(parent) @@ -117,7 +117,7 @@ H264CRFSection::H264CRFSection(QWidget *parent) : layout->addWidget(crf_slider_); IntegerSlider* crf_input = new IntegerSlider(); - crf_input->setMaximumWidth(QFontMetricsWidth(crf_input->fontMetrics(), QStringLiteral("HHHH"))); + crf_input->setMaximumWidth(QtUtils::QFontMetricsWidth(crf_input->fontMetrics(), QStringLiteral("HHHH"))); crf_input->SetMinimum(kMinimumCRF); crf_input->SetMaximum(kMaximumCRF); crf_input->SetValue(kDefaultCRF); @@ -208,4 +208,4 @@ int64_t H264FileSizeSection::GetFileSize() const return qRound64(file_size_->GetValue() * 1024.0 * 1024.0 * 8.0); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/export/codec/h264section.h b/app/dialog/export/codec/h264section.h index 6e85e632a..f00e9cb17 100644 --- a/app/dialog/export/codec/h264section.h +++ b/app/dialog/export/codec/h264section.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,10 +27,11 @@ #include "codecsection.h" #include "widget/slider/floatslider.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class H264CRFSection : public QWidget { + Q_OBJECT public: H264CRFSection(QWidget* parent = nullptr); @@ -49,6 +50,7 @@ private: class H264BitRateSection : public QWidget { + Q_OBJECT public: H264BitRateSection(QWidget* parent = nullptr); @@ -71,6 +73,7 @@ private: class H264FileSizeSection : public QWidget { + Q_OBJECT public: H264FileSizeSection(QWidget* parent = nullptr); @@ -86,6 +89,7 @@ private: class H264Section : public CodecSection { + Q_OBJECT public: enum CompressionMethod { kConstantRateFactor, @@ -108,6 +112,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // H264SECTION_H diff --git a/app/dialog/export/codec/imagesection.cpp b/app/dialog/export/codec/imagesection.cpp index 8b373796e..611a99504 100644 --- a/app/dialog/export/codec/imagesection.cpp +++ b/app/dialog/export/codec/imagesection.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { ImageSection::ImageSection(QWidget* parent) : CodecSection(parent) @@ -44,4 +44,4 @@ QCheckBox *ImageSection::image_sequence_checkbox() const return image_sequence_checkbox_; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/export/codec/imagesection.h b/app/dialog/export/codec/imagesection.h index a40d4dd8a..d21f782a2 100644 --- a/app/dialog/export/codec/imagesection.h +++ b/app/dialog/export/codec/imagesection.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,10 +25,11 @@ #include "codecsection.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ImageSection : public CodecSection { + Q_OBJECT public: ImageSection(QWidget* parent = nullptr); @@ -39,6 +40,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // IMAGESECTION_H diff --git a/app/dialog/export/export.cpp b/app/dialog/export/export.cpp index 2d3250be9..54fece4e8 100644 --- a/app/dialog/export/export.cpp +++ b/app/dialog/export/export.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,18 +30,19 @@ #include #include +#include "common/qtutils.h" #include "core.h" #include "dialog/task/task.h" #include "project/item/sequence/sequence.h" #include "project/project.h" -#include "render/pixelformat.h" #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) : +ExportDialog::ExportDialog(ViewerOutput *viewer_node, TimelinePoints *points, QWidget *parent) : QDialog(parent), - viewer_node_(viewer_node) + viewer_node_(viewer_node), + points_(points) { QHBoxLayout* layout = new QHBoxLayout(this); @@ -95,10 +96,23 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) : row++; - QFrame* horizontal_line = new QFrame(); - horizontal_line->setFrameShape(QFrame::HLine); - horizontal_line->setFrameShadow(QFrame::Sunken); - preferences_layout->addWidget(horizontal_line, row, 0, 1, 4); + preferences_layout->addWidget(QtUtils::CreateHorizontalLine(), row, 0, 1, 4); + + row++; + + preferences_layout->addWidget(new QLabel(tr("Range:")), row, 0); + + range_combobox_ = new QComboBox(); + range_combobox_->addItem(tr("Entire Sequence")); + range_combobox_->addItem(tr("In to Out")); + if (!points_) { + range_combobox_->setEnabled(false); + } + preferences_layout->addWidget(range_combobox_, row, 1, 1, 3); + + row++; + + preferences_layout->addWidget(QtUtils::CreateHorizontalLine(), row, 0, 1, 4); row++; @@ -156,6 +170,9 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) : preview_layout->addWidget(preview_viewer_); splitter->addWidget(preview_area); + // Prioritize preview area + splitter->setSizes({1, 99999}); + // Set default filename SetDefaultFilename(); @@ -179,6 +196,7 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) : video_tab_->height_slider()->SetDefaultValue(viewer_node_->video_params().height()); video_tab_->frame_rate_combobox()->SetFrameRate(viewer_node_->video_params().time_base().flipped()); video_tab_->pixel_aspect_combobox()->SetPixelAspectRatio(viewer_node_->video_params().pixel_aspect_ratio()); + video_tab_->pixel_format_field()->SetPixelFormat(static_cast(Config::Current()["OnlinePixelFormat"].toInt())); video_tab_->interlaced_combobox()->SetInterlaceMode(viewer_node_->video_params().interlacing()); audio_tab_->sample_rate_combobox()->SetSampleRate(viewer_node_->audio_params().sample_rate()); audio_tab_->channel_layout_combobox()->SetChannelLayout(viewer_node_->audio_params().channel_layout()); @@ -212,6 +230,7 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) : // Set viewer to view the node preview_viewer_->ConnectViewerNode(viewer_node_); + preview_viewer_->ruler()->ConnectTimelinePoints(points_); preview_viewer_->SetColorMenuEnabled(false); preview_viewer_->SetColorTransform(video_tab_->CurrentOCIOColorSpace()); } @@ -232,27 +251,28 @@ void ExportDialog::StartExport() // Validate if the entered filename contains the correct extension (the extension is necessary // for both FFmpeg and OIIO to determine the output format) QString necessary_ext = QStringLiteral(".%1").arg(ExportFormat::GetExtension(static_cast(format_combobox_->currentIndex()))); + QString proposed_filename = filename_edit_->text().trimmed(); // If it doesn't, see if the user wants to append it automatically. If not, we don't abort the export. - if (!filename_edit_->text().endsWith(necessary_ext, Qt::CaseInsensitive)) { + if (!proposed_filename.endsWith(necessary_ext, Qt::CaseInsensitive)) { QMessageBox b(this); b.setIcon(QMessageBox::Warning); b.setWindowModality(Qt::WindowModal); b.setWindowTitle(tr("Invalid filename")); - b.setText(tr("The filename must contain the extension \".%1\". Would you like to append it " - "automatically?")); + b.setText(tr("The filename must contain the extension \"%1\". Would you like to append it " + "automatically?").arg(necessary_ext)); b.addButton(QMessageBox::Yes); b.addButton(QMessageBox::No); if (b.exec() == QMessageBox::Yes) { - filename_edit_->setText(filename_edit_->text().append(necessary_ext)); + filename_edit_->setText(proposed_filename.append(necessary_ext)); } else { return; } } // Validate the intended path - QFileInfo file_info(filename_edit_->text()); + QFileInfo file_info(proposed_filename); QFileInfo dir_info(file_info.path()); // If the directory does not exist, try to create it @@ -275,7 +295,7 @@ void ExportDialog::StartExport() b.setWindowModality(Qt::WindowModal); b.setWindowTitle(tr("Confirm Overwrite")); b.setText(tr("The file \"%1\" already exists. Do you want to overwrite it?") - .arg(filename_edit_->text())); + .arg(proposed_filename)); b.addButton(QMessageBox::Yes); b.addButton(QMessageBox::No); @@ -285,25 +305,36 @@ void ExportDialog::StartExport() } // Validate video resolution - if (video_enabled_->isChecked()) { - if (video_tab_->width_slider()->GetValue() % 2 != 0 - || video_tab_->height_slider()->GetValue() % 2 != 0) { - QMessageBox b(this); - b.setIcon(QMessageBox::Critical); - b.setWindowModality(Qt::WindowModal); - b.setWindowTitle(tr("Invalid parameters")); - b.setText(tr("Width and height must be multiples of 2.")); - b.exec(); - return; - } + if (video_enabled_->isChecked() + && video_tab_->GetSelectedCodec() == ExportCodec::kCodecH264 + && (video_tab_->width_slider()->GetValue()%2 != 0 || video_tab_->height_slider()->GetValue()%2 != 0)) { + QMessageBox b(this); + b.setIcon(QMessageBox::Critical); + b.setWindowModality(Qt::WindowModal); + b.setWindowTitle(tr("Invalid Parameters")); + b.setText(tr("Width and height must be multiples of 2.")); + b.exec(); + return; } ExportTask* task = new ExportTask(viewer_node_, color_manager_, GenerateParams()); TaskDialog* td = new TaskDialog(task, tr("Export"), this); - connect(td, &TaskDialog::TaskSucceeded, this, &QDialog::accept); + connect(td, &TaskDialog::TaskSucceeded, this, &ExportDialog::ExportFinished); td->open(); } +void ExportDialog::ExportFinished() +{ + TaskDialog* td = static_cast(sender()); + + if (td->GetTask()->IsCancelled()) { + // If this task was cancelled, we stay open so the user can potentially queue another export + } else { + // Accept this dialog and close + this->accept(); + } +} + void ExportDialog::closeEvent(QCloseEvent *e) { preview_viewer_->ConnectViewerNode(nullptr); @@ -317,7 +348,7 @@ void ExportDialog::BrowseFilename() QString browsed_fn = QFileDialog::getSaveFileName(this, "", - filename_edit_->text(), + filename_edit_->text().trimmed(), QStringLiteral("%1 (*.%2)").arg(ExportFormat::GetName(f), ExportFormat::GetExtension(f)), nullptr, @@ -331,7 +362,7 @@ void ExportDialog::BrowseFilename() void ExportDialog::FormatChanged(int index) { - QString current_filename = filename_edit_->text(); + QString current_filename = filename_edit_->text().trimmed(); QString previously_selected_ext = ExportFormat::GetExtension(previously_selected_format_); ExportFormat::Format current_format = static_cast(index); QString currently_selected_ext = ExportFormat::GetExtension(current_format); @@ -373,7 +404,7 @@ void ExportDialog::ResolutionChanged() new_width *= video_aspect_ratio_; // Align to even number and set - video_tab_->width_slider()->SetValue(AlignEvenNumber(new_width)); + video_tab_->width_slider()->SetValue(new_width); } else { @@ -384,7 +415,7 @@ void ExportDialog::ResolutionChanged() new_height /= video_aspect_ratio_; // Align to even number and set - video_tab_->height_slider()->SetValue(AlignEvenNumber(new_height)); + video_tab_->height_slider()->SetValue(new_height); } } @@ -414,29 +445,31 @@ void ExportDialog::SetDefaultFilename() filename_edit_->setText(file_location); } -int ExportDialog::AlignEvenNumber(double d) -{ - return qCeil(d * 0.5) * 2; -} - ExportParams ExportDialog::GenerateParams() const { VideoParams video_render_params(static_cast(video_tab_->width_slider()->GetValue()), static_cast(video_tab_->height_slider()->GetValue()), video_tab_->frame_rate_combobox()->GetFrameRate().flipped(), - PixelFormat::instance()->GetConfiguredFormatForMode(RenderMode::kOnline), + video_tab_->pixel_format_field()->GetPixelFormat(), + VideoParams::kInternalChannelCount, video_tab_->pixel_aspect_combobox()->GetPixelAspectRatio(), video_tab_->interlaced_combobox()->GetInterlaceMode(), 1); AudioParams audio_render_params(audio_tab_->sample_rate_combobox()->currentData().toInt(), audio_tab_->channel_layout_combobox()->GetChannelLayout(), - SampleFormat::kInternalFormat); + AudioParams::kInternalFormat); ExportParams params; - params.SetFilename(filename_edit_->text()); + params.SetFilename(filename_edit_->text().trimmed()); params.SetExportLength(viewer_node_->GetLength()); + if (range_combobox_->currentIndex() == kRangeInToOut + && points_ + && points_->workarea()->enabled()) { + params.set_custom_range(points_->workarea()->range()); + } + if (video_tab_->scaling_method_combobox()->isEnabled()) { params.set_video_scaling_method(static_cast(video_tab_->scaling_method_combobox()->currentData().toInt())); } @@ -477,4 +510,4 @@ void ExportDialog::UpdateViewerDimensions() preview_viewer_->SetMatrix(transform); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/export/export.h b/app/dialog/export/export.h index 8313e59cf..37144b6b3 100644 --- a/app/dialog/export/export.h +++ b/app/dialog/export/export.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -34,13 +34,13 @@ #include "task/export/export.h" #include "widget/viewer/viewer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ExportDialog : public QDialog { Q_OBJECT public: - ExportDialog(ViewerOutput* viewer_node, QWidget* parent = nullptr); + ExportDialog(ViewerOutput* viewer_node, TimelinePoints* points = nullptr, QWidget* parent = nullptr); protected: virtual void closeEvent(QCloseEvent *e) override; @@ -49,14 +49,20 @@ private: void LoadPresets(); void SetDefaultFilename(); - static int AlignEvenNumber(double d); - ExportParams GenerateParams() const; ViewerOutput* viewer_node_; + TimelinePoints* points_; ExportFormat::Format previously_selected_format_; + enum RangeSelection { + kRangeEntireSequence, + kRangeInToOut + }; + + QComboBox* range_combobox_; + QCheckBox* video_enabled_; QCheckBox* audio_enabled_; @@ -85,8 +91,10 @@ private slots: void StartExport(); + void ExportFinished(); + }; -OLIVE_NAMESPACE_EXIT +} #endif // EXPORTDIALOG_H diff --git a/app/dialog/export/exportadvancedvideodialog.cpp b/app/dialog/export/exportadvancedvideodialog.cpp index f4fc6b6e6..9e38969fb 100644 --- a/app/dialog/export/exportadvancedvideodialog.cpp +++ b/app/dialog/export/exportadvancedvideodialog.cpp @@ -5,7 +5,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { ExportAdvancedVideoDialog::ExportAdvancedVideoDialog(const QList &pix_fmts, QWidget *parent) : QDialog(parent) @@ -59,4 +59,4 @@ ExportAdvancedVideoDialog::ExportAdvancedVideoDialog(const QList &pix_f layout->addWidget(buttons); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/export/exportadvancedvideodialog.h b/app/dialog/export/exportadvancedvideodialog.h index bdadbbebe..275ae44f9 100644 --- a/app/dialog/export/exportadvancedvideodialog.h +++ b/app/dialog/export/exportadvancedvideodialog.h @@ -6,7 +6,7 @@ #include "widget/slider/integerslider.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ExportAdvancedVideoDialog : public QDialog { @@ -42,6 +42,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // EXPORTADVANCEDVIDEODIALOG_H diff --git a/app/dialog/export/exportaudiotab.cpp b/app/dialog/export/exportaudiotab.cpp index c6f4ae003..781183c19 100644 --- a/app/dialog/export/exportaudiotab.cpp +++ b/app/dialog/export/exportaudiotab.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "core.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ExportAudioTab::ExportAudioTab(QWidget* parent) : QWidget(parent) @@ -64,4 +64,4 @@ ExportAudioTab::ExportAudioTab(QWidget* parent) : outer_layout->addStretch(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/export/exportaudiotab.h b/app/dialog/export/exportaudiotab.h index 924d0b655..5ef06d2a2 100644 --- a/app/dialog/export/exportaudiotab.h +++ b/app/dialog/export/exportaudiotab.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,10 +27,11 @@ #include "common/define.h" #include "widget/standardcombos/standardcombos.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ExportAudioTab : public QWidget { + Q_OBJECT public: ExportAudioTab(QWidget* parent = nullptr); @@ -56,6 +57,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // EXPORTAUDIOTAB_H diff --git a/app/dialog/export/exportvideotab.cpp b/app/dialog/export/exportvideotab.cpp index 9d62c360f..d37f61389 100644 --- a/app/dialog/export/exportvideotab.cpp +++ b/app/dialog/export/exportvideotab.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -31,7 +31,7 @@ #include "render/colormanager.h" #include "task/export/exportparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ExportVideoTab::ExportVideoTab(ColorManager* color_manager, QWidget *parent) : QWidget(parent), @@ -115,6 +115,13 @@ QWidget* ExportVideoTab::SetupResolutionSection() interlaced_combobox_ = new InterlacedComboBox(); layout->addWidget(interlaced_combobox_, row, 1); + row++; + + layout->addWidget(new QLabel(tr("Quality:")), row, 0); + + pixel_format_field_ = new PixelFormatComboBox(true); + layout->addWidget(pixel_format_field_, row, 1); + return resolution_group; } @@ -199,4 +206,4 @@ void ExportVideoTab::VideoCodecChanged() qDebug() << "Set default pix fmt" << pix_fmt_; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/export/exportvideotab.h b/app/dialog/export/exportvideotab.h index fe35d884b..feed9eb78 100644 --- a/app/dialog/export/exportvideotab.h +++ b/app/dialog/export/exportvideotab.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -33,7 +33,7 @@ #include "widget/slider/integerslider.h" #include "widget/standardcombos/standardcombos.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ExportVideoTab : public QWidget { @@ -111,6 +111,11 @@ public: return pixel_aspect_combobox_; } + PixelFormatComboBox* pixel_format_field() const + { + return pixel_format_field_; + } + const int& threads() const { return threads_; @@ -149,6 +154,7 @@ private: InterlacedComboBox* interlaced_combobox_; PixelAspectRatioComboBox* pixel_aspect_combobox_; + PixelFormatComboBox* pixel_format_field_; int threads_; @@ -161,6 +167,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // EXPORTVIDEOTAB_H diff --git a/app/dialog/footageproperties/CMakeLists.txt b/app/dialog/footageproperties/CMakeLists.txt index 84282a556..0a3d6a7e2 100644 --- a/app/dialog/footageproperties/CMakeLists.txt +++ b/app/dialog/footageproperties/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/footageproperties/footageproperties.cpp b/app/dialog/footageproperties/footageproperties.cpp index d1dbd0fe7..e08da2564 100644 --- a/app/dialog/footageproperties/footageproperties.cpp +++ b/app/dialog/footageproperties/footageproperties.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -36,7 +36,7 @@ #include "streamproperties/audiostreamproperties.h" #include "streamproperties/videostreamproperties.h" -OLIVE_NAMESPACE_ENTER +namespace olive { FootagePropertiesDialog::FootagePropertiesDialog(QWidget *parent, Footage *footage) : QDialog(parent), @@ -198,4 +198,4 @@ void FootagePropertiesDialog::StreamEnableChangeCommand::undo_internal() stream_->set_enabled(old_enabled_); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/footageproperties/footageproperties.h b/app/dialog/footageproperties/footageproperties.h index d2018699f..614fb8800 100644 --- a/app/dialog/footageproperties/footageproperties.h +++ b/app/dialog/footageproperties/footageproperties.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -32,7 +32,7 @@ #include "project/item/footage/footage.h" #include "undo/undocommand.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief The MediaPropertiesDialog class @@ -132,6 +132,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // MEDIAPROPERTIESDIALOG_H diff --git a/app/dialog/footageproperties/streamproperties/CMakeLists.txt b/app/dialog/footageproperties/streamproperties/CMakeLists.txt index b6952d2aa..3228e9520 100644 --- a/app/dialog/footageproperties/streamproperties/CMakeLists.txt +++ b/app/dialog/footageproperties/streamproperties/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/footageproperties/streamproperties/audiostreamproperties.cpp b/app/dialog/footageproperties/streamproperties/audiostreamproperties.cpp index d09b5cff4..9f52c0e3e 100644 --- a/app/dialog/footageproperties/streamproperties/audiostreamproperties.cpp +++ b/app/dialog/footageproperties/streamproperties/audiostreamproperties.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "audiostreamproperties.h" -OLIVE_NAMESPACE_ENTER +namespace olive { AudioStreamProperties::AudioStreamProperties(AudioStreamPtr stream) : stream_(stream) @@ -31,4 +31,4 @@ void AudioStreamProperties::Accept(QUndoCommand*) { } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/footageproperties/streamproperties/audiostreamproperties.h b/app/dialog/footageproperties/streamproperties/audiostreamproperties.h index 4afc506ba..f3a77c4b9 100644 --- a/app/dialog/footageproperties/streamproperties/audiostreamproperties.h +++ b/app/dialog/footageproperties/streamproperties/audiostreamproperties.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "project/item/footage/audiostream.h" #include "streamproperties.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class AudioStreamProperties : public StreamProperties { @@ -37,6 +37,6 @@ private: AudioStreamPtr stream_; }; -OLIVE_NAMESPACE_EXIT +} #endif // AUDIOSTREAMPROPERTIES_H diff --git a/app/dialog/footageproperties/streamproperties/streamproperties.cpp b/app/dialog/footageproperties/streamproperties/streamproperties.cpp index 2344a1277..96f3bbd5a 100644 --- a/app/dialog/footageproperties/streamproperties/streamproperties.cpp +++ b/app/dialog/footageproperties/streamproperties/streamproperties.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,11 +20,11 @@ #include "streamproperties.h" -OLIVE_NAMESPACE_ENTER +namespace olive { StreamProperties::StreamProperties(QWidget *parent) : QWidget(parent) { } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/footageproperties/streamproperties/streamproperties.h b/app/dialog/footageproperties/streamproperties/streamproperties.h index 9e9e510f5..677be9b0a 100644 --- a/app/dialog/footageproperties/streamproperties/streamproperties.h +++ b/app/dialog/footageproperties/streamproperties/streamproperties.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class StreamProperties : public QWidget { @@ -39,6 +39,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // STREAMPROPERTIES_H diff --git a/app/dialog/footageproperties/streamproperties/videostreamproperties.cpp b/app/dialog/footageproperties/streamproperties/videostreamproperties.cpp index 0aaca3a43..c97b011c0 100644 --- a/app/dialog/footageproperties/streamproperties/videostreamproperties.cpp +++ b/app/dialog/footageproperties/streamproperties/videostreamproperties.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,18 +25,18 @@ #include #include #include -#include -namespace OCIO = OCIO_NAMESPACE::v1; +#include "common/ocioutils.h" #include "core.h" #include "project/item/footage/footage.h" #include "project/project.h" #include "undo/undostack.h" -OLIVE_NAMESPACE_ENTER +namespace olive { VideoStreamProperties::VideoStreamProperties(VideoStreamPtr stream) : - stream_(stream) + stream_(stream), + video_premultiply_alpha_(nullptr) { QGridLayout* video_layout = new QGridLayout(this); video_layout->setMargin(0); @@ -78,11 +78,13 @@ VideoStreamProperties::VideoStreamProperties(VideoStreamPtr stream) : video_layout->addWidget(video_color_space_, row, 1); - row++; + if (stream->channel_count() == VideoParams::kRGBAChannelCount) { + row++; - video_premultiply_alpha_ = new QCheckBox(tr("Premultiplied Alpha")); - video_premultiply_alpha_->setChecked(stream_->premultiplied_alpha()); - video_layout->addWidget(video_premultiply_alpha_, row, 0, 1, 2); + video_premultiply_alpha_ = new QCheckBox(tr("Premultiplied Alpha")); + video_premultiply_alpha_->setChecked(stream_->premultiplied_alpha()); + video_layout->addWidget(video_premultiply_alpha_, row, 0, 1, 2); + } row++; @@ -130,13 +132,13 @@ void VideoStreamProperties::Accept(QUndoCommand *parent) set_colorspace = video_color_space_->currentText(); } - if (video_premultiply_alpha_->isChecked() != stream_->premultiplied_alpha() + if ((video_premultiply_alpha_ && video_premultiply_alpha_->isChecked() != stream_->premultiplied_alpha()) || set_colorspace != stream_->colorspace(false) || static_cast(video_interlace_combo_->currentIndex()) != stream_->interlacing() || pixel_aspect_combo_->GetPixelAspectRatio() != stream_->pixel_aspect_ratio()) { new VideoStreamChangeCommand(stream_, - video_premultiply_alpha_->isChecked(), + video_premultiply_alpha_ ? video_premultiply_alpha_->isChecked() : stream_->premultiplied_alpha(), set_colorspace, static_cast(video_interlace_combo_->currentIndex()), pixel_aspect_combo_->GetPixelAspectRatio(), @@ -251,4 +253,4 @@ void VideoStreamProperties::ImageSequenceChangeCommand::undo_internal() video_stream_->set_timebase(old_frame_rate_.flipped()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/footageproperties/streamproperties/videostreamproperties.h b/app/dialog/footageproperties/streamproperties/videostreamproperties.h index 2b82b80d1..96416f596 100644 --- a/app/dialog/footageproperties/streamproperties/videostreamproperties.h +++ b/app/dialog/footageproperties/streamproperties/videostreamproperties.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,10 +30,11 @@ #include "widget/slider/integerslider.h" #include "widget/standardcombos/standardcombos.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class VideoStreamProperties : public StreamProperties { + Q_OBJECT public: VideoStreamProperties(VideoStreamPtr stream); @@ -142,6 +143,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // VIDEOSTREAMPROPERTIES_H diff --git a/app/dialog/footagerelink/CMakeLists.txt b/app/dialog/footagerelink/CMakeLists.txt index 3d420d890..74f158922 100644 --- a/app/dialog/footagerelink/CMakeLists.txt +++ b/app/dialog/footagerelink/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/footagerelink/footagerelinkdialog.cpp b/app/dialog/footagerelink/footagerelinkdialog.cpp index eae68b38e..cfdde7fc5 100644 --- a/app/dialog/footagerelink/footagerelinkdialog.cpp +++ b/app/dialog/footagerelink/footagerelinkdialog.cpp @@ -27,7 +27,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { FootageRelinkDialog::FootageRelinkDialog(const QList& footage, QWidget* parent) : QDialog(parent), @@ -100,4 +100,4 @@ void FootageRelinkDialog::BrowseForFootage() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/footagerelink/footagerelinkdialog.h b/app/dialog/footagerelink/footagerelinkdialog.h index 1c9984f9c..b201b6762 100644 --- a/app/dialog/footagerelink/footagerelinkdialog.h +++ b/app/dialog/footagerelink/footagerelinkdialog.h @@ -26,7 +26,7 @@ #include "project/item/footage/footage.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class FootageRelinkDialog : public QDialog { @@ -44,6 +44,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // FOOTAGERELINKDIALOG_H diff --git a/app/dialog/keyframeproperties/CMakeLists.txt b/app/dialog/keyframeproperties/CMakeLists.txt index fc3b399ec..1764bab10 100644 --- a/app/dialog/keyframeproperties/CMakeLists.txt +++ b/app/dialog/keyframeproperties/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/keyframeproperties/keyframeproperties.cpp b/app/dialog/keyframeproperties/keyframeproperties.cpp index 090902cd0..469734cfd 100644 --- a/app/dialog/keyframeproperties/keyframeproperties.cpp +++ b/app/dialog/keyframeproperties/keyframeproperties.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "widget/keyframeview/keyframeviewundo.h" #include "widget/nodeparamview/nodeparamviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { KeyframePropertiesDialog::KeyframePropertiesDialog(const QList &keys, const rational &timebase, QWidget *parent) : QDialog(parent), @@ -240,4 +240,4 @@ void KeyframePropertiesDialog::KeyTypeChanged(int index) bezier_group_->setEnabled(type_select_->itemData(index) == NodeKeyframe::kBezier); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/keyframeproperties/keyframeproperties.h b/app/dialog/keyframeproperties/keyframeproperties.h index fdf9f7076..3ad6145af 100644 --- a/app/dialog/keyframeproperties/keyframeproperties.h +++ b/app/dialog/keyframeproperties/keyframeproperties.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,7 +29,7 @@ #include "widget/slider/floatslider.h" #include "widget/slider/timeslider.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class KeyframePropertiesDialog : public QDialog { @@ -66,6 +66,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // KEYFRAMEPROPERTIESDIALOG_H diff --git a/app/dialog/preferences/CMakeLists.txt b/app/dialog/preferences/CMakeLists.txt index 82201b179..85eaf5822 100644 --- a/app/dialog/preferences/CMakeLists.txt +++ b/app/dialog/preferences/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/preferences/keysequenceeditor.cpp b/app/dialog/preferences/keysequenceeditor.cpp index d0e6645d8..34012ef2f 100644 --- a/app/dialog/preferences/keysequenceeditor.cpp +++ b/app/dialog/preferences/keysequenceeditor.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { KeySequenceEditor::KeySequenceEditor(QWidget* parent, QAction* a) : QKeySequenceEdit(parent), action(a) { @@ -49,4 +49,4 @@ QString KeySequenceEditor::export_shortcut() { return nullptr; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/preferences/keysequenceeditor.h b/app/dialog/preferences/keysequenceeditor.h index b3fc396b9..3231df622 100644 --- a/app/dialog/preferences/keysequenceeditor.h +++ b/app/dialog/preferences/keysequenceeditor.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/debug.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief The KeySequenceEditor class @@ -101,6 +101,6 @@ private: QAction* action; }; -OLIVE_NAMESPACE_EXIT +} #endif // KEYSEQUENCEEDITOR_H diff --git a/app/dialog/preferences/preferences.cpp b/app/dialog/preferences/preferences.cpp index 6ca624c07..c3c34131f 100644 --- a/app/dialog/preferences/preferences.cpp +++ b/app/dialog/preferences/preferences.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -33,7 +33,7 @@ #include "tabs/preferencesaudiotab.h" #include "tabs/preferenceskeyboardtab.h" -OLIVE_NAMESPACE_ENTER +namespace olive { PreferencesDialog::PreferencesDialog(QWidget *parent, QMenuBar* main_menu_bar) : QDialog(parent) @@ -98,4 +98,4 @@ void PreferencesDialog::AddTab(PreferencesTab *tab, const QString &title) tabs_.append(tab); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/preferences/preferences.h b/app/dialog/preferences/preferences.h index 6f97e2e08..e337c3eeb 100644 --- a/app/dialog/preferences/preferences.h +++ b/app/dialog/preferences/preferences.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "tabs/preferencestab.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief The PreferencesDialog class @@ -69,6 +69,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // PREFERENCESDIALOG_H diff --git a/app/dialog/preferences/tabs/CMakeLists.txt b/app/dialog/preferences/tabs/CMakeLists.txt index 62c3270c1..37bfe7a5a 100644 --- a/app/dialog/preferences/tabs/CMakeLists.txt +++ b/app/dialog/preferences/tabs/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/preferences/tabs/preferencesappearancetab.cpp b/app/dialog/preferences/tabs/preferencesappearancetab.cpp index 737821e48..1ad9a6113 100644 --- a/app/dialog/preferences/tabs/preferencesappearancetab.cpp +++ b/app/dialog/preferences/tabs/preferencesappearancetab.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,7 +29,7 @@ #include "node/node.h" #include "widget/colorbutton/colorbutton.h" -OLIVE_NAMESPACE_ENTER +namespace olive { PreferencesAppearanceTab::PreferencesAppearanceTab() { @@ -122,4 +122,4 @@ void PreferencesAppearanceTab::ColorButtonClicked() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/preferences/tabs/preferencesappearancetab.h b/app/dialog/preferences/tabs/preferencesappearancetab.h index 35dc1ffac..6e3e82751 100644 --- a/app/dialog/preferences/tabs/preferencesappearancetab.h +++ b/app/dialog/preferences/tabs/preferencesappearancetab.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "preferencestab.h" #include "ui/style/style.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PreferencesAppearanceTab : public PreferencesTab { @@ -60,6 +60,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // PREFERENCESAPPEARANCETAB_H diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.cpp b/app/dialog/preferences/tabs/preferencesaudiotab.cpp index dfe3536a7..66c34a3d9 100644 --- a/app/dialog/preferences/tabs/preferencesaudiotab.cpp +++ b/app/dialog/preferences/tabs/preferencesaudiotab.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "audio/audiomanager.h" #include "config/config.h" -OLIVE_NAMESPACE_ENTER +namespace olive { PreferencesAudioTab::PreferencesAudioTab() { @@ -206,4 +206,4 @@ void PreferencesAudioTab::PopulateComboBox(QComboBox *cb, bool still_refreshing, } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.h b/app/dialog/preferences/tabs/preferencesaudiotab.h index dcf9252b7..e0cb6fa7b 100644 --- a/app/dialog/preferences/tabs/preferencesaudiotab.h +++ b/app/dialog/preferences/tabs/preferencesaudiotab.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "preferencestab.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PreferencesAudioTab : public PreferencesTab { @@ -79,6 +79,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // PREFERENCESAUDIOTAB_H diff --git a/app/dialog/preferences/tabs/preferencesbehaviortab.cpp b/app/dialog/preferences/tabs/preferencesbehaviortab.cpp index 6713fe81b..79b6d217c 100644 --- a/app/dialog/preferences/tabs/preferencesbehaviortab.cpp +++ b/app/dialog/preferences/tabs/preferencesbehaviortab.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "config/config.h" -OLIVE_NAMESPACE_ENTER +namespace olive { PreferencesBehaviorTab::PreferencesBehaviorTab() { @@ -99,6 +99,11 @@ PreferencesBehaviorTab::PreferencesBehaviorTab() AddItem(tr("Auto-Scale By Default"), QStringLiteral("AutoscaleByDefault"), node_group); + AddItem(tr("Splitting Clips Copies Dependencies"), + QStringLiteral("SplitClipsCopyNodes"), + tr("Multiple clips can share the same nodes. Disable this to automatically share node " + "dependencies among clips when copying or splitting them."), + node_group); } void PreferencesBehaviorTab::Accept() @@ -151,4 +156,4 @@ QTreeWidgetItem *PreferencesBehaviorTab::AddParent(const QString &text, QTreeWid return AddParent(text, QString(), parent); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/preferences/tabs/preferencesbehaviortab.h b/app/dialog/preferences/tabs/preferencesbehaviortab.h index 521f36cb4..997aee0cc 100644 --- a/app/dialog/preferences/tabs/preferencesbehaviortab.h +++ b/app/dialog/preferences/tabs/preferencesbehaviortab.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "preferencestab.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PreferencesBehaviorTab : public PreferencesTab { @@ -48,6 +48,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // PREFERENCESBEHAVIORTAB_H diff --git a/app/dialog/preferences/tabs/preferencesdisktab.cpp b/app/dialog/preferences/tabs/preferencesdisktab.cpp index fef948409..ec1eeefb1 100644 --- a/app/dialog/preferences/tabs/preferencesdisktab.cpp +++ b/app/dialog/preferences/tabs/preferencesdisktab.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,7 +29,7 @@ #include "common/filefunctions.h" -OLIVE_NAMESPACE_ENTER +namespace olive { PreferencesDiskTab::PreferencesDiskTab() { @@ -69,7 +69,7 @@ PreferencesDiskTab::PreferencesDiskTab() cache_behavior_layout->addWidget(new QLabel(tr("Cache Ahead:")), row, 0); cache_ahead_slider_ = new FloatSlider(); - cache_ahead_slider_->SetFormat(tr("%1 seconds")); + cache_ahead_slider_->SetFormat(tr("%1 second(s)")); cache_ahead_slider_->SetMinimum(0); cache_ahead_slider_->SetValue(Config::Current()["DiskCacheAhead"].value().toDouble()); cache_behavior_layout->addWidget(cache_ahead_slider_, row, 1); @@ -78,7 +78,7 @@ PreferencesDiskTab::PreferencesDiskTab() cache_behind_slider_ = new FloatSlider(); cache_behind_slider_->SetMinimum(0); - cache_behind_slider_->SetFormat(tr("%1 seconds")); + cache_behind_slider_->SetFormat(tr("%1 second(s)")); cache_behind_slider_->SetValue(Config::Current()["DiskCacheBehind"].value().toDouble()); cache_behavior_layout->addWidget(cache_behind_slider_, row, 3); @@ -117,4 +117,4 @@ void PreferencesDiskTab::Accept() Config::Current()["DiskCacheAhead"] = QVariant::fromValue(rational::fromDouble(cache_ahead_slider_->GetValue())); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/preferences/tabs/preferencesdisktab.h b/app/dialog/preferences/tabs/preferencesdisktab.h index 5eb7438b7..6f4e45771 100644 --- a/app/dialog/preferences/tabs/preferencesdisktab.h +++ b/app/dialog/preferences/tabs/preferencesdisktab.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "widget/slider/floatslider.h" #include "widget/path/pathwidget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PreferencesDiskTab : public PreferencesTab { @@ -53,6 +53,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // PREFERENCESDISKTAB_H diff --git a/app/dialog/preferences/tabs/preferencesgeneraltab.cpp b/app/dialog/preferences/tabs/preferencesgeneraltab.cpp index 520728c36..aafe93d70 100644 --- a/app/dialog/preferences/tabs/preferencesgeneraltab.cpp +++ b/app/dialog/preferences/tabs/preferencesgeneraltab.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,10 +25,11 @@ #include #include "common/autoscroll.h" +#include "core.h" #include "dialog/sequence/sequence.h" #include "project/item/sequence/sequence.h" -OLIVE_NAMESPACE_ENTER +namespace olive { PreferencesGeneralTab::PreferencesGeneralTab() { @@ -46,34 +47,23 @@ PreferencesGeneralTab::PreferencesGeneralTab() language_combobox_ = new QComboBox(); // Add default language (en-US) - language_combobox_->addItem(QLocale("en_US").nativeLanguageName()); + QDir language_dir(QStringLiteral(":/ts")); + QStringList languages = language_dir.entryList(); + foreach (const QString& l, languages) { + AddLanguage(l); + } - /* - // add languages from file - QList translation_paths = get_language_paths(); + QString current_language = Config::Current()[QStringLiteral("Language")].toString(); + if (current_language.isEmpty()) { + // No configured language, use system language + current_language = QLocale::system().name(); - // iterate through all language search paths - for (int j=0;jaddItem(QLocale(locale_str).nativeLanguageName(), locale_relative_path); - - if (olive::config.language_file == locale_relative_path) { - language_combobox->setCurrentIndex(language_combobox->count() - 1); - } - } - } + // If we don't have a language for this, default to en_US + if (!languages.contains(current_language)) { + current_language = QStringLiteral("en_US"); } - */ + } + language_combobox_->setCurrentIndex(languages.indexOf(current_language)); general_layout->addWidget(language_combobox_, row, 1); @@ -103,7 +93,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() default_still_length_ = new FloatSlider(); default_still_length_->SetMinimum(0.1); - default_still_length_->SetFormat(tr("%1 seconds")); + default_still_length_->SetFormat(tr("%1 second(s)")); default_still_length_->SetValue(Config::Current()["DefaultStillLength"].value().toDouble()); general_layout->addWidget(default_still_length_); @@ -112,11 +102,30 @@ PreferencesGeneralTab::PreferencesGeneralTab() void PreferencesGeneralTab::Accept() { - Config::Current()["RectifiedWaveforms"] = rectified_waveforms_->isChecked(); + Config::Current()[QStringLiteral("RectifiedWaveforms")] = rectified_waveforms_->isChecked(); - Config::Current()["Autoscroll"] = autoscroll_method_->currentData(); + Config::Current()[QStringLiteral("Autoscroll")] = autoscroll_method_->currentData(); - Config::Current()["DefaultStillLength"] = QVariant::fromValue(rational::fromDouble(default_still_length_->GetValue())); + Config::Current()[QStringLiteral("DefaultStillLength")] = QVariant::fromValue(rational::fromDouble(default_still_length_->GetValue())); + + QString set_language = language_combobox_->currentData().toString(); + if (QLocale::system().name() == set_language) { + // Language is set to the system, assume this is effectively "auto" + set_language = QString(); + } + + // If the language has changed, set it now + if (Config::Current()[QStringLiteral("Language")].toString() != set_language) { + Config::Current()[QStringLiteral("Language")] = set_language; + Core::instance()->SetLanguage(set_language.isEmpty() ? QLocale::system().name() : set_language); + } } -OLIVE_NAMESPACE_EXIT +void PreferencesGeneralTab::AddLanguage(const QString &locale_name) +{ + language_combobox_->addItem(tr("%1 (%2)").arg(QLocale(locale_name).nativeLanguageName(), + locale_name));; + language_combobox_->setItemData(language_combobox_->count() - 1, locale_name); +} + +} diff --git a/app/dialog/preferences/tabs/preferencesgeneraltab.h b/app/dialog/preferences/tabs/preferencesgeneraltab.h index 609d182c9..e48123fc6 100644 --- a/app/dialog/preferences/tabs/preferencesgeneraltab.h +++ b/app/dialog/preferences/tabs/preferencesgeneraltab.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,7 +29,7 @@ #include "project/item/sequence/sequence.h" #include "widget/slider/floatslider.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PreferencesGeneralTab : public PreferencesTab { @@ -40,6 +40,8 @@ public: virtual void Accept() override; private: + void AddLanguage(const QString& locale_name); + QComboBox* language_combobox_; QComboBox* autoscroll_method_; @@ -50,6 +52,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // PREFERENCESGENERALTAB_H diff --git a/app/dialog/preferences/tabs/preferenceskeyboardtab.cpp b/app/dialog/preferences/tabs/preferenceskeyboardtab.cpp index f5cbe3da6..22ab4f652 100644 --- a/app/dialog/preferences/tabs/preferenceskeyboardtab.cpp +++ b/app/dialog/preferences/tabs/preferenceskeyboardtab.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { PreferencesKeyboardTab::PreferencesKeyboardTab(QMenuBar *menubar) { @@ -239,4 +239,4 @@ void PreferencesKeyboardTab::save_shortcut_file() { } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/preferences/tabs/preferenceskeyboardtab.h b/app/dialog/preferences/tabs/preferenceskeyboardtab.h index 69b906bd6..723d95e44 100644 --- a/app/dialog/preferences/tabs/preferenceskeyboardtab.h +++ b/app/dialog/preferences/tabs/preferenceskeyboardtab.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "preferencestab.h" #include "../keysequenceeditor.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PreferencesKeyboardTab : public PreferencesTab { @@ -134,6 +134,6 @@ private: QVector key_shortcut_fields_; }; -OLIVE_NAMESPACE_EXIT +} #endif // PREFERENCESKEYBOARDTAB_H diff --git a/app/dialog/preferences/tabs/preferencestab.cpp b/app/dialog/preferences/tabs/preferencestab.cpp index 883f108cb..4dc6d46d8 100644 --- a/app/dialog/preferences/tabs/preferencestab.cpp +++ b/app/dialog/preferences/tabs/preferencestab.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,11 +20,11 @@ #include "preferencestab.h" -OLIVE_NAMESPACE_ENTER +namespace olive { bool PreferencesTab::Validate() { return true; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/preferences/tabs/preferencestab.h b/app/dialog/preferences/tabs/preferencestab.h index 60e83d950..8bfaec15d 100644 --- a/app/dialog/preferences/tabs/preferencestab.h +++ b/app/dialog/preferences/tabs/preferencestab.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "config/config.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PreferencesTab : public QWidget { @@ -37,6 +37,6 @@ public: virtual void Accept() = 0; }; -OLIVE_NAMESPACE_EXIT +} #endif // PREFERENCESTAB_H diff --git a/app/dialog/progress/CMakeLists.txt b/app/dialog/progress/CMakeLists.txt index 99c331702..0acb642e0 100644 --- a/app/dialog/progress/CMakeLists.txt +++ b/app/dialog/progress/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/progress/progress.cpp b/app/dialog/progress/progress.cpp index 011980cb9..3b46c8926 100644 --- a/app/dialog/progress/progress.cpp +++ b/app/dialog/progress/progress.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,10 +27,11 @@ #include "window/mainwindow/mainwindow.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ProgressDialog::ProgressDialog(const QString& message, const QString& title, QWidget *parent) : - QDialog(parent) + QDialog(parent), + show_progress_(true) { if (!title.isEmpty()) { setWindowTitle(title); @@ -56,7 +57,19 @@ ProgressDialog::ProgressDialog(const QString& message, const QString& title, QWi cancel_layout->addStretch(); QPushButton* cancel_btn = new QPushButton(tr("Cancel")); - connect(cancel_btn, &QPushButton::clicked, this, &ProgressDialog::Cancelled); + + // Signal that derivatives can connect to + connect(cancel_btn, &QPushButton::clicked, this, &ProgressDialog::Cancelled, Qt::DirectConnection); + + // Stop updating the elapsed/remaining timers + connect(cancel_btn, &QPushButton::clicked, elapsed_timer_lbl_, &ElapsedCounterWidget::Stop); + + // Disable the button so that users know they don't need to keep clicking it + connect(cancel_btn, &QPushButton::clicked, this, &ProgressDialog::DisableSenderWidget); + + // Prevent the progress bar from continuing to move + connect(cancel_btn, &QPushButton::clicked, this, &ProgressDialog::DisableProgressWidgets); + cancel_layout->addWidget(cancel_btn); cancel_layout->addStretch(); @@ -80,6 +93,10 @@ void ProgressDialog::closeEvent(QCloseEvent *e) void ProgressDialog::SetProgress(double value) { + if (!show_progress_) { + return; + } + int percent = qRound(100.0 * value); bar_->setValue(percent); @@ -101,4 +118,14 @@ void ProgressDialog::ShowErrorMessage(const QString &title, const QString &messa b.exec(); } -OLIVE_NAMESPACE_EXIT +void ProgressDialog::DisableSenderWidget() +{ + static_cast(sender())->setEnabled(false); +} + +void ProgressDialog::DisableProgressWidgets() +{ + show_progress_ = false; +} + +} diff --git a/app/dialog/progress/progress.h b/app/dialog/progress/progress.h index 401afe839..38e2854b1 100644 --- a/app/dialog/progress/progress.h +++ b/app/dialog/progress/progress.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/debug.h" #include "widget/taskview/elapsedcounterwidget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ProgressDialog : public QDialog { @@ -54,8 +54,15 @@ private: ElapsedCounterWidget* elapsed_timer_lbl_; + bool show_progress_; + +private slots: + void DisableSenderWidget(); + + void DisableProgressWidgets(); + }; -OLIVE_NAMESPACE_EXIT +} #endif // PROGRESSDIALOG_H diff --git a/app/dialog/projectproperties/CMakeLists.txt b/app/dialog/projectproperties/CMakeLists.txt index 7763f8c34..b45092bf6 100644 --- a/app/dialog/projectproperties/CMakeLists.txt +++ b/app/dialog/projectproperties/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/projectproperties/projectproperties.cpp b/app/dialog/projectproperties/projectproperties.cpp index 5a8713f5c..7f7414f3f 100644 --- a/app/dialog/projectproperties/projectproperties.cpp +++ b/app/dialog/projectproperties/projectproperties.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,16 +27,15 @@ #include #include #include -#include -namespace OCIO = OCIO_NAMESPACE::v1; #include "common/filefunctions.h" +#include "common/ocioutils.h" #include "config/config.h" #include "core.h" #include "render/colormanager.h" #include "render/diskmanager.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectPropertiesDialog::ProjectPropertiesDialog(Project* p, QWidget *parent) : QDialog(parent), @@ -243,4 +242,4 @@ void ProjectPropertiesDialog::OCIOFilenameUpdated() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/projectproperties/projectproperties.h b/app/dialog/projectproperties/projectproperties.h index 5c0f31347..e861004b8 100644 --- a/app/dialog/projectproperties/projectproperties.h +++ b/app/dialog/projectproperties/projectproperties.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -31,7 +31,7 @@ #include "project/project.h" #include "widget/path/pathwidget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ProjectPropertiesDialog : public QDialog { @@ -68,6 +68,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTPROPERTIESDIALOG_H diff --git a/app/dialog/rendercancel/CMakeLists.txt b/app/dialog/rendercancel/CMakeLists.txt index a9ca563e9..36c3f9cbb 100644 --- a/app/dialog/rendercancel/CMakeLists.txt +++ b/app/dialog/rendercancel/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/rendercancel/rendercancel.cpp b/app/dialog/rendercancel/rendercancel.cpp index d0f3af8a0..29aee8137 100644 --- a/app/dialog/rendercancel/rendercancel.cpp +++ b/app/dialog/rendercancel/rendercancel.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "rendercancel.h" -OLIVE_NAMESPACE_ENTER +namespace olive { RenderCancelDialog::RenderCancelDialog(QWidget *parent) : ProgressDialog(tr("Waiting for workers to finish..."), tr("Renderer"), parent), @@ -79,4 +79,4 @@ void RenderCancelDialog::UpdateProgress() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/rendercancel/rendercancel.h b/app/dialog/rendercancel/rendercancel.h index 75ba0a563..bc6dd72ed 100644 --- a/app/dialog/rendercancel/rendercancel.h +++ b/app/dialog/rendercancel/rendercancel.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "dialog/progress/progress.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class RenderCancelDialog : public ProgressDialog { @@ -54,6 +54,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // RENDERCANCELDIALOG_H diff --git a/app/dialog/richtext/CMakeLists.txt b/app/dialog/richtext/CMakeLists.txt index c434be383..28528c8b5 100644 --- a/app/dialog/richtext/CMakeLists.txt +++ b/app/dialog/richtext/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/richtext/richtext.cpp b/app/dialog/richtext/richtext.cpp index 40f2baabd..a623ed3e1 100644 --- a/app/dialog/richtext/richtext.cpp +++ b/app/dialog/richtext/richtext.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { RichTextDialog::RichTextDialog(QString start, QWidget* parent) : QDialog(parent) @@ -336,4 +336,4 @@ void RichTextDialog::UpdateButtons() */ } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/richtext/richtext.h b/app/dialog/richtext/richtext.h index b3514df4b..479581cb9 100644 --- a/app/dialog/richtext/richtext.h +++ b/app/dialog/richtext/richtext.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "common/define.h" #include "widget/slider/floatslider.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class RichTextDialog : public QDialog { @@ -82,6 +82,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // RICHTEXTDIALOG_H diff --git a/app/dialog/sequence/CMakeLists.txt b/app/dialog/sequence/CMakeLists.txt index d4a05877d..294b9caeb 100644 --- a/app/dialog/sequence/CMakeLists.txt +++ b/app/dialog/sequence/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/sequence/presetmanager.h b/app/dialog/sequence/presetmanager.h index 08f88f89f..1ac467a9e 100644 --- a/app/dialog/sequence/presetmanager.h +++ b/app/dialog/sequence/presetmanager.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -34,7 +34,7 @@ #include "common/filefunctions.h" #include "common/xmlutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Preset { @@ -234,6 +234,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // PRESETMANAGER_H diff --git a/app/dialog/sequence/sequence.cpp b/app/dialog/sequence/sequence.cpp index 3006c2b73..db9e50615 100644 --- a/app/dialog/sequence/sequence.cpp +++ b/app/dialog/sequence/sequence.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -33,7 +33,7 @@ #include "common/rational.h" #include "undo/undostack.h" -OLIVE_NAMESPACE_ENTER +namespace olive { SequenceDialog::SequenceDialog(Sequence* s, Type t, QWidget* parent) : QDialog(parent), @@ -107,13 +107,14 @@ void SequenceDialog::accept() parameter_tab_->GetSelectedVideoHeight(), parameter_tab_->GetSelectedVideoFrameRate().flipped(), parameter_tab_->GetSelectedPreviewFormat(), + VideoParams::kInternalChannelCount, parameter_tab_->GetSelectedVideoPixelAspect(), parameter_tab_->GetSelectedVideoInterlacingMode(), parameter_tab_->GetSelectedPreviewResolution()); AudioParams audio_params = AudioParams(parameter_tab_->GetSelectedAudioSampleRate(), parameter_tab_->GetSelectedAudioChannelLayout(), - SampleFormat::kInternalFormat); + AudioParams::kInternalFormat); if (make_undoable_) { @@ -170,4 +171,4 @@ void SequenceDialog::SequenceParamCommand::undo_internal() sequence_->set_name(old_name_); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/sequence/sequence.h b/app/dialog/sequence/sequence.h index acbe22a0b..947627642 100644 --- a/app/dialog/sequence/sequence.h +++ b/app/dialog/sequence/sequence.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "sequencedialogpresettab.h" #include "undo/undocommand.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A dialog for editing Sequence parameters @@ -133,6 +133,6 @@ private: }; }; -OLIVE_NAMESPACE_EXIT +} #endif // SEQUENCEDIALOG_H diff --git a/app/dialog/sequence/sequencedialogparametertab.cpp b/app/dialog/sequence/sequencedialogparametertab.cpp index 98689b16c..11ea7ea71 100644 --- a/app/dialog/sequence/sequencedialogparametertab.cpp +++ b/app/dialog/sequence/sequencedialogparametertab.cpp @@ -7,7 +7,7 @@ #include "core.h" -OLIVE_NAMESPACE_ENTER +namespace olive { SequenceDialogParameterTab::SequenceDialogParameterTab(Sequence* sequence, QWidget* parent) : QWidget(parent) @@ -74,8 +74,8 @@ SequenceDialogParameterTab::SequenceDialogParameterTab(Sequence* sequence, QWidg preview_resolution_label_ = new QLabel(); preview_layout->addWidget(preview_resolution_label_, row, 2); row++; - preview_layout->addWidget(new QLabel(tr("Format:")), row, 0); - preview_format_field_ = new PixelFormatComboBox(true, true); + preview_layout->addWidget(new QLabel(tr("Quality:")), row, 0); + preview_format_field_ = new PixelFormatComboBox(true); preview_layout->addWidget(preview_format_field_, row, 1, 1, 2); layout->addWidget(preview_group); @@ -133,7 +133,8 @@ void SequenceDialogParameterTab::UpdatePreviewResolutionLabel() { VideoParams test_param(video_width_field_->GetValue(), video_height_field_->GetValue(), - PixelFormat::PIX_FMT_INVALID, + VideoParams::kFormatInvalid, + VideoParams::kInternalChannelCount, rational(1), VideoParams::kInterlaceNone, preview_resolution_field_->currentData().toInt()); @@ -142,4 +143,4 @@ void SequenceDialogParameterTab::UpdatePreviewResolutionLabel() QString::number(test_param.effective_height()))); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/sequence/sequencedialogparametertab.h b/app/dialog/sequence/sequencedialogparametertab.h index 794abe505..dcc1a4b4e 100644 --- a/app/dialog/sequence/sequencedialogparametertab.h +++ b/app/dialog/sequence/sequencedialogparametertab.h @@ -10,7 +10,7 @@ #include "widget/slider/integerslider.h" #include "widget/standardcombos/standardcombos.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SequenceDialogParameterTab : public QWidget { @@ -58,7 +58,7 @@ public: return preview_resolution_field_->GetDivider(); } - PixelFormat::Format GetSelectedPreviewFormat() const + VideoParams::Format GetSelectedPreviewFormat() const { return preview_format_field_->GetPixelFormat(); } @@ -97,6 +97,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // SEQUENCEDIALOGPARAMETERTAB_H diff --git a/app/dialog/sequence/sequencedialogpresettab.cpp b/app/dialog/sequence/sequencedialogpresettab.cpp index 18c9419db..a57852b64 100644 --- a/app/dialog/sequence/sequencedialogpresettab.cpp +++ b/app/dialog/sequence/sequencedialogpresettab.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,19 +30,18 @@ #include #include "common/filefunctions.h" +#include "config/config.h" #include "node/input.h" #include "render/videoparams.h" #include "ui/icons/icons.h" #include "widget/menu/menu.h" -OLIVE_NAMESPACE_ENTER +namespace olive { const int kDataIsPreset = Qt::UserRole; const int kDataPresetIsCustomRole = Qt::UserRole + 1; const int kDataPresetDataRole = Qt::UserRole + 2; -const PixelFormat::Format kDefaultPreviewFormat = PixelFormat::PIX_FMT_RGBA16F; - SequenceDialogPresetTab::SequenceDialogPresetTab(QWidget* parent) : QWidget(parent), PresetManager(this, QStringLiteral("sequencepresets")) @@ -100,6 +99,7 @@ QTreeWidgetItem* SequenceDialogPresetTab::CreateFolder(const QString &name) QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &name, int width, int height, int divider) { + VideoParams::Format default_format = static_cast(Config::Current()["OfflinePixelFormat"].toInt()); QTreeWidgetItem* parent = CreateFolder(name); AddStandardItem(parent, SequencePreset::Create(tr("%1 23.976 FPS").arg(name), width, @@ -110,7 +110,7 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &na 48000, AV_CH_LAYOUT_STEREO, divider, - kDefaultPreviewFormat)); + default_format)); AddStandardItem(parent, SequencePreset::Create(tr("%1 25 FPS").arg(name), width, height, @@ -120,7 +120,7 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &na 48000, AV_CH_LAYOUT_STEREO, divider, - kDefaultPreviewFormat)); + default_format)); AddStandardItem(parent, SequencePreset::Create(tr("%1 29.97 FPS").arg(name), width, height, @@ -130,7 +130,7 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &na 48000, AV_CH_LAYOUT_STEREO, divider, - kDefaultPreviewFormat)); + default_format)); AddStandardItem(parent, SequencePreset::Create(tr("%1 50 FPS").arg(name), width, height, @@ -140,7 +140,7 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &na 48000, AV_CH_LAYOUT_STEREO, divider, - kDefaultPreviewFormat)); + default_format)); AddStandardItem(parent, SequencePreset::Create(tr("%1 59.94 FPS").arg(name), width, height, @@ -150,12 +150,13 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &na 48000, AV_CH_LAYOUT_STEREO, divider, - kDefaultPreviewFormat)); + default_format)); return parent; } QTreeWidgetItem *SequenceDialogPresetTab::CreateSDPresetFolder(const QString &name, int width, int height, const rational& frame_rate, const rational &standard_par, const rational &wide_par, int divider) { + VideoParams::Format default_format = static_cast(Config::Current()["OfflinePixelFormat"].toInt()); QTreeWidgetItem* parent = CreateFolder(name); preset_tree_->addTopLevelItem(parent); AddStandardItem(parent, SequencePreset::Create(tr("%1 Standard").arg(name), @@ -167,7 +168,7 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateSDPresetFolder(const QString &na 48000, AV_CH_LAYOUT_STEREO, divider, - kDefaultPreviewFormat)); + default_format)); AddStandardItem(parent, SequencePreset::Create(tr("%1 Widescreen").arg(name), width, height, @@ -177,7 +178,7 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateSDPresetFolder(const QString &na 48000, AV_CH_LAYOUT_STEREO, divider, - kDefaultPreviewFormat)); + default_format)); return parent; } @@ -294,4 +295,4 @@ void SequenceDialogPresetTab::DeleteSelectedPreset() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/sequence/sequencedialogpresettab.h b/app/dialog/sequence/sequencedialogpresettab.h index a2ef8a95d..c6296673f 100644 --- a/app/dialog/sequence/sequencedialogpresettab.h +++ b/app/dialog/sequence/sequencedialogpresettab.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "presetmanager.h" #include "sequencepreset.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SequenceDialogPresetTab : public QWidget, public PresetManager { @@ -77,6 +77,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // SEQUENCEDIALOGPRESETTAB_H diff --git a/app/dialog/sequence/sequencepreset.h b/app/dialog/sequence/sequencepreset.h index 6b134b8f1..f6fc052b9 100644 --- a/app/dialog/sequence/sequencepreset.h +++ b/app/dialog/sequence/sequencepreset.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,10 +26,9 @@ #include "common/rational.h" #include "common/xmlutils.h" #include "dialog/sequence/presetmanager.h" -#include "render/pixelformat.h" #include "render/videoparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SequencePreset : public Preset { public: @@ -44,7 +43,7 @@ public: int sample_rate, uint64_t channel_layout, int preview_divider, - PixelFormat::Format preview_format) : + VideoParams::Format preview_format) : width_(width), height_(height), frame_rate_(frame_rate), @@ -67,7 +66,7 @@ public: int sample_rate, uint64_t channel_layout, int preview_divider, - PixelFormat::Format preview_format) + VideoParams::Format preview_format) { return std::make_shared(name, width, height, frame_rate, pixel_aspect, interlacing, sample_rate, channel_layout, @@ -96,7 +95,7 @@ public: } else if (reader->name() == QStringLiteral("divider")) { preview_divider_ = reader->readElementText().toInt(); } else if (reader->name() == QStringLiteral("format")) { - preview_format_ = static_cast(reader->readElementText().toInt()); + preview_format_ = static_cast(reader->readElementText().toInt()); } else { reader->skipCurrentElement(); } @@ -157,7 +156,7 @@ public: return preview_divider_; } - PixelFormat::Format preview_format() const + VideoParams::Format preview_format() const { return preview_format_; } @@ -171,10 +170,10 @@ private: int sample_rate_; uint64_t channel_layout_; int preview_divider_; - PixelFormat::Format preview_format_; + VideoParams::Format preview_format_; }; -OLIVE_NAMESPACE_EXIT +} #endif // SEQUENCEPARAM_H diff --git a/app/dialog/task/CMakeLists.txt b/app/dialog/task/CMakeLists.txt index df35aad3a..e387095d8 100644 --- a/app/dialog/task/CMakeLists.txt +++ b/app/dialog/task/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/dialog/task/task.cpp b/app/dialog/task/task.cpp index e3e1f673b..094d91120 100644 --- a/app/dialog/task/task.cpp +++ b/app/dialog/task/task.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { TaskDialog::TaskDialog(Task* task, const QString& title, QWidget *parent) : ProgressDialog(task->GetTitle(), title, parent), @@ -85,4 +85,4 @@ void TaskDialog::TaskFinished() close(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/dialog/task/task.h b/app/dialog/task/task.h index e796ff248..7fbfaa239 100644 --- a/app/dialog/task/task.h +++ b/app/dialog/task/task.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "dialog/progress/progress.h" #include "task/task.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TaskDialog : public ProgressDialog { @@ -77,6 +77,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // TASKDIALOG_H diff --git a/app/main.cpp b/app/main.cpp index 3cfa34db2..4043a53d3 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -48,7 +48,7 @@ extern "C" { int main(int argc, char *argv[]) { // Set up debug handler - qInstallMessageHandler(OLIVE_NAMESPACE::DebugHandler); + qInstallMessageHandler(olive::DebugHandler); // Generate version string QString app_version = APPVERSION; @@ -63,18 +63,16 @@ int main(int argc, char *argv[]) QCoreApplication::setOrganizationName("olivevideoeditor.org"); QCoreApplication::setOrganizationDomain("olivevideoeditor.org"); QCoreApplication::setApplicationName("Olive"); + QGuiApplication::setDesktopFileName("org.olivevideoeditor.Olive"); QCoreApplication::setApplicationVersion(app_version); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)) - QGuiApplication::setDesktopFileName("org.olivevideoeditor.Olive"); -#endif // // Parse command line arguments // - OLIVE_NAMESPACE::Core::CoreParams startup_params; + olive::Core::CoreParams startup_params; CommandLineParser parser; @@ -94,6 +92,12 @@ int main(int argc, char *argv[]) parser.AddOption({QStringLiteral("x"), QStringLiteral("-export")}, QCoreApplication::translate("main", "Export only (No GUI)")); + const CommandLineParser::Option* ts_option = + parser.AddOption({QStringLiteral("-ts")}, + QCoreApplication::translate("main", "Override language with file"), + true, + QCoreApplication::translate("main", "qm-file")); + const CommandLineParser::PositionalArgument* project_argument = parser.AddPositionalArgument(QStringLiteral("project"), QCoreApplication::translate("main", "Project to open on startup")); @@ -113,18 +117,36 @@ int main(int argc, char *argv[]) } if (export_option->IsSet()) { - startup_params.set_run_mode(OLIVE_NAMESPACE::Core::CoreParams::kHeadlessExport); + startup_params.set_run_mode(olive::Core::CoreParams::kHeadlessExport); + } + + if (ts_option->IsSet()) { + if (ts_option->GetSetting().isEmpty()) { + qWarning() << "--ts was set but no translation file was provided"; + } else { + startup_params.set_startup_language(ts_option->GetSetting()); + } } startup_params.set_fullscreen(fullscreen_option->IsSet()); startup_params.set_startup_project(project_argument->GetSetting()); - // Set OpenGL display profile (3.2 Core) + // Set OpenGL display profile QSurfaceFormat format; + + // Tries to cover all bases. If drivers don't support 3.2, they should fallback to the closest + // alternative. Unfortunately Qt doesn't support 3.0-3.1 without DeprecatedFunctions, so we + // declare that too. We also force Qt to not use ANGLE because I've had a lot of problems with it + // so far. + // + // https://bugreports.qt.io/browse/QTBUG-46140 + QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL); format.setVersion(3, 2); - format.setDepthBufferSize(24); format.setProfile(QSurfaceFormat::CoreProfile); + format.setOption(QSurfaceFormat::DeprecatedFunctions); + + format.setDepthBufferSize(24); QSurfaceFormat::setDefaultFormat(format); // Enable application automatically using higher resolution images from icons @@ -133,7 +155,7 @@ int main(int argc, char *argv[]) // Create application instance std::unique_ptr a; - if (startup_params.run_mode() == OLIVE_NAMESPACE::Core::CoreParams::kRunNormal) { + if (startup_params.run_mode() == olive::Core::CoreParams::kRunNormal) { a.reset(new QApplication(argc, argv)); } else { a.reset(new QCoreApplication(argc, argv)); @@ -155,7 +177,8 @@ int main(int argc, char *argv[]) #endif // USE_CRASHPAD // Start core - OLIVE_NAMESPACE::Core c(startup_params); + olive::Core c(startup_params); + c.Start(); int ret = a->exec(); diff --git a/app/node/CMakeLists.txt b/app/node/CMakeLists.txt index 744bc7da9..a39950a51 100644 --- a/app/node/CMakeLists.txt +++ b/app/node/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -16,6 +16,7 @@ add_subdirectory(audio) add_subdirectory(block) +add_subdirectory(distort) add_subdirectory(filter) add_subdirectory(generator) add_subdirectory(input) diff --git a/app/node/audio/CMakeLists.txt b/app/node/audio/CMakeLists.txt index e8bfe8647..e1dfd8173 100644 --- a/app/node/audio/CMakeLists.txt +++ b/app/node/audio/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/audio/pan/CMakeLists.txt b/app/node/audio/pan/CMakeLists.txt index 66384293d..56e7ed226 100644 --- a/app/node/audio/pan/CMakeLists.txt +++ b/app/node/audio/pan/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/audio/pan/pan.cpp b/app/node/audio/pan/pan.cpp index dad795d02..71ae6ea6f 100644 --- a/app/node/audio/pan/pan.cpp +++ b/app/node/audio/pan/pan.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "pan.h" -OLIVE_NAMESPACE_ENTER +namespace olive { PanNode::PanNode() { @@ -28,9 +28,9 @@ PanNode::PanNode() AddInput(samples_input_); panning_input_ = new NodeInput("panning_in", NodeParam::kFloat, 0.0); - panning_input_->set_property("min", -1.0); - panning_input_->set_property("max", 1.0); - panning_input_->set_property("view", "percent"); + panning_input_->setProperty("min", -1.0); + panning_input_->setProperty("max", 1.0); + panning_input_->setProperty("view", QStringLiteral("percent")); AddInput(panning_input_); } @@ -49,7 +49,7 @@ QString PanNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.pan"); } -QList PanNode::Category() const +QVector PanNode::Category() const { return {kCategoryChannels}; } @@ -69,7 +69,7 @@ NodeValueTable PanNode::Value(NodeValueDatabase &value) const NodeValueTable table = value.Merge(); if (job.HasSamples()) { - float pan_volume = job.GetValue(panning_input_).data().toFloat(); + float pan_volume = job.GetValue(panning_input_).data.toFloat(); if (panning_input_->is_static()) { if (!qIsNull(pan_volume) && job.samples()->audio_params().channel_count() == 2) { if (pan_volume > 0) { @@ -114,4 +114,4 @@ void PanNode::Retranslate() panning_input_->set_name(tr("Pan")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/audio/pan/pan.h b/app/node/audio/pan/pan.h index df23f9d0f..e6298fc84 100644 --- a/app/node/audio/pan/pan.h +++ b/app/node/audio/pan/pan.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,10 +23,11 @@ #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PanNode : public Node { + Q_OBJECT public: PanNode(); @@ -34,7 +35,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; virtual NodeValueTable Value(NodeValueDatabase &value) const override; @@ -49,6 +50,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // PANNODE_H diff --git a/app/node/audio/volume/CMakeLists.txt b/app/node/audio/volume/CMakeLists.txt index 6956ebd0c..097f0f14f 100644 --- a/app/node/audio/volume/CMakeLists.txt +++ b/app/node/audio/volume/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/audio/volume/volume.cpp b/app/node/audio/volume/volume.cpp index 4b403118b..20c94b342 100644 --- a/app/node/audio/volume/volume.cpp +++ b/app/node/audio/volume/volume.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,17 +20,17 @@ #include "volume.h" -OLIVE_NAMESPACE_ENTER +namespace olive { VolumeNode::VolumeNode() { - samples_input_ = new NodeInput("samples_in", NodeParam::kSamples); + samples_input_ = new NodeInput(QStringLiteral("samples_in"), NodeParam::kSamples); samples_input_->set_is_keyframable(false); AddInput(samples_input_); - volume_input_ = new NodeInput("volume_in", NodeParam::kFloat, 1.0); - volume_input_->set_property("min", 0.0); - volume_input_->set_property("view", "db"); + volume_input_ = new NodeInput(QStringLiteral("volume_in"), NodeParam::kFloat, 1.0); + volume_input_->setProperty("min", 0.0); + volume_input_->setProperty("view", QStringLiteral("db")); AddInput(volume_input_); } @@ -49,7 +49,7 @@ QString VolumeNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.volume"); } -QList VolumeNode::Category() const +QVector VolumeNode::Category() const { return {kCategoryFilter}; } @@ -81,4 +81,4 @@ void VolumeNode::Retranslate() volume_input_->set_name(tr("Volume")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/audio/volume/volume.h b/app/node/audio/volume/volume.h index e408e3be7..a45aeb340 100644 --- a/app/node/audio/volume/volume.h +++ b/app/node/audio/volume/volume.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,10 +23,11 @@ #include "node/math/math/mathbase.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class VolumeNode : public MathNodeBase { + Q_OBJECT public: VolumeNode(); @@ -34,7 +35,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; virtual NodeValueTable Value(NodeValueDatabase &value) const override; @@ -54,6 +55,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // VOLUMENODE_H diff --git a/app/node/block/CMakeLists.txt b/app/node/block/CMakeLists.txt index 97828e68b..d9d613ebd 100644 --- a/app/node/block/CMakeLists.txt +++ b/app/node/block/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/block/block.cpp b/app/node/block/block.cpp index 68b9779bd..29857d25f 100644 --- a/app/node/block/block.cpp +++ b/app/node/block/block.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "node/output/track/track.h" #include "transition/transition.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Block::Block() : previous_(nullptr), @@ -51,14 +51,14 @@ Block::Block() : speed_input_ = new NodeInput("speed_in", NodeParam::kFloat); speed_input_->set_standard_value(1.0); - speed_input_->set_property(QStringLiteral("view"), QStringLiteral("percent")); + speed_input_->setProperty("view", QStringLiteral("percent")); AddInput(speed_input_); // A block's length must be greater than 0 set_length_and_media_out(1); } -QList Block::Category() const +QVector Block::Category() const { return {kCategoryTimeline}; } @@ -241,9 +241,9 @@ void Block::SaveInternal(QXmlStreamWriter *writer) const } } -QList Block::GetInputsToHash() const +QVector Block::GetInputsToHash() const { - QList inputs = Node::GetInputsToHash(); + QVector inputs = Node::GetInputsToHash(); // Ignore these inputs inputs.removeOne(media_in_input_); @@ -375,4 +375,4 @@ void Block::Hash(QCryptographicHash &, const rational &) const // A block does nothing by default, so we hash nothing } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/block/block.h b/app/node/block/block.h index ca5c700ee..1f4362340 100644 --- a/app/node/block/block.h +++ b/app/node/block/block.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "node/node.h" #include "timeline/timelinecommon.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A Node that represents a block of time, also displayable on a Timeline @@ -43,7 +43,7 @@ public: virtual Type type() const = 0; - virtual QList Category() const override; + virtual QVector Category() const override; const rational& in() const; const rational& out() const; @@ -110,7 +110,7 @@ protected: virtual void SaveInternal(QXmlStreamWriter* writer) const override; - virtual QList GetInputsToHash() const override; + virtual QVector GetInputsToHash() const override; virtual void LengthChangedEvent(const rational& old_length, const rational& new_length, @@ -137,6 +137,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // BLOCK_H diff --git a/app/node/block/clip/CMakeLists.txt b/app/node/block/clip/CMakeLists.txt index 378335849..75cb1845a 100644 --- a/app/node/block/clip/CMakeLists.txt +++ b/app/node/block/clip/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/block/clip/clip.cpp b/app/node/block/clip/clip.cpp index 5143d226c..cc73034e6 100644 --- a/app/node/block/clip/clip.cpp +++ b/app/node/block/clip/clip.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "clip.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ClipBlock::ClipBlock() { @@ -120,4 +120,4 @@ void ClipBlock::Hash(QCryptographicHash &hash, const rational &time) const } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/block/clip/clip.h b/app/node/block/clip/clip.h index 00f6e0ba0..adedaaac6 100644 --- a/app/node/block/clip/clip.h +++ b/app/node/block/clip/clip.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "node/block/block.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief Node that represents a block of Media @@ -61,6 +61,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEBLOCK_H diff --git a/app/node/block/gap/CMakeLists.txt b/app/node/block/gap/CMakeLists.txt index f66cee93c..c4fe85a8c 100644 --- a/app/node/block/gap/CMakeLists.txt +++ b/app/node/block/gap/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/block/gap/gap.cpp b/app/node/block/gap/gap.cpp index 8d0e4fdf6..2312cc539 100644 --- a/app/node/block/gap/gap.cpp +++ b/app/node/block/gap/gap.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "gap.h" -OLIVE_NAMESPACE_ENTER +namespace olive { GapBlock::GapBlock() { @@ -51,4 +51,4 @@ QString GapBlock::Description() const return tr("A time-based node that represents an empty space."); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/block/gap/gap.h b/app/node/block/gap/gap.h index 4eded9d4d..17856c039 100644 --- a/app/node/block/gap/gap.h +++ b/app/node/block/gap/gap.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "node/block/block.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief Node that represents nothing in its respective track for a certain period of time @@ -46,6 +46,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEBLOCK_H diff --git a/app/node/block/transition/CMakeLists.txt b/app/node/block/transition/CMakeLists.txt index 4a380bc81..70a644afa 100644 --- a/app/node/block/transition/CMakeLists.txt +++ b/app/node/block/transition/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/block/transition/crossdissolve/CMakeLists.txt b/app/node/block/transition/crossdissolve/CMakeLists.txt index 25c90ed8e..572ca510f 100644 --- a/app/node/block/transition/crossdissolve/CMakeLists.txt +++ b/app/node/block/transition/crossdissolve/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp b/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp index 2dfe7ace4..c37ac9715 100644 --- a/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp +++ b/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "crossdissolvetransition.h" -OLIVE_NAMESPACE_ENTER +namespace olive { CrossDissolveTransition::CrossDissolveTransition() { @@ -42,7 +42,7 @@ QString CrossDissolveTransition::id() const return QStringLiteral("org.olivevideoeditor.Olive.crossdissolve"); } -QList CrossDissolveTransition::Category() const +QVector CrossDissolveTransition::Category() const { return {kCategoryTransition}; } @@ -56,7 +56,12 @@ ShaderCode CrossDissolveTransition::GetShaderCode(const QString &shader_id) cons { Q_UNUSED(shader_id) - return ShaderCode(Node::ReadFileAsString(":/shaders/crossdissolve.frag"), QString()); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/crossdissolve.frag"), QString()); +} + +void CrossDissolveTransition::ShaderJobEvent(NodeValueDatabase &value, ShaderJob &job) const +{ + job.SetAlphaChannelRequired(true); } void CrossDissolveTransition::SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const @@ -86,4 +91,4 @@ void CrossDissolveTransition::SampleJobEvent(SampleBufferPtr from_samples, Sampl } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/block/transition/crossdissolve/crossdissolvetransition.h b/app/node/block/transition/crossdissolve/crossdissolvetransition.h index e45d1de67..6b93042bf 100644 --- a/app/node/block/transition/crossdissolve/crossdissolvetransition.h +++ b/app/node/block/transition/crossdissolve/crossdissolvetransition.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,10 +23,11 @@ #include "node/block/transition/transition.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class CrossDissolveTransition : public TransitionBlock { + Q_OBJECT public: CrossDissolveTransition(); @@ -34,7 +35,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; //virtual void Retranslate() override; @@ -42,10 +43,12 @@ public: virtual ShaderCode GetShaderCode(const QString& shader_id) const override; protected: + virtual void ShaderJobEvent(NodeValueDatabase& value, ShaderJob& job) const override; + virtual void SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const override; }; -OLIVE_NAMESPACE_EXIT +} #endif // CROSSDISSOLVETRANSITION_H diff --git a/app/node/block/transition/diptocolor/CMakeLists.txt b/app/node/block/transition/diptocolor/CMakeLists.txt index 7eb37f14d..cc19d8c80 100644 --- a/app/node/block/transition/diptocolor/CMakeLists.txt +++ b/app/node/block/transition/diptocolor/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/block/transition/diptocolor/diptocolortransition.cpp b/app/node/block/transition/diptocolor/diptocolortransition.cpp index 816c75011..6925ffa25 100644 --- a/app/node/block/transition/diptocolor/diptocolortransition.cpp +++ b/app/node/block/transition/diptocolor/diptocolortransition.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "diptocolortransition.h" -OLIVE_NAMESPACE_ENTER +namespace olive { DipToColorTransition::DipToColorTransition() { @@ -43,7 +43,7 @@ QString DipToColorTransition::id() const return QStringLiteral("org.olivevideoeditor.Olive.diptocolor"); } -QList DipToColorTransition::Category() const +QVector DipToColorTransition::Category() const { return {kCategoryTransition}; } @@ -57,7 +57,7 @@ ShaderCode DipToColorTransition::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) - return ShaderCode(Node::ReadFileAsString(":/shaders/diptoblack.frag"), QString()); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/diptoblack.frag"), QString()); } void DipToColorTransition::ShaderJobEvent(NodeValueDatabase &value, ShaderJob &job) const @@ -65,4 +65,4 @@ void DipToColorTransition::ShaderJobEvent(NodeValueDatabase &value, ShaderJob &j job.InsertValue(color_input_, value); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/block/transition/diptocolor/diptocolortransition.h b/app/node/block/transition/diptocolor/diptocolortransition.h index 2c19443e1..0f54b272b 100644 --- a/app/node/block/transition/diptocolor/diptocolortransition.h +++ b/app/node/block/transition/diptocolor/diptocolortransition.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,10 +23,11 @@ #include "node/block/transition/transition.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class DipToColorTransition : public TransitionBlock { + Q_OBJECT public: DipToColorTransition(); @@ -34,7 +35,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; virtual ShaderCode GetShaderCode(const QString& shader_id) const override; @@ -47,6 +48,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // DIPTOCOLORTRANSITION_H diff --git a/app/node/block/transition/transition.cpp b/app/node/block/transition/transition.cpp index 3b339f536..eacffe377 100644 --- a/app/node/block/transition/transition.cpp +++ b/app/node/block/transition/transition.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "common/clamp.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TransitionBlock::TransitionBlock() : connected_out_block_(nullptr), @@ -161,15 +161,15 @@ void TransitionBlock::InsertTransitionTimes(AcceleratedJob *job, const double &t { // Provides total transition progress from 0.0 (start) - 1.0 (end) job->InsertValue(QStringLiteral("ove_tprog_all"), - NodeValue(NodeParam::kFloat, GetTotalProgress(time), this)); + ShaderValue(GetTotalProgress(time), NodeParam::kFloat)); // Provides progress of out section from 1.0 (start) - 0.0 (end) job->InsertValue(QStringLiteral("ove_tprog_out"), - NodeValue(NodeParam::kFloat, GetOutProgress(time), this)); + ShaderValue(GetOutProgress(time), NodeParam::kFloat)); // Provides progress of in section from 0.0 (start) - 1.0 (end) job->InsertValue(QStringLiteral("ove_tprog_in"), - NodeValue(NodeParam::kFloat, GetInProgress(time), this)); + ShaderValue(GetInProgress(time), NodeParam::kFloat)); } void TransitionBlock::BlockConnected(NodeEdgePtr edge) @@ -319,4 +319,4 @@ double TransitionBlock::TransformCurve(double linear) const return linear; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/block/transition/transition.h b/app/node/block/transition/transition.h index d8c5c6a39..8a6acca7e 100644 --- a/app/node/block/transition/transition.h +++ b/app/node/block/transition/transition.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,10 +23,11 @@ #include "node/block/block.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TransitionBlock : public Block { + Q_OBJECT public: TransitionBlock(); @@ -90,6 +91,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // TRANSITIONBLOCK_H diff --git a/app/node/input/media/audio/CMakeLists.txt b/app/node/distort/CMakeLists.txt similarity index 87% rename from app/node/input/media/audio/CMakeLists.txt rename to app/node/distort/CMakeLists.txt index e3de8ae0b..0c704b458 100644 --- a/app/node/input/media/audio/CMakeLists.txt +++ b/app/node/distort/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -14,9 +14,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +add_subdirectory(crop) +add_subdirectory(transform) + set(OLIVE_SOURCES ${OLIVE_SOURCES} - node/input/media/audio/audio.h - node/input/media/audio/audio.cpp PARENT_SCOPE ) diff --git a/app/render/backend/CMakeLists.txt b/app/node/distort/crop/CMakeLists.txt similarity index 63% rename from app/render/backend/CMakeLists.txt rename to app/node/distort/crop/CMakeLists.txt index 79650bd7b..e42a61e81 100644 --- a/app/render/backend/CMakeLists.txt +++ b/app/node/distort/crop/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -14,19 +14,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -add_subdirectory(opengl) - set(OLIVE_SOURCES ${OLIVE_SOURCES} - render/backend/colorprocessorcache.h - render/backend/decodercache.h - render/backend/renderbackend.h - render/backend/renderbackend.cpp - render/backend/renderticket.h - render/backend/renderticket.cpp - render/backend/renderticketwatcher.h - render/backend/renderticketwatcher.cpp - render/backend/renderworker.h - render/backend/renderworker.cpp + node/distort/crop/cropdistortnode.cpp + node/distort/crop/cropdistortnode.h PARENT_SCOPE ) diff --git a/app/node/distort/crop/cropdistortnode.cpp b/app/node/distort/crop/cropdistortnode.cpp new file mode 100644 index 000000000..4c7c8b446 --- /dev/null +++ b/app/node/distort/crop/cropdistortnode.cpp @@ -0,0 +1,268 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 "cropdistortnode.h" + +#include "common/lerp.h" + +namespace olive { + +CropDistortNode::CropDistortNode() +{ + texture_input_ = new NodeInput(QStringLiteral("tex_in"), NodeParam::kTexture); + AddInput(texture_input_); + + left_input_ = new NodeInput(QStringLiteral("left_in"), NodeParam::kFloat, 0.0); + left_input_->setProperty("min", 0.0); + left_input_->setProperty("max", 1.0); + left_input_->setProperty("view", QStringLiteral("percent")); + AddInput(left_input_); + + top_input_ = new NodeInput(QStringLiteral("top_in"), NodeParam::kFloat, 0.0); + top_input_->setProperty("min", 0.0); + top_input_->setProperty("max", 1.0); + top_input_->setProperty("view", QStringLiteral("percent")); + AddInput(top_input_); + + right_input_ = new NodeInput(QStringLiteral("right_in"), NodeParam::kFloat, 0.0); + right_input_->setProperty("min", 0.0); + right_input_->setProperty("max", 1.0); + right_input_->setProperty("view", QStringLiteral("percent")); + AddInput(right_input_); + + bottom_input_ = new NodeInput(QStringLiteral("bottom_in"), NodeParam::kFloat, 0.0); + bottom_input_->setProperty("min", 0.0); + bottom_input_->setProperty("max", 1.0); + bottom_input_->setProperty("view", QStringLiteral("percent")); + AddInput(bottom_input_); + + feather_input_ = new NodeInput(QStringLiteral("feather_in"), NodeParam::kFloat, 0.0); + feather_input_->setProperty("min", 0.0); + AddInput(feather_input_); +} + +void CropDistortNode::Retranslate() +{ + texture_input_->set_name(tr("Texture")); + left_input_->set_name(tr("Left")); + top_input_->set_name(tr("Top")); + right_input_->set_name(tr("Right")); + bottom_input_->set_name(tr("Bottom")); + feather_input_->set_name(tr("Feather")); +} + +NodeValueTable CropDistortNode::Value(NodeValueDatabase &value) const +{ + ShaderJob job; + job.InsertValue(texture_input_, value); + job.InsertValue(left_input_, value); + job.InsertValue(top_input_, value); + job.InsertValue(right_input_, value); + job.InsertValue(bottom_input_, value); + job.InsertValue(feather_input_, value); + job.InsertValue(QStringLiteral("resolution_in"), + ShaderValue(value[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")), NodeParam::kVec2)); + job.SetAlphaChannelRequired(true); + + NodeValueTable table = value.Merge(); + + if (!job.GetValue(texture_input_).data.isNull()) { + if (!qIsNull(job.GetValue(left_input_).data.toDouble()) + || !qIsNull(job.GetValue(right_input_).data.toDouble()) + || !qIsNull(job.GetValue(top_input_).data.toDouble()) + || !qIsNull(job.GetValue(bottom_input_).data.toDouble())) { + table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); + } else { + table.Push(NodeParam::kTexture, job.GetValue(texture_input_).data, this); + } + } + + return table; +} + +ShaderCode CropDistortNode::GetShaderCode(const QString &shader_id) const +{ + Q_UNUSED(shader_id) + return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/crop.frag"))); +} + +void CropDistortNode::DrawGizmos(NodeValueDatabase &db, QPainter *p) +{ + QVector2D resolution = db[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")).value(); + + const double handle_radius = GetGizmoHandleRadius(p->transform()); + + p->setPen(QPen(Qt::white, 0)); + + double left_pt = resolution.x() * db[left_input_].Get(NodeParam::kFloat).toDouble(); + double top_pt = resolution.y() * db[top_input_].Get(NodeParam::kFloat).toDouble(); + double right_pt = resolution.x() * (1.0 - db[right_input_].Get(NodeParam::kFloat).toDouble()); + double bottom_pt = resolution.y() * (1.0 - db[bottom_input_].Get(NodeParam::kFloat).toDouble()); + double center_x_pt = lerp(left_pt, right_pt, 0.5); + double center_y_pt = lerp(top_pt, bottom_pt, 0.5); + + gizmo_whole_rect_ = QRectF(left_pt, top_pt, right_pt - left_pt, bottom_pt - top_pt); + p->drawRect(gizmo_whole_rect_); + + gizmo_resize_handle_[kGizmoScaleTopLeft] = CreateGizmoHandleRect(QPointF(left_pt, top_pt), handle_radius); + gizmo_resize_handle_[kGizmoScaleTopCenter] = CreateGizmoHandleRect(QPointF(center_x_pt, top_pt), handle_radius); + gizmo_resize_handle_[kGizmoScaleTopRight] = CreateGizmoHandleRect(QPointF(right_pt, top_pt), handle_radius); + gizmo_resize_handle_[kGizmoScaleBottomLeft] = CreateGizmoHandleRect(QPointF(left_pt, bottom_pt), handle_radius); + gizmo_resize_handle_[kGizmoScaleBottomCenter] = CreateGizmoHandleRect(QPointF(center_x_pt, bottom_pt), handle_radius); + gizmo_resize_handle_[kGizmoScaleBottomRight] = CreateGizmoHandleRect(QPointF(right_pt, bottom_pt), handle_radius); + gizmo_resize_handle_[kGizmoScaleCenterLeft] = CreateGizmoHandleRect(QPointF(left_pt, center_y_pt), handle_radius); + gizmo_resize_handle_[kGizmoScaleCenterRight] = CreateGizmoHandleRect(QPointF(right_pt, center_y_pt), handle_radius); + + p->setPen(Qt::NoPen); + p->setBrush(Qt::white); + DrawAndExpandGizmoHandles(p, handle_radius, gizmo_resize_handle_, kGizmoScaleCount); +} + +bool CropDistortNode::GizmoPress(NodeValueDatabase &db, const QPointF &p) +{ + bool found_handle = false; + + bool gizmo_active[kGizmoScaleCount] = {false}; + + for (int i=0; i kGizmoNone) { + gizmo_res_ = db[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")).value(); + gizmo_drag_start_ = p; + + return true; + } + + return false; +} + +void CropDistortNode::GizmoMove(const QPointF &p, const rational &time) +{ + if (gizmo_dragger_.isEmpty()) { + gizmo_dragger_.resize(gizmo_start_.size()); + + int counter = 0; + + if (gizmo_drag_ & kGizmoLeft) { + gizmo_dragger_[counter].Start(left_input_, time, 0); + counter++; + } + + if (gizmo_drag_ & kGizmoTop) { + gizmo_dragger_[counter].Start(top_input_, time, 0); + counter++; + } + + if (gizmo_drag_ & kGizmoRight) { + gizmo_dragger_[counter].Start(right_input_, time, 0); + counter++; + } + + if (gizmo_drag_ & kGizmoBottom) { + gizmo_dragger_[counter].Start(bottom_input_, time, 0); + counter++; + } + } + + int counter = 0; + + double x_diff = (p.x() - gizmo_drag_start_.x()) / gizmo_res_.x(); + double y_diff = (p.y() - gizmo_drag_start_.y()) / gizmo_res_.y(); + + if (gizmo_drag_ & kGizmoLeft) { + gizmo_dragger_[counter].Drag(gizmo_start_[counter].toDouble() + x_diff); + counter++; + } + + if (gizmo_drag_ & kGizmoTop) { + gizmo_dragger_[counter].Drag(gizmo_start_[counter].toDouble() + y_diff); + counter++; + } + + if (gizmo_drag_ & kGizmoRight) { + gizmo_dragger_[counter].Drag(gizmo_start_[counter].toDouble() - x_diff); + counter++; + } + + if (gizmo_drag_ & kGizmoBottom) { + gizmo_dragger_[counter].Drag(gizmo_start_[counter].toDouble() - y_diff); + counter++; + } +} + +void CropDistortNode::GizmoRelease() +{ + for (NodeInputDragger& i : gizmo_dragger_) { + i.End(); + } + gizmo_dragger_.clear(); + + gizmo_start_.clear(); +} + +} diff --git a/app/node/distort/crop/cropdistortnode.h b/app/node/distort/crop/cropdistortnode.h new file mode 100644 index 000000000..92ece059f --- /dev/null +++ b/app/node/distort/crop/cropdistortnode.h @@ -0,0 +1,111 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 CROPDISTORTNODE_H +#define CROPDISTORTNODE_H + +#include + +#include "node/inputdragger.h" +#include "node/node.h" + +namespace olive { + +class CropDistortNode : public Node +{ +public: + CropDistortNode(); + + virtual Node* copy() const override + { + return new CropDistortNode(); + } + + virtual QString Name() const override + { + return tr("Crop"); + } + + virtual QString id() const override + { + return QStringLiteral("org.olivevideoeditor.Olive.crop"); + } + + virtual QVector Category() const override + { + return {kCategoryDistort}; + } + + virtual QString Description() const override + { + return tr("Crop the edges of an image."); + } + + virtual void Retranslate() override; + + virtual NodeValueTable Value(NodeValueDatabase& value) const override; + + virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + + virtual bool HasGizmos() const override + { + return true; + } + + virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p) override; + + virtual bool GizmoPress(NodeValueDatabase& db, const QPointF &p) override; + virtual void GizmoMove(const QPointF &p, const rational &time) override; + virtual void GizmoRelease() override; + +private: + NodeInput* texture_input_; + + NodeInput* left_input_; + NodeInput* top_input_; + NodeInput* right_input_; + NodeInput* bottom_input_; + + NodeInput* feather_input_; + + // Gizmo variables + QRectF gizmo_resize_handle_[kGizmoScaleCount]; + QRectF gizmo_whole_rect_; + + enum GizmoDragDirection { + kGizmoNone = 0x0, + kGizmoLeft = 0x1, + kGizmoTop = 0x2, + kGizmoRight = 0x4, + kGizmoBottom = 0x8, + kGizmoRectangle = 0xFF + }; + + int gizmo_drag_; + QVector gizmo_dragger_; + QVector gizmo_start_; + QPointF gizmo_drag_start_; + QVector2D gizmo_res_; + +}; + +} + +#endif // CROPDISTORTNODE_H diff --git a/app/node/distort/transform/CMakeLists.txt b/app/node/distort/transform/CMakeLists.txt new file mode 100644 index 000000000..bee2f4649 --- /dev/null +++ b/app/node/distort/transform/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2020 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 . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + node/distort/transform/transformdistortnode.cpp + node/distort/transform/transformdistortnode.h + PARENT_SCOPE +) diff --git a/app/node/distort/transform/transformdistortnode.cpp b/app/node/distort/transform/transformdistortnode.cpp new file mode 100644 index 000000000..46abe9cf4 --- /dev/null +++ b/app/node/distort/transform/transformdistortnode.cpp @@ -0,0 +1,444 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 "transformdistortnode.h" + +#include + +#include "common/range.h" + +namespace olive { + +TransformDistortNode::TransformDistortNode() +{ + autoscale_input_ = new NodeInput(QStringLiteral("autoscale_in"), NodeParam::kCombo, 0); + AddInput(autoscale_input_); + + interpolation_input_ = new NodeInput(QStringLiteral("interpolation_in"), NodeParam::kCombo, 2); + AddInput(interpolation_input_); + + texture_input_ = new NodeInput(QStringLiteral("tex_in"), NodeParam::kTexture); + AddInput(texture_input_); +} + +void TransformDistortNode::Retranslate() +{ + MatrixGenerator::Retranslate(); + + autoscale_input_->set_name(tr("Auto-Scale")); + texture_input_->set_name(tr("Texture")); + interpolation_input_->set_name(tr("Interpolation")); + + autoscale_input_->set_combobox_strings({tr("None"), tr("Fit"), tr("Fill"), tr("Stretch")}); + interpolation_input_->set_combobox_strings({tr("Nearest Neighbor"), tr("Bilinear"), tr("Mipmapped Bilinear")}); +} + +NodeValueTable TransformDistortNode::Value(NodeValueDatabase &value) const +{ + // Generate matrix + QMatrix4x4 generated_matrix = GenerateMatrix(value, true, false, false, false); + + // Pop texture + TexturePtr texture = value[texture_input_].Take(NodeParam::kTexture).value(); + + // Merge table + NodeValueTable table = value.Merge(); + + // If we have a texture, generate a matrix and make it happen + if (texture) { + // Adjust our matrix by the resolutions involved + QVector2D sequence_res = value[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")).value(); + QVector2D texture_res(texture->params().width() * texture->pixel_aspect_ratio().toDouble(), texture->params().height()); + AutoScaleType autoscale = static_cast(value[autoscale_input_].Get(NodeParam::kCombo).toInt()); + + QMatrix4x4 real_matrix = AdjustMatrixByResolutions(generated_matrix, + sequence_res, + texture_res, + autoscale); + + if (real_matrix.isIdentity()) { + // We don't expect any changes, just push as normal + table.Push(NodeParam::kTexture, QVariant::fromValue(texture), this); + } else { + // The matrix will transform things + ShaderJob job; + job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(texture), NodeParam::kTexture)); + job.InsertValue(QStringLiteral("ove_mvpmat"), ShaderValue(real_matrix, NodeParam::kMatrix)); + job.SetInterpolation(QStringLiteral("ove_maintex"), static_cast(value[interpolation_input_].Get(NodeParam::kCombo).toInt())); + + // FIXME: This should be optimized, we can use matrix math to determine if this operation will + // end up with gaps in the screen that will require an alpha channel. + job.SetAlphaChannelRequired(true); + + table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); + } + } + + return table; +} + +ShaderCode TransformDistortNode::GetShaderCode(const QString &shader_id) const +{ + Q_UNUSED(shader_id); + + // Returns default frag and vert shader + return ShaderCode(); +} + +bool TransformDistortNode::GizmoPress(NodeValueDatabase &db, const QPointF &p) +{ + // Store cursor position + gizmo_drag_pos_ = p; + + // Check scaling + bool gizmo_scale_active[kGizmoScaleCount] = {false}; + bool scaling = false; + + for (int i=0; i(); + gizmo_scale_anchor_ = db[anchor_input()].Get(NodeParam::kVec2).value() + texture_sz/2; + + if (gizmo_scale_active[kGizmoScaleTopRight] + || gizmo_scale_active[kGizmoScaleBottomRight] + || gizmo_scale_active[kGizmoScaleCenterRight]) { + // Right handles, flip X axis + gizmo_scale_anchor_.setX(texture_sz.x() - gizmo_scale_anchor_.x()); + } + + if (gizmo_scale_active[kGizmoScaleBottomLeft] + || gizmo_scale_active[kGizmoScaleBottomRight] + || gizmo_scale_active[kGizmoScaleBottomCenter]) { + // Bottom handles, flip Y axis + gizmo_scale_anchor_.setY(texture_sz.y() - gizmo_scale_anchor_.y()); + } + + // Store current matrix + gizmo_matrix_ = GenerateMatrix(db, false, true, true, true); + + return true; + + } else if (gizmo_anchor_pt_.contains(p)) { + + // Dragging the anchor point specifically + gizmo_start_ = {db[anchor_input()].Get(NodeParam::kVec2), + db[position_input()].Get(NodeParam::kVec2)}; + gizmo_drag_ = anchor_input(); + + // Store current matrix + gizmo_matrix_ = GenerateMatrix(db, false, true, true, false); + + return true; + + } else if (gizmo_rect_.containsPoint(p, Qt::OddEvenFill)) { + + // Dragging the main rectangle + gizmo_start_ = {db[position_input()].Get(NodeParam::kVec2)}; + gizmo_drag_ = position_input(); + + return true; + + } else { + + // Dragging rotation + gizmo_start_ = {db[rotation_input()].Get(NodeParam::kFloat)}; + gizmo_drag_ = rotation_input(); + gizmo_start_angle_ = qAtan2(gizmo_drag_pos_.y() - gizmo_anchor_pt_.center().y(), + gizmo_drag_pos_.x() - gizmo_anchor_pt_.center().x()); + + return true; + + } + + return false; +} + +void TransformDistortNode::GizmoMove(const QPointF &p, const rational &time) +{ + QPointF movement = (p - gizmo_drag_pos_); + QVector2D vec_movement(movement); + + if (gizmo_drag_ == anchor_input()) { + + // Dragging the anchor point around + if (gizmo_dragger_.isEmpty()) { + gizmo_dragger_.resize(4); + gizmo_dragger_[0].Start(anchor_input(), time, 0); + gizmo_dragger_[1].Start(anchor_input(), time, 1); + gizmo_dragger_[2].Start(position_input(), time, 0); + gizmo_dragger_[3].Start(position_input(), time, 1); + } + + QVector2D inverted_movement(gizmo_matrix_.toTransform().inverted().map(movement)); + QVector2D anchor_cont = gizmo_start_[0].value() + inverted_movement; + QVector2D position_cont = gizmo_start_[1].value() + vec_movement; + + gizmo_dragger_[0].Drag(anchor_cont.x()); + gizmo_dragger_[1].Drag(anchor_cont.y()); + gizmo_dragger_[2].Drag(position_cont.x()); + gizmo_dragger_[3].Drag(position_cont.y()); + + } else if (gizmo_drag_ == position_input()) { + + // Dragging the main rectangle around + if (gizmo_dragger_.isEmpty()) { + gizmo_dragger_.resize(2); + gizmo_dragger_[0].Start(position_input(), time, 0); + gizmo_dragger_[1].Start(position_input(), time, 1); + } + + QVector2D position_cont = gizmo_start_[0].value() + vec_movement; + + gizmo_dragger_[0].Drag(position_cont.x()); + gizmo_dragger_[1].Drag(position_cont.y()); + + } else if (gizmo_drag_ == scale_input()) { + + // Dragging a resize handle + if (gizmo_dragger_.isEmpty()) { + if (gizmo_scale_uniform_ || gizmo_scale_axes_ == kGizmoScaleXOnly) { + gizmo_dragger_.resize(1); + gizmo_dragger_[0].Start(scale_input(), time, 0); + } else if (gizmo_scale_axes_ == kGizmoScaleYOnly) { + gizmo_dragger_.resize(1); + gizmo_dragger_[0].Start(scale_input(), time, 1); + } else { + gizmo_dragger_.resize(2); + gizmo_dragger_[0].Start(scale_input(), time, 0); + gizmo_dragger_[1].Start(scale_input(), time, 1); + } + } + + QPointF mouse_relative = gizmo_matrix_.toTransform().inverted().map(QPointF(p - gizmo_anchor_pt_.center())); + + double x_scaled_movement = qAbs(mouse_relative.x() / gizmo_scale_anchor_.x()); + double y_scaled_movement = qAbs(mouse_relative.y() / gizmo_scale_anchor_.y()); + + switch (gizmo_scale_axes_) { + case kGizmoScaleXOnly: + gizmo_dragger_[0].Drag(x_scaled_movement); + break; + case kGizmoScaleYOnly: + gizmo_dragger_[0].Drag(y_scaled_movement); + break; + case kGizmoScaleBoth: + if (gizmo_scale_uniform_) { + double distance = std::hypot(mouse_relative.x(), mouse_relative.y()); + double texture_diag = std::hypot(gizmo_scale_anchor_.x(), gizmo_scale_anchor_.y()); + + gizmo_dragger_[0].Drag(qAbs(distance / texture_diag)); + } else { + gizmo_dragger_[0].Drag(x_scaled_movement); + gizmo_dragger_[1].Drag(y_scaled_movement); + } + break; + } + + } else if (gizmo_drag_ == rotation_input()) { + + // Dragging outside the rectangle to rotate + if (gizmo_dragger_.isEmpty()) { + gizmo_dragger_.resize(1); + gizmo_dragger_[0].Start(rotation_input(), time, 0); + } + + double current_angle = qAtan2(p.y() - gizmo_anchor_pt_.center().y(), + p.x() - gizmo_anchor_pt_.center().x()); + + double rotation_difference = (current_angle - gizmo_start_angle_) * 57.2958; + + double rotation_cont = gizmo_start_[0].toDouble() + rotation_difference; + + gizmo_dragger_[0].Drag(rotation_cont); + + } +} + +void TransformDistortNode::GizmoRelease() +{ + for (NodeInputDragger& i : gizmo_dragger_) { + i.End(); + } + gizmo_dragger_.clear(); + + gizmo_start_.clear(); + + gizmo_drag_ = nullptr; +} + +QMatrix4x4 TransformDistortNode::AdjustMatrixByResolutions(const QMatrix4x4 &mat, const QVector2D &sequence_res, const QVector2D &texture_res, AutoScaleType autoscale_type) +{ + // First, create an identity matrix + QMatrix4x4 adjusted_matrix; + + // Scale it to a square based on the sequence's resolution + adjusted_matrix.scale(2.0 / sequence_res.x(), 2.0 / sequence_res.y(), 1.0); + + // Adjust by the matrix we generated earlier + adjusted_matrix *= mat; + + // Scale back out to texture size (adjusted by pixel aspect) + adjusted_matrix.scale(texture_res.x() * 0.5, texture_res.y() * 0.5, 1.0); + + // If auto-scale is enabled, fit the texture to the sequence (without cropping) + if (autoscale_type != kAutoScaleNone) { + if (autoscale_type == kAutoScaleStretch) { + adjusted_matrix.scale(sequence_res.x() / texture_res.x(), + sequence_res.y() / texture_res.y(), + 1.0); + } else { + double footage_real_ar = texture_res.x() / texture_res.y(); + double sequence_real_ar = sequence_res.x() / sequence_res.y(); + + double scale_by_x = sequence_res.x() / texture_res.x(); + double scale_by_y = sequence_res.y() / texture_res.y(); + double autoscale_val; + + if ((autoscale_type == kAutoScaleFit) == (sequence_real_ar > footage_real_ar)) { + // Scale by height. Either the sequence is wider than the footage or we're using fill and + // cutting off the sides + autoscale_val = scale_by_y; + } else { + // Scale by width. Either the footage is wider than the sequence or we're using fill and + // cutting off the top and bottom + autoscale_val = scale_by_x; + } + + adjusted_matrix.scale(autoscale_val, autoscale_val, 1.0); + } + } + + return adjusted_matrix; +} + +QPointF TransformDistortNode::CreateScalePoint(double x, double y, const QPointF &half_res, const QMatrix4x4 &mat) +{ + return mat.map(QPointF(x, y)) + half_res; +} + +void TransformDistortNode::DrawGizmos(NodeValueDatabase &db, QPainter *p) +{ + // 0 pen width is always 1px wide despite any transform + p->setPen(QPen(Qt::white, 0)); + + // Get the sequence resolution + QVector2D sequence_res = db[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")).value(); + QVector2D sequence_half_res = sequence_res/2; + QPointF sequence_half_res_pt = sequence_half_res.toPointF(); + + // GizmoTraverser just returns the sizes of the textures and no other data + QVector2D tex_sz = db[texture_input_].Get(NodeParam::kTexture).value(); + + // Retrieve autoscale value + AutoScaleType autoscale = static_cast(db[autoscale_input_].Get(NodeParam::kCombo).toInt()); + + // Fold values into a matrix for the rectangle + QMatrix4x4 rectangle_matrix; + rectangle_matrix.scale(sequence_half_res); + rectangle_matrix *= AdjustMatrixByResolutions(GenerateMatrix(db, false, false, false, false), + sequence_res, + tex_sz, + autoscale); + + // Create rect and transform it + const QVector points = {QPointF(-1, -1), + QPointF(1, -1), + QPointF(1, 1), + QPointF(-1, 1), + QPointF(-1, -1)}; + QTransform rectangle_transform = rectangle_matrix.toTransform(); + gizmo_rect_ = rectangle_transform.map(points); + gizmo_rect_.translate(sequence_half_res_pt); + + // Draw rectangle + p->drawPolyline(gizmo_rect_); + + // Get handle size (relative to screen space rather than buffer space) + const double resize_handle_rad = GetGizmoHandleRadius(p->transform()); + + // Draw anchor point + QMatrix4x4 anchor_matrix; + anchor_matrix.scale(sequence_half_res); + anchor_matrix *= AdjustMatrixByResolutions(GenerateMatrix(db, false, true, false, false), + sequence_res, + tex_sz, + autoscale); + QPointF anchor_pt = anchor_matrix.toTransform().map(QPointF(0, 0)) + sequence_half_res_pt; + const double anchor_pt_radius = resize_handle_rad * 2; + + gizmo_anchor_pt_ = QRectF(anchor_pt.x() - anchor_pt_radius, + anchor_pt.y() - anchor_pt_radius, + anchor_pt_radius*2, + anchor_pt_radius*2); + + p->drawEllipse(anchor_pt, anchor_pt_radius, anchor_pt_radius); + + p->drawLines({QLineF(anchor_pt.x() - anchor_pt_radius, anchor_pt.y(), + anchor_pt.x() + anchor_pt_radius, anchor_pt.y()), + QLineF(anchor_pt.x(), anchor_pt.y() - anchor_pt_radius, + anchor_pt.x(), anchor_pt.y() + anchor_pt_radius)}); + + // Draw scale handles + p->setPen(Qt::NoPen); + p->setBrush(Qt::white); + + gizmo_resize_handle_[kGizmoScaleTopLeft] = CreateGizmoHandleRect(CreateScalePoint(-1, -1, sequence_half_res_pt, rectangle_matrix), resize_handle_rad); + gizmo_resize_handle_[kGizmoScaleTopCenter] = CreateGizmoHandleRect(CreateScalePoint( 0, -1, sequence_half_res_pt, rectangle_matrix), resize_handle_rad); + gizmo_resize_handle_[kGizmoScaleTopRight] = CreateGizmoHandleRect(CreateScalePoint( 1, -1, sequence_half_res_pt, rectangle_matrix), resize_handle_rad); + gizmo_resize_handle_[kGizmoScaleBottomLeft] = CreateGizmoHandleRect(CreateScalePoint(-1, 1, sequence_half_res_pt, rectangle_matrix), resize_handle_rad); + gizmo_resize_handle_[kGizmoScaleBottomCenter] = CreateGizmoHandleRect(CreateScalePoint( 0, 1, sequence_half_res_pt, rectangle_matrix), resize_handle_rad); + gizmo_resize_handle_[kGizmoScaleBottomRight] = CreateGizmoHandleRect(CreateScalePoint( 1, 1, sequence_half_res_pt, rectangle_matrix), resize_handle_rad); + gizmo_resize_handle_[kGizmoScaleCenterLeft] = CreateGizmoHandleRect(CreateScalePoint(-1, 0, sequence_half_res_pt, rectangle_matrix), resize_handle_rad); + gizmo_resize_handle_[kGizmoScaleCenterRight] = CreateGizmoHandleRect(CreateScalePoint( 1, 0, sequence_half_res_pt, rectangle_matrix), resize_handle_rad); + + DrawAndExpandGizmoHandles(p, resize_handle_rad, gizmo_resize_handle_, kGizmoScaleCount); + + // Use offsets to make the appearance of values that start in the top left, even though we + // really anchor around the center + position_input()->setProperty("offset", sequence_res * 0.5); + anchor_input()->setProperty("offset", tex_sz * 0.5); +} + +} diff --git a/app/node/distort/transform/transformdistortnode.h b/app/node/distort/transform/transformdistortnode.h new file mode 100644 index 000000000..5002db06b --- /dev/null +++ b/app/node/distort/transform/transformdistortnode.h @@ -0,0 +1,132 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 TRANSFORMDISTORTNODE_H +#define TRANSFORMDISTORTNODE_H + +#include "node/generator/matrix/matrix.h" + +namespace olive { + +class TransformDistortNode : public MatrixGenerator +{ + Q_OBJECT +public: + TransformDistortNode(); + + virtual Node* copy() const override + { + return new TransformDistortNode(); + } + + virtual QString Name() const override + { + return tr("Transform"); + } + + virtual QString ShortName() const override + { + return Node::ShortName(); + } + + virtual QString id() const override + { + return QStringLiteral("org.olivevideoeditor.Olive.transform"); + } + + virtual QVector Category() const override + { + return {kCategoryDistort}; + } + + virtual QString Description() const override + { + return tr("Transform an image in 2D space. Equivalent to multiplying by an orthographic matrix."); + } + + virtual void Retranslate() override; + + virtual NodeValueTable Value(NodeValueDatabase& value) const override; + + virtual ShaderCode GetShaderCode(const QString& shader_id) const override; + + virtual bool HasGizmos() const override + { + return true; + } + + virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p) override; + + virtual bool GizmoPress(NodeValueDatabase& db, const QPointF &p) override; + virtual void GizmoMove(const QPointF &p, const rational &time) override; + virtual void GizmoRelease() override; + + NodeInput* texture_input() const + { + return texture_input_; + } + + enum AutoScaleType { + kAutoScaleNone, + kAutoScaleFit, + kAutoScaleFill, + kAutoScaleStretch + }; + + static QMatrix4x4 AdjustMatrixByResolutions(const QMatrix4x4& mat, + const QVector2D& sequence_res, + const QVector2D& texture_res, + AutoScaleType autoscale_type = kAutoScaleNone); + +private: + static QPointF CreateScalePoint(double x, double y, const QPointF& half_res, const QMatrix4x4& mat); + + NodeInput* texture_input_; + NodeInput* autoscale_input_; + NodeInput* interpolation_input_; + + // Gizmo variables + NodeInput* gizmo_drag_; + QVector gizmo_start_; + QVector gizmo_dragger_; + QPointF gizmo_drag_pos_; + double gizmo_start_angle_; + bool gizmo_scale_uniform_; + + enum GizmoScaleType { + kGizmoScaleXOnly, + kGizmoScaleYOnly, + kGizmoScaleBoth + }; + + GizmoScaleType gizmo_scale_axes_; + QMatrix4x4 gizmo_matrix_; + QVector2D gizmo_scale_anchor_; + + // Gizmo on screen object storage + QPolygonF gizmo_rect_; + QRectF gizmo_anchor_pt_; + QRectF gizmo_resize_handle_[kGizmoScaleCount]; + +}; + +} + +#endif // TRANSFORMDISTORTNODE_H diff --git a/app/node/edge.cpp b/app/node/edge.cpp index 5f009b8f3..ed6f8efbe 100644 --- a/app/node/edge.cpp +++ b/app/node/edge.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "node.h" #include "output.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeEdge::NodeEdge(NodeOutput *output, NodeInput *input) { @@ -47,4 +47,4 @@ NodeEdge::Connection NodeEdge::ParamToConnection(NodeParam *param) return {param->parentNode(), param->id()}; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/edge.h b/app/node/edge.h index a79b8aec7..a3f377741 100644 --- a/app/node/edge.h +++ b/app/node/edge.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Node; class NodeInput; @@ -82,6 +82,6 @@ private: using NodeEdgePtr = std::shared_ptr; -OLIVE_NAMESPACE_EXIT +} #endif // EDGE_H diff --git a/app/node/factory.cpp b/app/node/factory.cpp index 7c389f443..1d29bf6a1 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,14 +26,16 @@ #include "block/gap/gap.h" #include "block/transition/crossdissolve/crossdissolvetransition.h" #include "block/transition/diptocolor/diptocolortransition.h" +#include "distort/crop/cropdistortnode.h" +#include "distort/transform/transformdistortnode.h" #include "generator/matrix/matrix.h" #include "generator/polygon/polygon.h" #include "generator/solid/solid.h" #include "generator/text/text.h" #include "filter/blur/blur.h" +#include "filter/mosaic/mosaicfilternode.h" #include "filter/stroke/stroke.h" -#include "input/media/video/video.h" -#include "input/media/audio/audio.h" +#include "input/media/media.h" #include "input/time/timeinput.h" #include "math/math/math.h" #include "math/merge/merge.h" @@ -41,7 +43,7 @@ #include "output/track/track.h" #include "output/viewer/viewer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { QList NodeFactory::library_; void NodeFactory::Initialize() @@ -183,10 +185,10 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id) return new PolygonGenerator(); case kMatrixGenerator: return new MatrixGenerator(); - case kVideoInput: - return new VideoInput(); - case kAudioInput: - return new AudioInput(); + case kTransformDistort: + return new TransformDistortNode(); + case kFootageInput: + return new MediaInput(); case kTrackOutput: return new TrackOutput(); case kViewerOutput: @@ -215,6 +217,10 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id) return new CrossDissolveTransition(); case kDipToColorTransition: return new DipToColorTransition(); + case kMosaicFilter: + return new MosaicFilterNode(); + case kCropDistort: + return new CropDistortNode(); case kInternalNodeCount: break; @@ -224,4 +230,4 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id) abort(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/factory.h b/app/node/factory.h index 6025070ef..4ab3c43d6 100644 --- a/app/node/factory.h +++ b/app/node/factory.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "node.h" #include "widget/menu/menu.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeFactory { @@ -35,10 +35,10 @@ public: kViewerOutput, kClipBlock, kGapBlock, - kAudioInput, kPolygonGenerator, kMatrixGenerator, - kVideoInput, + kTransformDistort, + kFootageInput, kTrackOutput, kAudioVolume, kAudioPanning, @@ -52,6 +52,8 @@ public: kTextGenerator, kCrossDissolveTransition, kDipToColorTransition, + kMosaicFilter, + kCropDistort, // Count value kInternalNodeCount @@ -80,6 +82,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEFACTORY_H diff --git a/app/node/filter/CMakeLists.txt b/app/node/filter/CMakeLists.txt index 4d7db901d..95e7ce21c 100644 --- a/app/node/filter/CMakeLists.txt +++ b/app/node/filter/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -15,6 +15,7 @@ # along with this program. If not, see . add_subdirectory(blur) +add_subdirectory(mosaic) add_subdirectory(stroke) set(OLIVE_SOURCES diff --git a/app/node/filter/blur/CMakeLists.txt b/app/node/filter/blur/CMakeLists.txt index 50bd90ad5..a63449699 100644 --- a/app/node/filter/blur/CMakeLists.txt +++ b/app/node/filter/blur/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/filter/blur/blur.cpp b/app/node/filter/blur/blur.cpp index 7950f77e9..70e07d79f 100644 --- a/app/node/filter/blur/blur.cpp +++ b/app/node/filter/blur/blur.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "blur.h" -OLIVE_NAMESPACE_ENTER +namespace olive { BlurFilterNode::BlurFilterNode() { @@ -31,7 +31,7 @@ BlurFilterNode::BlurFilterNode() AddInput(method_input_); radius_input_ = new NodeInput("radius_in", NodeParam::kFloat, 10.0f); - radius_input_->set_property(QStringLiteral("min"), 0.0f); + radius_input_->setProperty("min", 0.0f); AddInput(radius_input_); horiz_input_ = new NodeInput("horiz_in", NodeParam::kBoolean, true); @@ -59,7 +59,7 @@ QString BlurFilterNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.blur"); } -QList BlurFilterNode::Category() const +QVector BlurFilterNode::Category() const { return {kCategoryFilter}; } @@ -83,7 +83,7 @@ void BlurFilterNode::Retranslate() ShaderCode BlurFilterNode::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) - return ShaderCode(ReadFileAsString(":/shaders/blur.frag"), QString()); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/blur.frag")); } NodeValueTable BlurFilterNode::Value(NodeValueDatabase &value) const @@ -96,23 +96,25 @@ NodeValueTable BlurFilterNode::Value(NodeValueDatabase &value) const job.InsertValue(horiz_input_, value); job.InsertValue(vert_input_, value); job.InsertValue(repeat_edge_pixels_input_, value); + job.InsertValue(QStringLiteral("resolution_in"), + ShaderValue(value[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")), NodeParam::kVec2)); NodeValueTable table = value.Merge(); // If there's no texture, no need to run an operation - if (!job.GetValue(texture_input_).data().isNull()) { + if (!job.GetValue(texture_input_).data.isNull()) { // Check if radius > 0, and both "horiz" and/or "vert" are enabled - if ((job.GetValue(horiz_input_).data().toBool() || job.GetValue(vert_input_).data().toBool()) - && job.GetValue(radius_input_).data().toDouble() > 0.0) { + if ((job.GetValue(horiz_input_).data.toBool() || job.GetValue(vert_input_).data.toBool()) + && job.GetValue(radius_input_).data.toDouble() > 0.0) { // Set iteration count to 2 if we're blurring both horizontally and vertically - if (job.GetValue(horiz_input_).data().toBool() && job.GetValue(vert_input_).data().toBool()) { + if (job.GetValue(horiz_input_).data.toBool() && job.GetValue(vert_input_).data.toBool()) { job.SetIterations(2, texture_input_); } // If we're not repeating pixels, expect an alpha channel to appear - if (!job.GetValue(repeat_edge_pixels_input_).data().toBool()) { + if (!job.GetValue(repeat_edge_pixels_input_).data.toBool()) { job.SetAlphaChannelRequired(true); } @@ -120,7 +122,7 @@ NodeValueTable BlurFilterNode::Value(NodeValueDatabase &value) const } else { // If we're not performing the blur job, just push the texture - table.Push(job.GetValue(texture_input_)); + table.Push(job.GetValue(texture_input_), this); } } @@ -128,4 +130,4 @@ NodeValueTable BlurFilterNode::Value(NodeValueDatabase &value) const return table; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/filter/blur/blur.h b/app/node/filter/blur/blur.h index 6f9100605..7a121a34b 100644 --- a/app/node/filter/blur/blur.h +++ b/app/node/filter/blur/blur.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,10 +23,11 @@ #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class BlurFilterNode : public Node { + Q_OBJECT public: BlurFilterNode(); @@ -34,7 +35,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; virtual void Retranslate() override; @@ -57,6 +58,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // BLURFILTERNODE_H diff --git a/app/node/filter/mosaic/CMakeLists.txt b/app/node/filter/mosaic/CMakeLists.txt new file mode 100644 index 000000000..17c75fa7e --- /dev/null +++ b/app/node/filter/mosaic/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2020 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 . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + node/filter/mosaic/mosaicfilternode.h + node/filter/mosaic/mosaicfilternode.cpp + PARENT_SCOPE +) diff --git a/app/node/filter/mosaic/mosaicfilternode.cpp b/app/node/filter/mosaic/mosaicfilternode.cpp new file mode 100644 index 000000000..b1e633b63 --- /dev/null +++ b/app/node/filter/mosaic/mosaicfilternode.cpp @@ -0,0 +1,81 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 "mosaicfilternode.h" + +namespace olive { + +MosaicFilterNode::MosaicFilterNode() +{ + tex_input_ = new NodeInput(QStringLiteral("tex_in"), NodeParam::kTexture); + AddInput(tex_input_); + + horiz_input_ = new NodeInput(QStringLiteral("horiz_in"), NodeParam::kFloat, 32.0); + horiz_input_->setProperty("min", 1.0); + AddInput(horiz_input_); + + vert_input_ = new NodeInput(QStringLiteral("vert_in"), NodeParam::kFloat, 18.0); + vert_input_->setProperty("min", 1.0); + AddInput(vert_input_); +} + +void MosaicFilterNode::Retranslate() +{ + tex_input_->set_name(tr("Texture")); + horiz_input_->set_name(tr("Horizontal")); + vert_input_->set_name(tr("Vertical")); +} + +NodeValueTable MosaicFilterNode::Value(NodeValueDatabase &value) const +{ + ShaderJob job; + + job.InsertValue(tex_input_, value); + job.InsertValue(horiz_input_, value); + job.InsertValue(vert_input_, value); + + // Mipmapping makes this look weird, so we just use bilinear for finding the color of each block + job.SetInterpolation(tex_input_, Texture::kLinear); + + NodeValueTable table = value.Merge(); + + if (!job.GetValue(tex_input_).data.isNull()) { + TexturePtr texture = job.GetValue(tex_input_).data.value(); + + if (texture + && job.GetValue(horiz_input_).data.toInt() != texture->width() + && job.GetValue(vert_input_).data.toInt() != texture->height()) { + table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); + } else { + table.Push(job.GetValue(tex_input_), this); + } + } + + return table; +} + +ShaderCode MosaicFilterNode::GetShaderCode(const QString &shader_id) const +{ + Q_UNUSED(shader_id) + + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/mosaic.frag")); +} + +} diff --git a/app/node/filter/mosaic/mosaicfilternode.h b/app/node/filter/mosaic/mosaicfilternode.h new file mode 100644 index 000000000..104e05b31 --- /dev/null +++ b/app/node/filter/mosaic/mosaicfilternode.h @@ -0,0 +1,75 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 MOSAICFILTERNODE_H +#define MOSAICFILTERNODE_H + +#include "node/node.h" + +namespace olive { + +class MosaicFilterNode : public Node +{ + Q_OBJECT +public: + MosaicFilterNode(); + + virtual Node* copy() const override + { + return new MosaicFilterNode(); + } + + virtual QString Name() const override + { + return tr("Mosaic"); + } + + virtual QString id() const override + { + return QStringLiteral("org.olivevideoeditor.Olive.mosaicfilter"); + } + + virtual QVector Category() const override + { + return {kCategoryFilter}; + } + + virtual QString Description() const override + { + return tr("Apply a pixelated mosaic filter to video."); + } + + virtual void Retranslate() override; + + virtual NodeValueTable Value(NodeValueDatabase &value) const override; + virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + +private: + NodeInput* tex_input_; + + NodeInput* horiz_input_; + + NodeInput* vert_input_; + +}; + +} + +#endif // MOSAICFILTERNODE_H diff --git a/app/node/filter/stroke/CMakeLists.txt b/app/node/filter/stroke/CMakeLists.txt index 212f3bfe2..a28916ea5 100644 --- a/app/node/filter/stroke/CMakeLists.txt +++ b/app/node/filter/stroke/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/filter/stroke/stroke.cpp b/app/node/filter/stroke/stroke.cpp index d62c99b37..edc74b4c5 100644 --- a/app/node/filter/stroke/stroke.cpp +++ b/app/node/filter/stroke/stroke.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "render/color.h" -OLIVE_NAMESPACE_ENTER +namespace olive { StrokeFilterNode::StrokeFilterNode() { @@ -35,13 +35,13 @@ StrokeFilterNode::StrokeFilterNode() AddInput(color_input_); radius_input_ = new NodeInput("radius_in", NodeParam::kFloat, 10.0f); - radius_input_->set_property("min", 0.0f); + radius_input_->setProperty("min", 0.0f); AddInput(radius_input_); opacity_input_ = new NodeInput("opacity_in", NodeParam::kFloat, 1.0f); - opacity_input_->set_property("view", "percent"); - opacity_input_->set_property("min", 0.0f); - opacity_input_->set_property("max", 1.0f); + opacity_input_->setProperty("view", QStringLiteral("percent")); + opacity_input_->setProperty("min", 0.0f); + opacity_input_->setProperty("max", 1.0f); AddInput(opacity_input_); inner_input_ = new NodeInput("inner_in", NodeParam::kBoolean, false); @@ -63,7 +63,7 @@ QString StrokeFilterNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.stroke"); } -QList StrokeFilterNode::Category() const +QVector StrokeFilterNode::Category() const { return {kCategoryFilter}; } @@ -91,15 +91,17 @@ NodeValueTable StrokeFilterNode::Value(NodeValueDatabase &value) const job.InsertValue(radius_input_, value); job.InsertValue(opacity_input_, value); job.InsertValue(inner_input_, value); + job.InsertValue(QStringLiteral("resolution_in"), + ShaderValue(value[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")), NodeParam::kVec2)); NodeValueTable table = value.Merge(); - if (!job.GetValue(tex_input_).data().isNull()) { - if (job.GetValue(radius_input_).data().toDouble() > 0.0 - && job.GetValue(opacity_input_).data().toDouble() > 0.0) { + if (!job.GetValue(tex_input_).data.isNull()) { + if (job.GetValue(radius_input_).data.toDouble() > 0.0 + && job.GetValue(opacity_input_).data.toDouble() > 0.0) { table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); } else { - table.Push(job.GetValue(tex_input_)); + table.Push(job.GetValue(tex_input_), this); } } @@ -110,7 +112,7 @@ ShaderCode StrokeFilterNode::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) - return ShaderCode(ReadFileAsString(":/shaders/stroke.frag"), QString()); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/stroke.frag")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/filter/stroke/stroke.h b/app/node/filter/stroke/stroke.h index b9d1ac993..fb29aea33 100644 --- a/app/node/filter/stroke/stroke.h +++ b/app/node/filter/stroke/stroke.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,10 +23,11 @@ #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class StrokeFilterNode : public Node { + Q_OBJECT public: StrokeFilterNode(); @@ -34,7 +35,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; virtual void Retranslate() override; @@ -55,6 +56,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // STROKEFILTERNODE_H diff --git a/app/node/generator/CMakeLists.txt b/app/node/generator/CMakeLists.txt index 264d7dade..ebc18dd7c 100644 --- a/app/node/generator/CMakeLists.txt +++ b/app/node/generator/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/generator/matrix/CMakeLists.txt b/app/node/generator/matrix/CMakeLists.txt index b986f2aca..321b4f8fa 100644 --- a/app/node/generator/matrix/CMakeLists.txt +++ b/app/node/generator/matrix/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/generator/matrix/matrix.cpp b/app/node/generator/matrix/matrix.cpp index b35247276..52cecfad2 100644 --- a/app/node/generator/matrix/matrix.cpp +++ b/app/node/generator/matrix/matrix.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,13 +20,10 @@ #include "matrix.h" -#include #include #include -#include "common/range.h" - -OLIVE_NAMESPACE_ENTER +namespace olive { MatrixGenerator::MatrixGenerator() { @@ -37,9 +34,9 @@ MatrixGenerator::MatrixGenerator() AddInput(rotation_input_); scale_input_ = new NodeInput("scale_in", NodeParam::kVec2, QVector2D(1.0f, 1.0f)); - scale_input_->set_property("min", QVector2D(0, 0)); - scale_input_->set_property("view", "percent"); - scale_input_->set_property("disabley", true); + scale_input_->setProperty("min", QVector2D(0, 0)); + scale_input_->setProperty("view", QStringLiteral("percent")); + scale_input_->setProperty("disabley", true); AddInput(scale_input_); uniform_scale_input_ = new NodeInput("uniform_scale_in", NodeParam::kBoolean, true); @@ -69,10 +66,10 @@ QString MatrixGenerator::ShortName() const QString MatrixGenerator::id() const { - return QStringLiteral("org.olivevideoeditor.Olive.transform"); + return QStringLiteral("org.olivevideoeditor.Olive.ortho"); } -QList MatrixGenerator::Category() const +QVector MatrixGenerator::Category() const { return {kCategoryGenerator, kCategoryMath}; } @@ -94,144 +91,65 @@ void MatrixGenerator::Retranslate() NodeValueTable MatrixGenerator::Value(NodeValueDatabase &value) const { // Push matrix output - QMatrix4x4 mat = GenerateMatrix(value); + QMatrix4x4 mat = GenerateMatrix(value, true, false, false, false); NodeValueTable output = value.Merge(); output.Push(NodeParam::kMatrix, mat, this); return output; } -bool MatrixGenerator::GizmoPress(NodeValueDatabase &db, const QPointF &p, const QVector2D &scale, const QSize &viewport) -{ - GizmoSharedData gizmo_data(viewport, scale); - - QPointF anchor_pt = GetGizmoAnchorPoint(db, gizmo_data); - int anchor_radius = GetGizmoAnchorPointRadius(); - - if (InRange(p.x(), anchor_pt.x(), anchor_radius * 2.0) - && InRange(p.y(), anchor_pt.y(), anchor_radius * 2.0)) { - gizmo_drag_ = anchor_input_; - gizmo_start2_ = db[position_input_].Get(NodeParam::kVec2).value(); - } else { - gizmo_drag_ = position_input_; - } - - gizmo_start_ = db[gizmo_drag_].Get(NodeParam::kVec2).value(); - gizmo_mouse_start_ = p; - - return true; -} - -void MatrixGenerator::GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) -{ - QVector2D movement = 2.0 * QVector2D(p - gizmo_mouse_start_) / scale; - QVector2D new_pos = gizmo_start_ + movement; - - if (!gizmo_x_dragger_.IsStarted()) { - gizmo_x_dragger_.Start(gizmo_drag_, time, 0); - } - - if (!gizmo_y_dragger_.IsStarted()) { - gizmo_y_dragger_.Start(gizmo_drag_, time, 1); - } - - gizmo_x_dragger_.Drag(new_pos.x()); - gizmo_y_dragger_.Drag(new_pos.y()); - - if (gizmo_drag_ == anchor_input_) { - // If we're dragging the anchor, counter the position at the same time - QVector2D new_pos2 = gizmo_start2_ + movement; - - if (!gizmo_x2_dragger_.IsStarted()) { - gizmo_x2_dragger_.Start(position_input_, time, 0); - } - - if (!gizmo_y2_dragger_.IsStarted()) { - gizmo_y2_dragger_.Start(position_input_, time, 1); - } - - gizmo_x2_dragger_.Drag(new_pos2.x()); - gizmo_y2_dragger_.Drag(new_pos2.y()); - } -} - -void MatrixGenerator::GizmoRelease() -{ - gizmo_x_dragger_.End(); - gizmo_y_dragger_.End(); - gizmo_x2_dragger_.End(); - gizmo_y2_dragger_.End(); -} - -bool MatrixGenerator::HasGizmos() const -{ - return true; -} - -void MatrixGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p, const QVector2D &scale, const QSize& viewport) const -{ - p->setPen(Qt::white); - - GizmoSharedData gizmo_data(viewport, scale); - - { - // Fold values into a matrix - QMatrix4x4 matrix; - matrix.scale(gizmo_data.half_scale); - matrix *= GenerateMatrix(db, false); - matrix.scale(gizmo_data.inverted_half_scale); - - // Create rect and transform it - QVector points = {QPointF(-100, -100), - QPointF(100, -100), - QPointF(100, 100), - QPointF(-100, 100), - QPointF(-100, -100)}; - QPolygonF poly(points); - poly = matrix.toTransform().map(poly); - poly.translate(gizmo_data.half_viewport); - - // Draw square - p->drawPolyline(poly); - } - - { - // Draw anchor point marker (with no anchor point translation) - QPointF pt = GetGizmoAnchorPoint(db, gizmo_data); - - // Draw anchor point - int anchor_pt_radius = GetGizmoAnchorPointRadius(); - - p->drawEllipse(pt, anchor_pt_radius, anchor_pt_radius); - - p->drawLines({QLineF(pt.x() - anchor_pt_radius, pt.y(), - pt.x() + anchor_pt_radius, pt.y()), - QLineF(pt.x(), pt.y() - anchor_pt_radius, - pt.x(), pt.y() + anchor_pt_radius)}); - } -} - -QMatrix4x4 MatrixGenerator::GenerateMatrix(NodeValueDatabase &value) const -{ - return GenerateMatrix(value[position_input_].Take(NodeParam::kVec2).value(), - value[rotation_input_].Take(NodeParam::kFloat).toFloat(), - value[scale_input_].Take(NodeParam::kVec2).value(), - value[uniform_scale_input_].Take(NodeParam::kBoolean).toBool(), - value[anchor_input_].Take(NodeParam::kVec2).value()); -} - -QMatrix4x4 MatrixGenerator::GenerateMatrix(NodeValueDatabase &value, bool ignore_anchor) const +QMatrix4x4 MatrixGenerator::GenerateMatrix(NodeValueDatabase &value, bool take, bool ignore_anchor, bool ignore_position, bool ignore_scale) const { QVector2D anchor; + QVector2D position; + QVector2D scale; if (!ignore_anchor) { - anchor = value[anchor_input_].Get(NodeParam::kVec2).value(); + if (take) { + // Take and store + anchor = value[anchor_input_].Take(NodeParam::kVec2).value(); + } else { + // Get and store + anchor = value[anchor_input_].Get(NodeParam::kVec2).value(); + } + } else if (take) { + // Just take + value[anchor_input_].Take(NodeParam::kVec2).value(); } - return GenerateMatrix(value[position_input_].Get(NodeParam::kVec2).value(), - value[rotation_input_].Get(NodeParam::kFloat).toFloat(), - value[scale_input_].Get(NodeParam::kVec2).value(), - value[uniform_scale_input_].Get(NodeParam::kBoolean).toBool(), - anchor); + if (!ignore_scale) { + if (take) { + scale = value[scale_input_].Take(NodeParam::kVec2).value(); + } else { + scale = value[scale_input_].Get(NodeParam::kVec2).value(); + } + } else if (take) { + value[scale_input_].Take(NodeParam::kVec2).value(); + } + + if (!ignore_position) { + if (take) { + position = value[position_input_].Take(NodeParam::kVec2).value(); + } else { + position = value[position_input_].Get(NodeParam::kVec2).value(); + } + } else if (take) { + value[position_input_].Take(NodeParam::kVec2).value(); + } + + if (take) { + return GenerateMatrix(position, + value[rotation_input_].Take(NodeParam::kFloat).toFloat(), + scale, + value[uniform_scale_input_].Take(NodeParam::kBoolean).toBool(), + anchor); + } else { + return GenerateMatrix(position, + value[rotation_input_].Get(NodeParam::kFloat).toFloat(), + scale, + value[uniform_scale_input_].Get(NodeParam::kBoolean).toBool(), + anchor); + + } } QMatrix4x4 MatrixGenerator::GenerateMatrix(const QVector2D& pos, @@ -263,35 +181,9 @@ QMatrix4x4 MatrixGenerator::GenerateMatrix(const QVector2D& pos, return mat; } -QPointF MatrixGenerator::GetGizmoAnchorPoint(NodeValueDatabase &db, - const GizmoSharedData& gizmo_data) const -{ - QMatrix4x4 matrix; - matrix.scale(gizmo_data.half_scale); - matrix *= GenerateMatrix(db, true); - matrix.scale(gizmo_data.inverted_half_scale); - - QPointF pt = matrix.toTransform().map(QPointF()); - pt += gizmo_data.half_viewport; - - return pt; -} - -int MatrixGenerator::GetGizmoAnchorPointRadius() -{ - return QFontMetrics(qApp->font()).height() / 2; -} - void MatrixGenerator::UniformScaleChanged() { - scale_input_->set_property("disabley", uniform_scale_input_->get_standard_value().toBool()); + scale_input_->setProperty("disabley", uniform_scale_input_->get_standard_value().toBool()); } -MatrixGenerator::GizmoSharedData::GizmoSharedData(const QSize &viewport, const QVector2D &scale) -{ - half_viewport = QPointF(viewport.width() / 2, viewport.height() / 2); - half_scale = scale * 0.5; - inverted_half_scale = QVector2D(1.0f / half_scale.x(), 1.0f / half_scale.y()); } - -OLIVE_NAMESPACE_EXIT diff --git a/app/node/generator/matrix/matrix.h b/app/node/generator/matrix/matrix.h index d6418eda8..6c22e2e5a 100644 --- a/app/node/generator/matrix/matrix.h +++ b/app/node/generator/matrix/matrix.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "node/node.h" #include "node/inputdragger.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class MatrixGenerator : public Node { @@ -39,41 +39,47 @@ public: virtual QString Name() const override; virtual QString ShortName() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; virtual void Retranslate() override; virtual NodeValueTable Value(NodeValueDatabase& value) const override; - virtual bool HasGizmos() const override; - virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p, const QVector2D &scale, const QSize& viewport) const override; - - virtual bool GizmoPress(NodeValueDatabase& db, const QPointF &p, const QVector2D &scale, const QSize& viewport) override; - virtual void GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) override; - virtual void GizmoRelease() override; - -private: - struct GizmoSharedData { - GizmoSharedData(const QSize& viewport, const QVector2D& scale); - - QPointF half_viewport; - QVector2D half_scale; - QVector2D inverted_half_scale; - }; - - QMatrix4x4 GenerateMatrix(NodeValueDatabase& value) const; - QMatrix4x4 GenerateMatrix(NodeValueDatabase &value, bool ignore_anchor) const; +protected: + QMatrix4x4 GenerateMatrix(NodeValueDatabase &value, bool take, bool ignore_anchor, bool ignore_position, bool ignore_scale) const; static QMatrix4x4 GenerateMatrix(const QVector2D &pos, const float &rot, const QVector2D &scale, bool uniform_scale, const QVector2D &anchor); - QPointF GetGizmoAnchorPoint(NodeValueDatabase &db, const GizmoSharedData &gizmo_data) const; - static int GetGizmoAnchorPointRadius(); - NodeInput* gizmo_drag_; + NodeInput* position_input() const + { + return position_input_; + } + NodeInput* rotation_input() const + { + return rotation_input_; + } + + NodeInput* scale_input() const + { + return scale_input_; + } + + NodeInput* uniform_scale_input() const + { + return uniform_scale_input_; + } + + NodeInput* anchor_input() const + { + return anchor_input_; + } + +private: NodeInput* position_input_; NodeInput* rotation_input_; @@ -84,19 +90,11 @@ private: NodeInput* anchor_input_; - QVector2D gizmo_start_; - QVector2D gizmo_start2_; - QPointF gizmo_mouse_start_; - NodeInputDragger gizmo_x_dragger_; - NodeInputDragger gizmo_y_dragger_; - NodeInputDragger gizmo_x2_dragger_; - NodeInputDragger gizmo_y2_dragger_; - private slots: void UniformScaleChanged(); }; -OLIVE_NAMESPACE_EXIT +} #endif // TRANSFORMDISTORT_H diff --git a/app/node/generator/polygon/CMakeLists.txt b/app/node/generator/polygon/CMakeLists.txt index a1a4b2cc5..8e8e77a41 100644 --- a/app/node/generator/polygon/CMakeLists.txt +++ b/app/node/generator/polygon/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/generator/polygon/polygon.cpp b/app/node/generator/polygon/polygon.cpp index 870488cc0..aa1afee4c 100644 --- a/app/node/generator/polygon/polygon.cpp +++ b/app/node/generator/polygon/polygon.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { PolygonGenerator::PolygonGenerator() { @@ -69,7 +69,7 @@ QString PolygonGenerator::id() const return QStringLiteral("org.olivevideoeditor.Olive.polygon"); } -QList PolygonGenerator::Category() const +QVector PolygonGenerator::Category() const { return {kCategoryGenerator}; } @@ -89,7 +89,7 @@ ShaderCode PolygonGenerator::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) - return ShaderCode(Node::ReadFileAsString(":/shaders/polygon.frag"), QString()); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/polygon.frag")); } NodeValueTable PolygonGenerator::Value(NodeValueDatabase &value) const @@ -98,6 +98,7 @@ NodeValueTable PolygonGenerator::Value(NodeValueDatabase &value) const job.InsertValue(points_input_, value); job.InsertValue(color_input_, value); + job.InsertValue(QStringLiteral("resolution_in"), ShaderValue(value[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")), NodeParam::kVec2)); job.SetAlphaChannelRequired(true); NodeValueTable table = value.Merge(); @@ -110,7 +111,7 @@ bool PolygonGenerator::HasGizmos() const return true; } -void PolygonGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p, const QVector2D &scale, const QSize &viewport) const +/*void PolygonGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p) const { Q_UNUSED(viewport) @@ -170,7 +171,7 @@ void PolygonGenerator::GizmoRelease() { gizmo_x_dragger_.End(); gizmo_y_dragger_.End(); -} +}*/ QVector PolygonGenerator::GetGizmoCoordinates(NodeValueDatabase &db, const QVector2D& scale) const { @@ -204,4 +205,4 @@ QVector PolygonGenerator::GetGizmoRects(const QVector &points) return rects; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/generator/polygon/polygon.h b/app/node/generator/polygon/polygon.h index 296177dea..e14519d58 100644 --- a/app/node/generator/polygon/polygon.h +++ b/app/node/generator/polygon/polygon.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,10 +24,11 @@ #include "node/node.h" #include "node/inputdragger.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PolygonGenerator : public Node { + Q_OBJECT public: PolygonGenerator(); @@ -35,7 +36,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; virtual void Retranslate() override; @@ -44,11 +45,11 @@ public: virtual NodeValueTable Value(NodeValueDatabase &value) const override; virtual bool HasGizmos() const override; - virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p, const QVector2D &scale, const QSize& viewport) const override; + //virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p) const override; - virtual bool GizmoPress(NodeValueDatabase &db, const QPointF &p, const QVector2D &scale, const QSize& viewport) override; - virtual void GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) override; - virtual void GizmoRelease() override; + //virtual bool GizmoPress(NodeValueDatabase &db, const QPointF &p) override; + //virtual void GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) override; + //virtual void GizmoRelease() override; private: QVector GetGizmoCoordinates(NodeValueDatabase &db, const QVector2D &scale) const; @@ -67,6 +68,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // POLYGONGENERATOR_H diff --git a/app/node/generator/solid/CMakeLists.txt b/app/node/generator/solid/CMakeLists.txt index df388a97d..0740bd656 100644 --- a/app/node/generator/solid/CMakeLists.txt +++ b/app/node/generator/solid/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/generator/solid/solid.cpp b/app/node/generator/solid/solid.cpp index abcf6491f..c722b910a 100644 --- a/app/node/generator/solid/solid.cpp +++ b/app/node/generator/solid/solid.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "render/color.h" -OLIVE_NAMESPACE_ENTER +namespace olive { SolidGenerator::SolidGenerator() { @@ -48,7 +48,7 @@ QString SolidGenerator::id() const return QStringLiteral("org.olivevideoeditor.Olive.solidgenerator"); } -QList SolidGenerator::Category() const +QVector SolidGenerator::Category() const { return {kCategoryGenerator}; } @@ -77,7 +77,7 @@ ShaderCode SolidGenerator::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) - return ShaderCode(ReadFileAsString(":/shaders/solid.frag"), QString()); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/solid.frag")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/generator/solid/solid.h b/app/node/generator/solid/solid.h index aa6fb5f79..dbf21cf93 100644 --- a/app/node/generator/solid/solid.h +++ b/app/node/generator/solid/solid.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,10 +23,11 @@ #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SolidGenerator : public Node { + Q_OBJECT public: SolidGenerator(); @@ -34,7 +35,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; virtual void Retranslate() override; @@ -47,6 +48,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // SOLIDGENERATOR_H diff --git a/app/node/generator/text/CMakeLists.txt b/app/node/generator/text/CMakeLists.txt index ec2049f42..7fb53b9f0 100644 --- a/app/node/generator/text/CMakeLists.txt +++ b/app/node/generator/text/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/generator/text/text.cpp b/app/node/generator/text/text.cpp index de38f08bd..c221f709f 100644 --- a/app/node/generator/text/text.cpp +++ b/app/node/generator/text/text.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { enum TextVerticalAlign { kVerticalAlignTop, @@ -72,7 +72,7 @@ QString TextGenerator::id() const return QStringLiteral("org.olivevideoeditor.Olive.textgenerator"); } -QList TextGenerator::Category() const +QVector TextGenerator::Category() const { return {kCategoryGenerator}; } @@ -104,7 +104,7 @@ NodeValueTable TextGenerator::Value(NodeValueDatabase &value) const NodeValueTable table = value.Merge(); - if (!job.GetValue(text_input_).data().toString().isEmpty()) { + if (!job.GetValue(text_input_).data.toString().isEmpty()) { table.Push(NodeParam::kGenerateJob, QVariant::fromValue(job), this); } @@ -124,14 +124,14 @@ void TextGenerator::GenerateFrame(FramePtr frame, const GenerateJob& job) const // Set default font QFont default_font; - default_font.setFamily(job.GetValue(font_input_).data().toString()); - default_font.setPointSizeF(job.GetValue(font_size_input_).data().toFloat()); + default_font.setFamily(job.GetValue(font_input_).data.toString()); + default_font.setPointSizeF(job.GetValue(font_size_input_).data.toFloat()); text_doc.setDefaultFont(default_font); // Center by default text_doc.setDefaultTextOption(QTextOption(Qt::AlignCenter)); - text_doc.setHtml(job.GetValue(text_input_).data().toString()); + text_doc.setHtml(job.GetValue(text_input_).data.toString()); // Align to 80% width because that's considered the "title safe" area int tenth_of_width = frame->video_params().width() / 10; @@ -144,7 +144,7 @@ void TextGenerator::GenerateFrame(FramePtr frame, const GenerateJob& job) const // Push 10% inwards to compensate for title safe area p.translate(tenth_of_width, 0); - TextVerticalAlign valign = static_cast(job.GetValue(valign_input_).data().toInt()); + TextVerticalAlign valign = static_cast(job.GetValue(valign_input_).data.toInt()); int doc_height = text_doc.size().height(); switch (valign) { @@ -165,7 +165,7 @@ void TextGenerator::GenerateFrame(FramePtr frame, const GenerateJob& job) const text_doc.drawContents(&p); // Transplant alpha channel to frame - Color rgb = job.GetValue(color_input_).data().value(); + Color rgb = job.GetValue(color_input_).data.value(); for (int x=0; xwidth(); x++) { for (int y=0; yheight(); y++) { uchar src_alpha = img.bits()[img.bytesPerLine() * y + x]; @@ -176,4 +176,4 @@ void TextGenerator::GenerateFrame(FramePtr frame, const GenerateJob& job) const } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/generator/text/text.h b/app/node/generator/text/text.h index e4a14b868..f672459a5 100644 --- a/app/node/generator/text/text.h +++ b/app/node/generator/text/text.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,10 +23,11 @@ #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TextGenerator : public Node { + Q_OBJECT public: TextGenerator(); @@ -34,7 +35,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; virtual void Retranslate() override; @@ -56,6 +57,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TEXTGENERATOR_H diff --git a/app/node/graph.cpp b/app/node/graph.cpp index aa7515f9a..37b674d64 100644 --- a/app/node/graph.cpp +++ b/app/node/graph.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "graph.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeGraph::NodeGraph() : operation_stack_(0) @@ -164,4 +164,4 @@ bool NodeGraph::ContainsNode(Node *n) const return (n->parent() == this); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/graph.h b/app/node/graph.h index 68324eb7a..e722403d7 100644 --- a/app/node/graph.h +++ b/app/node/graph.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A collection of nodes @@ -110,6 +110,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEGRAPH_H diff --git a/app/node/input.cpp b/app/node/input.cpp index de31c0934..b1ac562b8 100644 --- a/app/node/input.cpp +++ b/app/node/input.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -35,7 +35,7 @@ #include "project/item/footage/stream.h" #include "render/color.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeInput::NodeInput(const QString& id, const DataType &type, const QVector &default_value) : NodeParam(id) @@ -192,13 +192,13 @@ void NodeInput::Load(QXmlStreamReader *reader, XMLNodeData &xml_node_data, const } } } else if (reader->name() == QStringLiteral("csinput")) { - set_property(QStringLiteral("col_input"), reader->readElementText()); + setProperty("col_input", reader->readElementText()); } else if (reader->name() == QStringLiteral("csdisplay")) { - set_property(QStringLiteral("col_display"), reader->readElementText()); + setProperty("col_display", reader->readElementText()); } else if (reader->name() == QStringLiteral("csview")) { - set_property(QStringLiteral("col_view"), reader->readElementText()); + setProperty("col_view", reader->readElementText()); } else if (reader->name() == QStringLiteral("cslook")) { - set_property(QStringLiteral("col_look"), reader->readElementText()); + setProperty("col_look", reader->readElementText()); } else if (reader->name() == QStringLiteral("custom")) { LoadInternal(reader, xml_node_data, cancelled); } else { @@ -250,10 +250,10 @@ void NodeInput::Save(QXmlStreamWriter *writer) const if (data_type_ == NodeParam::kColor) { // Save color management information - writer->writeTextElement(QStringLiteral("csinput"), get_property(QStringLiteral("col_input")).toString()); - writer->writeTextElement(QStringLiteral("csdisplay"), get_property(QStringLiteral("col_display")).toString()); - writer->writeTextElement(QStringLiteral("csview"), get_property(QStringLiteral("col_view")).toString()); - writer->writeTextElement(QStringLiteral("cslook"), get_property(QStringLiteral("col_look")).toString()); + writer->writeTextElement(QStringLiteral("csinput"), property("col_input").toString()); + writer->writeTextElement(QStringLiteral("csdisplay"), property("col_display").toString()); + writer->writeTextElement(QStringLiteral("csview"), property("col_view").toString()); + writer->writeTextElement(QStringLiteral("cslook"), property("col_look").toString()); } SaveConnections(writer); @@ -289,6 +289,17 @@ void NodeInput::SaveInternal(QXmlStreamWriter*) const { } +bool NodeInput::event(QEvent *e) +{ + if (e->type() == QEvent::DynamicPropertyChange) { + QByteArray key = static_cast(e)->propertyName(); + emit PropertyChanged(key, property(key)); + return true; + } + + return QObject::event(e); +} + void NodeInput::Init(DataType type) { keyframable_ = true; @@ -413,7 +424,7 @@ QVariant NodeInput::StringToValue(const DataType& data_type, const QString &stri ValidateVectorString(&vals, 4); - return QVariant::fromValue(Color(vals.at(0).toFloat(), vals.at(1).toFloat(), vals.at(2).toFloat(), vals.at(3).toFloat())); + return QVariant::fromValue(Color(vals.at(0).toDouble(), vals.at(1).toDouble(), vals.at(2).toDouble(), vals.at(3).toDouble())); } else if (data_type == kInt) { return QVariant::fromValue(string.toLongLong()); } else if (data_type == kRational) { @@ -423,7 +434,7 @@ QVariant NodeInput::StringToValue(const DataType& data_type, const QString &stri } } -void NodeInput::GetDependencies(QList &list, bool traverse, bool exclusive_only) const +void NodeInput::GetDependencies(QVector &list, bool traverse, bool exclusive_only) const { if (is_connected() && (get_connected_output()->edges().size() == 1 || !exclusive_only)) { @@ -433,7 +444,7 @@ void NodeInput::GetDependencies(QList &list, bool traverse, bool exclusi list.append(connected); if (traverse) { - QList connected_inputs = connected->GetInputsIncludingArrays(); + QVector connected_inputs = connected->GetInputsIncludingArrays(); foreach (NodeInput* i, connected_inputs) { i->GetDependencies(list, traverse, exclusive_only); @@ -461,21 +472,21 @@ QVariant NodeInput::GetDefaultValueForTrack(int track) const return default_value_.at(track); } -QList NodeInput::GetDependencies(bool traverse, bool exclusive_only) const +QVector NodeInput::GetDependencies(bool traverse, bool exclusive_only) const { - QList list; + QVector list; GetDependencies(list, traverse, exclusive_only); return list; } -QList NodeInput::GetExclusiveDependencies() const +QVector NodeInput::GetExclusiveDependencies() const { return GetDependencies(true, true); } -QList NodeInput::GetImmediateDependencies() const +QVector NodeInput::GetImmediateDependencies() const { return GetDependencies(false, false); } @@ -1106,27 +1117,6 @@ void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_conn emit dest->ValueChanged(TimeRange(RATIONAL_MIN, RATIONAL_MAX)); } -void NodeInput::set_property(const QString &key, const QVariant &value) -{ - properties_.insert(key, value); - emit PropertyChanged(key, value); -} - -QVariant NodeInput::get_property(const QString &key) const -{ - return properties_.value(key); -} - -bool NodeInput::has_property(const QString &key) const -{ - return properties_.contains(key); -} - -const QHash &NodeInput::properties() const -{ - return properties_; -} - QVector NodeInput::split_normal_value_into_track_values(const QVariant &value) const { QVector vals(get_number_of_keyframe_tracks()); @@ -1207,12 +1197,12 @@ QVariant NodeInput::combine_track_values_into_normal_value(const QVector& properties() const; - QVector split_normal_value_into_track_values(const QVariant &value) const; QVariant combine_track_values_into_normal_value(const QVector& split) const; @@ -282,20 +249,20 @@ public: static QVariant StringToValue(const DataType &data_type, const QString &string, bool value_is_a_key_track); - void GetDependencies(QList& list, bool traverse, bool exclusive_only) const; + void GetDependencies(QVector &list, bool traverse, bool exclusive_only) const; QVariant GetDefaultValue() const; QVariant GetDefaultValueForTrack(int track) const; - QList GetDependencies(bool traverse = true, bool exclusive_only = false) const; + QVector GetDependencies(bool traverse = true, bool exclusive_only = false) const; - QList GetExclusiveDependencies() const; + QVector GetExclusiveDependencies() const; - QList GetImmediateDependencies() const; + QVector GetImmediateDependencies() const; signals: - void ValueChanged(const OLIVE_NAMESPACE::TimeRange& range); + void ValueChanged(const olive::TimeRange& range); void KeyframeEnableChanged(bool); @@ -310,6 +277,8 @@ protected: virtual void SaveInternal(QXmlStreamWriter* writer) const; + virtual bool event(QEvent* e) override; + private: void Init(NodeParam::DataType type); @@ -398,11 +367,6 @@ private: */ bool keyframing_; - /** - * @brief Internal properties variable - */ - QHash properties_; - private slots: /** * @brief Slot when a keyframe's time changes to keep the keyframes correctly sorted by time @@ -431,6 +395,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEINPUT_H diff --git a/app/node/input/CMakeLists.txt b/app/node/input/CMakeLists.txt index 5f711f39c..95e07c839 100644 --- a/app/node/input/CMakeLists.txt +++ b/app/node/input/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/input/media/CMakeLists.txt b/app/node/input/media/CMakeLists.txt index 8b674d74d..3ff361000 100644 --- a/app/node/input/media/CMakeLists.txt +++ b/app/node/input/media/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -14,9 +14,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -add_subdirectory(audio) -add_subdirectory(video) - set(OLIVE_SOURCES ${OLIVE_SOURCES} node/input/media/media.h diff --git a/app/node/input/media/audio/audio.cpp b/app/node/input/media/audio/audio.cpp deleted file mode 100644 index 49463aa22..000000000 --- a/app/node/input/media/audio/audio.cpp +++ /dev/null @@ -1,55 +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 "audio.h" - -OLIVE_NAMESPACE_ENTER - -Node *AudioInput::copy() const -{ - return new AudioInput(); -} - -Stream::Type AudioInput::type() const -{ - return Stream::kAudio; -} - -QString AudioInput::Name() const -{ - return tr("Audio Input"); -} - -QString AudioInput::ShortName() const -{ - return tr("Audio"); -} - -QString AudioInput::id() const -{ - return QStringLiteral("org.olivevideoeditor.Olive.audioinput"); -} - -QString AudioInput::Description() const -{ - return tr("Import an audio footage stream."); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/node/input/media/media.cpp b/app/node/input/media/media.cpp index 8d5acd4b8..ea9aefb6e 100644 --- a/app/node/input/media/media.cpp +++ b/app/node/input/media/media.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "common/timecodefunctions.h" #include "common/tohex.h" -OLIVE_NAMESPACE_ENTER +namespace olive { MediaInput::MediaInput() : connected_footage_(nullptr) @@ -35,7 +35,7 @@ MediaInput::MediaInput() : AddInput(footage_input_); } -QList MediaInput::Category() const +QVector MediaInput::Category() const { return {kCategoryInput}; } @@ -57,7 +57,7 @@ bool MediaInput::IsMedia() const void MediaInput::Retranslate() { - footage_input_->set_name(tr("Footage")); + footage_input_->set_name(tr("Media")); } NodeValueTable MediaInput::Value(NodeValueDatabase &value) const @@ -98,4 +98,4 @@ void MediaInput::FootageParametersChanged() InvalidateCache(TimeRange(0, RATIONAL_MAX), footage_input_, footage_input_); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/input/media/media.h b/app/node/input/media/media.h index 1ed9e0889..4a84a7d3d 100644 --- a/app/node/input/media/media.h +++ b/app/node/input/media/media.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "node/node.h" #include "project/item/footage/stream.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A node that imports an image @@ -36,16 +36,33 @@ class MediaInput : public Node public: MediaInput(); - virtual Stream::Type type() const = 0; + virtual QString Name() const override + { + return tr("Media"); + } - virtual QList Category() const override; + virtual QString id() const override + { + return QStringLiteral("org.olivevideoeditor.Olive.mediainput"); + } + + virtual QString Description() const override + { + return tr("Import footage into the node graph."); + } + + virtual Node* copy() const override + { + return new MediaInput(); + } + + virtual QVector Category() const override; StreamPtr stream(); void SetStream(StreamPtr s); virtual bool IsMedia() const override; - virtual void Retranslate() override; virtual NodeValueTable Value(NodeValueDatabase& value) const override; @@ -62,6 +79,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // MEDIAINPUT_H diff --git a/app/node/input/media/video/video.cpp b/app/node/input/media/video/video.cpp deleted file mode 100644 index c02aeaf39..000000000 --- a/app/node/input/media/video/video.cpp +++ /dev/null @@ -1,64 +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 "video.h" - -#include -#include -#include - -#include "codec/ffmpeg/ffmpegdecoder.h" -#include "core.h" -#include "project/item/footage/footage.h" -#include "render/pixelformat.h" - -OLIVE_NAMESPACE_ENTER - -Node *VideoInput::copy() const -{ - return new VideoInput(); -} - -Stream::Type VideoInput::type() const -{ - return Stream::kVideo; -} - -QString VideoInput::Name() const -{ - return tr("Video Input"); -} - -QString VideoInput::ShortName() const -{ - return tr("Video"); -} - -QString VideoInput::id() const -{ - return QStringLiteral("org.olivevideoeditor.Olive.videoinput"); -} - -QString VideoInput::Description() const -{ - return tr("Import a video footage stream."); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/node/input/media/video/video.h b/app/node/input/media/video/video.h deleted file mode 100644 index 7000ea82b..000000000 --- a/app/node/input/media/video/video.h +++ /dev/null @@ -1,49 +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 . - -***/ - -#ifndef VIDEOINPUT_H -#define VIDEOINPUT_H - -#include - -#include "../media.h" -#include "render/colormanager.h" - -OLIVE_NAMESPACE_ENTER - -class VideoInput : public MediaInput -{ -public: - VideoInput() = default; - - virtual Node* copy() const override; - - virtual Stream::Type type() const override; - - virtual QString Name() const override; - virtual QString ShortName() const override; - virtual QString id() const override; - virtual QString Description() const override; - -}; - -OLIVE_NAMESPACE_EXIT - -#endif // VIDEOINPUT_H diff --git a/app/node/input/time/CMakeLists.txt b/app/node/input/time/CMakeLists.txt index 0d308d952..d9a342a5f 100644 --- a/app/node/input/time/CMakeLists.txt +++ b/app/node/input/time/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/input/time/timeinput.cpp b/app/node/input/time/timeinput.cpp index d4df5b32b..101e738e8 100644 --- a/app/node/input/time/timeinput.cpp +++ b/app/node/input/time/timeinput.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "timeinput.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimeInput::TimeInput() { @@ -41,7 +41,7 @@ QString TimeInput::id() const return QStringLiteral("org.olivevideoeditor.Olive.time"); } -QList TimeInput::Category() const +QVector TimeInput::Category() const { return {kCategoryInput}; } @@ -71,4 +71,4 @@ void TimeInput::Hash(QCryptographicHash &hash, const rational &time) const hash.addData(NodeParam::ValueToBytes(NodeParam::kRational, QVariant::fromValue(time))); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/input/time/timeinput.h b/app/node/input/time/timeinput.h index e79d1b333..eb2dac8f2 100644 --- a/app/node/input/time/timeinput.h +++ b/app/node/input/time/timeinput.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimeInput : public Node { @@ -35,7 +35,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; virtual NodeValueTable Value(NodeValueDatabase& value) const override; @@ -44,6 +44,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMEINPUT_H diff --git a/app/node/inputarray.cpp b/app/node/inputarray.cpp index 94d5b4080..6811e8633 100644 --- a/app/node/inputarray.cpp +++ b/app/node/inputarray.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/xmlutils.h" #include "node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeInputArray::NodeInputArray(const QString &id, const DataType &type, const QVariant &default_value) : NodeInput(id, type, default_value), @@ -235,4 +235,4 @@ void NodeInputArray::SaveInternal(QXmlStreamWriter *writer) const writer->writeEndElement(); // subparameters } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/inputarray.h b/app/node/inputarray.h index 5aac757ac..4af48cd5c 100644 --- a/app/node/inputarray.h +++ b/app/node/inputarray.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "input.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeInputArray : public NodeInput { @@ -74,6 +74,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // INPUTARRAY_H diff --git a/app/node/inputdragger.cpp b/app/node/inputdragger.cpp index 9c62f520c..265994c46 100644 --- a/app/node/inputdragger.cpp +++ b/app/node/inputdragger.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "node.h" #include "widget/nodeparamview/nodeparamviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeInputDragger::NodeInputDragger() : input_(nullptr) @@ -70,10 +70,27 @@ void NodeInputDragger::Start(NodeInput *input, const rational &time, int track) } } -void NodeInputDragger::Drag(const QVariant& value) +void NodeInputDragger::Drag(QVariant value) { Q_ASSERT(input_); + if (input_->property("min").isValid()) { + // Assumes the value is a double of some kind + double min = input_->property("min").toDouble(); + double v = value.toDouble(); + if (v < min) { + value = min; + } + } + + if (input_->property("max").isValid()) { + double max = input_->property("max").toDouble(); + double v = value.toDouble(); + if (v > max) { + value = max; + } + } + end_value_ = value; //input_->blockSignals(true); @@ -115,4 +132,4 @@ void NodeInputDragger::End() input_ = nullptr; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/inputdragger.h b/app/node/inputdragger.h index f67f163a2..bd9f80eff 100644 --- a/app/node/inputdragger.h +++ b/app/node/inputdragger.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "node/input.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeInputDragger { @@ -34,7 +34,7 @@ public: void Start(NodeInput* input, const rational& time, int track); - void Drag(const QVariant &value); + void Drag(QVariant value); void End(); @@ -55,6 +55,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEINPUTDRAGGER_H diff --git a/app/node/keyframe.cpp b/app/node/keyframe.cpp index d6839088d..dd3ae2de3 100644 --- a/app/node/keyframe.cpp +++ b/app/node/keyframe.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "keyframe.h" -OLIVE_NAMESPACE_ENTER +namespace olive { const NodeKeyframe::Type NodeKeyframe::kDefaultType = kLinear; @@ -145,4 +145,4 @@ void NodeKeyframe::set_parent(NodeInput *parent) parent_ = parent; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/keyframe.h b/app/node/keyframe.h index 6b12de038..517defe6d 100644 --- a/app/node/keyframe.h +++ b/app/node/keyframe.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/rational.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeInput; @@ -164,8 +164,8 @@ private: }; -OLIVE_NAMESPACE_EXIT +} -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::NodeKeyframe::Type) +Q_DECLARE_METATYPE(olive::NodeKeyframe::Type) #endif // NODEKEYFRAME_H diff --git a/app/node/math/CMakeLists.txt b/app/node/math/CMakeLists.txt index 32ad7e923..c6cad0ac0 100644 --- a/app/node/math/CMakeLists.txt +++ b/app/node/math/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/math/math/CMakeLists.txt b/app/node/math/math/CMakeLists.txt index cfd3f7ab9..81f527c58 100644 --- a/app/node/math/math/CMakeLists.txt +++ b/app/node/math/math/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/math/math/math.cpp b/app/node/math/math/math.cpp index 9330d64d3..41d30bbf8 100644 --- a/app/node/math/math/math.cpp +++ b/app/node/math/math/math.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "math.h" -OLIVE_NAMESPACE_ENTER +namespace olive { MathNode::MathNode() { @@ -30,13 +30,13 @@ MathNode::MathNode() AddInput(method_in_); param_a_in_ = new NodeInput(QStringLiteral("param_a_in"), NodeParam::kFloat, 0.0); - param_a_in_->set_property(QStringLiteral("decimalplaces"), 8); - param_a_in_->set_property(QStringLiteral("autotrim"), true); + param_a_in_->setProperty("decimalplaces", 8); + param_a_in_->setProperty("autotrim", true); AddInput(param_a_in_); param_b_in_ = new NodeInput(QStringLiteral("param_b_in"), NodeParam::kFloat, 0.0); - param_b_in_->set_property(QStringLiteral("decimalplaces"), 8); - param_b_in_->set_property(QStringLiteral("autotrim"), true); + param_b_in_->setProperty("decimalplaces", 8); + param_b_in_->setProperty("autotrim", true); AddInput(param_b_in_); } @@ -55,7 +55,7 @@ QString MathNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.math"); } -QList MathNode::Category() const +QVector MathNode::Category() const { return {kCategoryMath}; } @@ -119,4 +119,4 @@ void MathNode::ProcessSamples(NodeValueDatabase &values, const SampleBufferPtr i return ProcessSamplesInternal(values, GetOperation(), param_a_in_, param_b_in_, input, output, index); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/math/math/math.h b/app/node/math/math/math.h index 81e5111b1..5d9584d77 100644 --- a/app/node/math/math/math.h +++ b/app/node/math/math/math.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,10 +23,11 @@ #include "mathbase.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class MathNode : public MathNodeBase { + Q_OBJECT public: MathNode(); @@ -34,7 +35,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; virtual void Retranslate() override; @@ -74,6 +75,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // MATHNODE_H diff --git a/app/node/math/math/mathbase.cpp b/app/node/math/math/mathbase.cpp index 731a750da..bb0015409 100644 --- a/app/node/math/math/mathbase.cpp +++ b/app/node/math/math/mathbase.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,9 +24,10 @@ #include #include "common/tohex.h" +#include "node/distort/transform/transformdistortnode.h" #include "render/color.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ShaderCode MathNodeBase::GetShaderCodeInternal(const QString &shader_id, NodeInput *param_a_in, olive::NodeInput *param_b_in) const { @@ -48,7 +49,17 @@ ShaderCode MathNodeBase::GetShaderCodeInternal(const QString &shader_id, NodeInp // No-op frag shader (can we return QString() instead?) operation = QStringLiteral("texture(%1, ove_texcoord)").arg(tex_in->id()); - vert = ReadFileAsString(":/shaders/matrix.vert").arg(mat_in->id(), tex_in->id()); + vert = QStringLiteral("uniform mat4 %1;\n" + "\n" + "in vec4 a_position;\n" + "in vec2 a_texcoord;\n" + "\n" + "out vec2 ove_texcoord;\n" + "\n" + "void main() {\n" + " gl_Position = %1 * a_position;\n" + " ove_texcoord = a_texcoord;\n" + "}\n").arg(mat_in->id()); } else { switch (op) { @@ -82,9 +93,7 @@ ShaderCode MathNodeBase::GetShaderCodeInternal(const QString &shader_id, NodeInp GetShaderVariableCall(param_b_in->id(), type_b)); } - frag = QStringLiteral("#version 150\n" - "\n" - "uniform %1 %3;\n" + frag = QStringLiteral("uniform %1 %3;\n" "uniform %2 %4;\n" "\n" "in vec2 ove_texcoord;\n" @@ -289,22 +298,31 @@ NodeValueTable MathNodeBase::ValueInternal(NodeValueDatabase &value, Operation o bool operation_is_noop = false; const NodeValue& number_val = val_a.type() == NodeParam::kTexture ? val_b : val_a; + const NodeValue& texture_val = val_a.type() == NodeParam::kTexture ? val_a : val_b; + TexturePtr texture = texture_val.data().value(); - if (pairing == kPairTextureNumber) { + if (!texture) { + operation_is_noop = true; + } else if (pairing == kPairTextureNumber) { if (NumberIsNoOp(operation, RetrieveNumber(number_val))) { operation_is_noop = true; } } else if (pairing == kPairTextureMatrix) { // Only allow matrix multiplication - bool matrix_is_identity = false; + QVector2D sequence_res = value[QStringLiteral("global")].Get(NodeParam::kVec2, QStringLiteral("resolution")).value(); + QVector2D texture_res(texture->params().width() * texture->pixel_aspect_ratio().toDouble(), texture->params().height()); - // FIXME: The matrix in the shader is transformed around footage+sequence resolution so we - // need to do that here to determine if the matrix is truly identity. But to do that, - // we need access to the texture parameters which is currently not possible. + QMatrix4x4 adjusted_matrix = TransformDistortNode::AdjustMatrixByResolutions(number_val.data().value(), + sequence_res, + texture_res); - if (operation != kOpMultiply || matrix_is_identity) { + if (operation != kOpMultiply || adjusted_matrix.isIdentity()) { operation_is_noop = true; } else { + // Replace with adjusted matrix + job.InsertValue(val_a.type() == NodeParam::kTexture ? param_b_in : param_a_in, + ShaderValue(adjusted_matrix, NodeParam::kMatrix)); + // It's likely an alpha channel will result from this operation job.SetAlphaChannelRequired(true); } @@ -312,7 +330,7 @@ NodeValueTable MathNodeBase::ValueInternal(NodeValueDatabase &value, Operation o if (operation_is_noop) { // Just push texture as-is - output.Push(val_a.type() == NodeParam::kTexture ? val_a : val_b); + output.Push(texture_val); } else { // Push shader job output.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); @@ -329,7 +347,7 @@ NodeValueTable MathNodeBase::ValueInternal(NodeValueDatabase &value, Operation o float number = RetrieveNumber(number_val); SampleJob job(val_a.type() == NodeParam::kSamples ? val_a : val_b); - job.InsertValue(number_param, NodeValue(NodeParam::kFloat, number, this)); + job.InsertValue(number_param, ShaderValue(number, NodeParam::kFloat)); if (job.HasSamples()) { if (number_param->is_static()) { @@ -611,4 +629,4 @@ T MathNodeBase::PerformAddSubMultDiv(Operation operation, T a, U b) return a; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/math/math/mathbase.h b/app/node/math/math/mathbase.h index cdea260bf..e54ac2f58 100644 --- a/app/node/math/math/mathbase.h +++ b/app/node/math/math/mathbase.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class MathNodeBase : public Node { @@ -119,6 +119,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // MATHNODEBASE_H diff --git a/app/node/math/merge/CMakeLists.txt b/app/node/math/merge/CMakeLists.txt index a7472ded0..62a57230b 100644 --- a/app/node/math/merge/CMakeLists.txt +++ b/app/node/math/merge/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/math/merge/merge.cpp b/app/node/math/merge/merge.cpp index 092b69455..877b73a31 100644 --- a/app/node/math/merge/merge.cpp +++ b/app/node/math/merge/merge.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "merge.h" -OLIVE_NAMESPACE_ENTER +namespace olive { MergeNode::MergeNode() { @@ -46,7 +46,7 @@ QString MergeNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.merge"); } -QList MergeNode::Category() const +QVector MergeNode::Category() const { return {kCategoryMath}; } @@ -66,7 +66,7 @@ ShaderCode MergeNode::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) - return ShaderCode(ReadFileAsString(":/shaders/alphaover.frag"), QString()); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/alphaover.frag")); } NodeValueTable MergeNode::Value(NodeValueDatabase &value) const @@ -75,17 +75,18 @@ NodeValueTable MergeNode::Value(NodeValueDatabase &value) const job.InsertValue(base_in_, value); job.InsertValue(blend_in_, value); - // FIXME: Check if "blend" is RGB-only, in which case it's a no-op - NodeValueTable table = value.Merge(); - if (!job.GetValue(base_in_).data().isNull() || !job.GetValue(blend_in_).data().isNull()) { - if (job.GetValue(base_in_).data().isNull()) { - // We only have a blend texture, no need to alpha over - table.Push(job.GetValue(blend_in_)); - } else if (job.GetValue(blend_in_).data().isNull()) { + TexturePtr base_tex = job.GetValue(base_in_).data.value(); + TexturePtr blend_tex = job.GetValue(blend_in_).data.value(); + + if (base_tex || blend_tex) { + if (!base_tex || (blend_tex && blend_tex->channel_count() < VideoParams::kRGBAChannelCount)) { + // We only have a blend texture or the blend texture is RGB only, no need to alpha over + table.Push(job.GetValue(blend_in_), this); + } else if (!blend_tex) { // We only have a base texture, no need to alpha over - table.Push(job.GetValue(base_in_)); + table.Push(job.GetValue(base_in_), this); } else { // We have both textures, push the job table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); @@ -116,4 +117,4 @@ void MergeNode::Hash(QCryptographicHash &hash, const rational &time) const } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/math/merge/merge.h b/app/node/math/merge/merge.h index 70f79369b..6fd205734 100644 --- a/app/node/math/merge/merge.h +++ b/app/node/math/merge/merge.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,10 +23,11 @@ #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class MergeNode : public Node { + Q_OBJECT public: MergeNode(); @@ -34,7 +35,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; virtual void Retranslate() override; @@ -54,6 +55,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // MERGENODE_H diff --git a/app/node/math/trigonometry/CMakeLists.txt b/app/node/math/trigonometry/CMakeLists.txt index 9dd5630de..ff8d4ef8f 100644 --- a/app/node/math/trigonometry/CMakeLists.txt +++ b/app/node/math/trigonometry/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/math/trigonometry/trigonometry.cpp b/app/node/math/trigonometry/trigonometry.cpp index c2f0d03ff..89119db60 100644 --- a/app/node/math/trigonometry/trigonometry.cpp +++ b/app/node/math/trigonometry/trigonometry.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "trigonometry.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TrigonometryNode::TrigonometryNode() { @@ -48,7 +48,7 @@ QString TrigonometryNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.trigonometry"); } -QList TrigonometryNode::Category() const +QVector TrigonometryNode::Category() const { return {kCategoryMath}; } @@ -118,4 +118,4 @@ NodeValueTable TrigonometryNode::Value(NodeValueDatabase &value) const return table; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/math/trigonometry/trigonometry.h b/app/node/math/trigonometry/trigonometry.h index 9af68472f..86c74d235 100644 --- a/app/node/math/trigonometry/trigonometry.h +++ b/app/node/math/trigonometry/trigonometry.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,10 +23,11 @@ #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TrigonometryNode : public Node { + Q_OBJECT public: TrigonometryNode(); @@ -34,7 +35,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; virtual void Retranslate() override; @@ -60,6 +61,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TRIGNODE_H diff --git a/app/node/node.cpp b/app/node/node.cpp index 148c41ee5..760da846b 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,6 +21,7 @@ #include "node.h" #include +#include #include #include @@ -29,8 +30,9 @@ #include "project/project.h" #include "project/item/footage/footage.h" #include "project/item/footage/videostream.h" +#include "widget/nodeview/nodeviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Node::Node() : can_be_deleted_(true) @@ -91,6 +93,7 @@ void Node::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const QAto if (!param) { qDebug() << "No parameter in" << id() << "with parameter" << param_id; + reader->skipCurrentElement(); continue; } @@ -239,6 +242,66 @@ TimeRange Node::OutputTimeAdjustment(NodeInput *, const TimeRange &input_time) c return input_time; } +QVector Node::CopyDependencyGraph(const QVector &nodes, QUndoCommand* command) +{ + int nb_nodes = nodes.size(); + + QVector copies(nb_nodes); + + for (int i=0; icopy();; + + // Copy the values, but NOT the connections, since we'll be connecting to our own clones later + Node::CopyInputs(nodes.at(i), c, false); + + // Add to graph + NodeGraph* graph = static_cast(nodes.at(i)->parent()); + if (command) { + new NodeAddCommand(graph, c, command); + } else { + graph->AddNode(c); + } + + // Store in array at the same index as source + copies[i] = c; + } + + CopyDependencyGraph(nodes, copies, command); + + return copies; +} + +void Node::CopyDependencyGraph(const QVector &src, const QVector &dst, QUndoCommand *command) +{ + int nb_nodes = src.size(); + + for (int i=0; i inputs = src.at(i)->GetInputsIncludingArrays(); + + for (int j=0; jget_connected_node() == src.at(j)) { + // Found a connection + NodeOutput* copy_output = dst.at(j)->GetOutputWithID(input->get_connected_output()->id()); + NodeInput* copy_input = dst.at(i)->GetInputWithID(input->id()); + + if (command) { + new NodeEdgeAddCommand(copy_output, copy_input, command); + } else { + NodeParam::ConnectEdge(copy_output, copy_input); + } + } + } + } + } +} + void Node::SendInvalidateCache(const TimeRange &range, NodeInput *source) { // Loop through all parameters (there should be no children that are not NodeParams) @@ -265,24 +328,12 @@ void Node::SaveInternal(QXmlStreamWriter *) const { } -QList Node::GetInputsToHash() const +QVector Node::GetInputsToHash() const { return GetInputsIncludingArrays(); } -QString Node::ReadFileAsString(const QString &filename) -{ - QFile f(filename); - QString file_data; - if (f.open(QFile::ReadOnly | QFile::Text)) { - QTextStream text_stream(&f); - file_data = text_stream.readAll(); - f.close(); - } - return file_data; -} - -void GetInputsIncludingArraysInternal(NodeInputArray* array, QList& list) +void GetInputsIncludingArraysInternal(NodeInputArray* array, QVector& list) { foreach (NodeInput* input, array->sub_params()) { list.append(input); @@ -293,9 +344,9 @@ void GetInputsIncludingArraysInternal(NodeInputArray* array, QList& } } -QList Node::GetInputsIncludingArrays() const +QVector Node::GetInputsIncludingArrays() const { - QList inputs; + QVector inputs; foreach (NodeParam* param, params_) { if (param->type() == NodeParam::kInput) { @@ -312,7 +363,7 @@ QList Node::GetInputsIncludingArrays() const return inputs; } -QList Node::GetOutputs() const +QVector Node::GetOutputs() const { // The current design only uses one output per node. This function returns a list just in case that changes. return {output_}; @@ -323,16 +374,16 @@ bool Node::HasGizmos() const return false; } -void Node::DrawGizmos(NodeValueDatabase &, QPainter *, const QVector2D &, const QSize &) const +void Node::DrawGizmos(NodeValueDatabase &, QPainter *) { } -bool Node::GizmoPress(NodeValueDatabase &, const QPointF &, const QVector2D &, const QSize &) +bool Node::GizmoPress(NodeValueDatabase &, const QPointF &) { return false; } -void Node::GizmoMove(const QPointF &, const QVector2D &, const rational &) +void Node::GizmoMove(const QPointF &, const rational&) { } @@ -359,7 +410,7 @@ void Node::Hash(QCryptographicHash &hash, const rational& time) const // Add this Node's ID hash.addData(id().toUtf8()); - QList inputs = GetInputsToHash(); + QVector inputs = GetInputsToHash(); foreach (NodeInput* input, inputs) { // For each input, try to hash its value @@ -428,8 +479,8 @@ void Node::CopyInputs(Node *source, Node *destination, bool include_connections) { Q_ASSERT(source->id() == destination->id()); - const QList& src_param = source->params_; - const QList& dst_param = destination->params_; + const QVector& src_param = source->params_; + const QVector& dst_param = destination->params_; for (int i=0;i& Node::parameters() const +const QVector& Node::parameters() const { return params_; } @@ -490,9 +541,9 @@ int Node::IndexOfParameter(NodeParam *param) const * TRUE to recursively traverse each node for a complete dependency graph. FALSE to return only the immediate * dependencies. */ -QList Node::GetDependenciesInternal(bool traverse, bool exclusive_only) const { - QList inputs = GetInputsIncludingArrays(); - QList list; +QVector Node::GetDependenciesInternal(bool traverse, bool exclusive_only) const { + QVector inputs = GetInputsIncludingArrays(); + QVector list; foreach (NodeInput* i, inputs) { i->GetDependencies(list, traverse, exclusive_only); @@ -501,17 +552,17 @@ QList Node::GetDependenciesInternal(bool traverse, bool exclusive_only) c return list; } -QList Node::GetDependencies() const +QVector Node::GetDependencies() const { return GetDependenciesInternal(true, false); } -QList Node::GetExclusiveDependencies() const +QVector Node::GetExclusiveDependencies() const { return GetDependenciesInternal(true, true); } -QList Node::GetImmediateDependencies() const +QVector Node::GetImmediateDependencies() const { return GetDependenciesInternal(false, false); } @@ -535,7 +586,7 @@ void Node::GenerateFrame(FramePtr frame, const GenerateJob &job) const NodeInput *Node::GetInputWithID(const QString &id) const { - QList inputs = GetInputsIncludingArrays(); + QVector inputs = GetInputsIncludingArrays(); foreach (NodeInput* i, inputs) { if (i->id() == id) { @@ -560,7 +611,7 @@ NodeOutput *Node::GetOutputWithID(const QString &id) const bool Node::OutputsTo(Node *n, bool recursively) const { - QList outputs = GetOutputs(); + QVector outputs = GetOutputs(); foreach (NodeOutput* output, outputs) { foreach (NodeEdgePtr edge, output->edges()) { @@ -579,7 +630,7 @@ bool Node::OutputsTo(Node *n, bool recursively) const bool Node::OutputsTo(const QString &id, bool recursively) const { - QList outputs = GetOutputs(); + QVector outputs = GetOutputs(); foreach (NodeOutput* output, outputs) { foreach (NodeEdgePtr edge, output->edges()) { @@ -598,7 +649,7 @@ bool Node::OutputsTo(const QString &id, bool recursively) const bool Node::OutputsTo(NodeInput *input, bool recursively, bool include_arrays) const { - QList outputs = GetOutputs(); + QVector outputs = GetOutputs(); foreach (NodeOutput* output, outputs) { foreach (NodeEdgePtr edge, output->edges()) { @@ -620,7 +671,7 @@ bool Node::OutputsTo(NodeInput *input, bool recursively, bool include_arrays) co bool Node::InputsFrom(Node *n, bool recursively) const { - QList inputs = GetInputsIncludingArrays(); + QVector inputs = GetInputsIncludingArrays(); foreach (NodeInput* input, inputs) { foreach (NodeEdgePtr edge, input->edges()) { @@ -639,7 +690,7 @@ bool Node::InputsFrom(Node *n, bool recursively) const bool Node::InputsFrom(const QString &id, bool recursively) const { - QList inputs = GetInputsIncludingArrays(); + QVector inputs = GetInputsIncludingArrays(); foreach (NodeInput* input, inputs) { foreach (NodeEdgePtr edge, input->edges()) { @@ -661,7 +712,7 @@ int Node::GetRoutesTo(Node *n) const bool outputs_directly = false; int routes = 0; - QList outputs = GetOutputs(); + QVector outputs = GetOutputs(); foreach (NodeOutput* o, outputs) { foreach (NodeEdgePtr edge, o->edges()) { @@ -718,6 +769,8 @@ QString Node::GetCategoryName(const CategoryID &c) return tr("Output"); case kCategoryGeneral: return tr("General"); + case kCategoryDistort: + return tr("Distort"); case kCategoryMath: return tr("Math"); case kCategoryColor: @@ -740,13 +793,13 @@ QString Node::GetCategoryName(const CategoryID &c) return tr("Uncategorized"); } -QList Node::TransformTimeTo(const TimeRange &time, Node *target, NodeParam::Type direction) +QVector Node::TransformTimeTo(const TimeRange &time, Node *target, NodeParam::Type direction) { - QList paths_found; + QVector paths_found; if (direction == NodeParam::kInput) { // Get list of all inputs - QList inputs = GetInputsIncludingArrays(); + QVector inputs = GetInputsIncludingArrays(); // If this input is connected, traverse it to see if we stumble across the specified `node` foreach (NodeInput* input, inputs) { @@ -767,7 +820,7 @@ QList Node::TransformTimeTo(const TimeRange &time, Node *target, Node } } else { // Get list of all outputs - QList outputs = GetOutputs(); + QVector outputs = GetOutputs(); // If this input is connected, traverse it to see if we stumble across the specified `node` foreach (NodeOutput* output, outputs) { @@ -884,4 +937,34 @@ void Node::InputConnectionChanged(NodeEdgePtr edge) InvalidateCache(TimeRange(RATIONAL_MIN, RATIONAL_MAX), edge->input(), edge->input()); } -OLIVE_NAMESPACE_EXIT +QRectF Node::CreateGizmoHandleRect(const QPointF &pt, int radius) +{ + return QRectF(pt.x() - radius, + pt.y() - radius, + 2*radius, + 2*radius); +} + +double Node::GetGizmoHandleRadius(const QTransform &transform) +{ + double raw_value = QFontMetrics(qApp->font()).height() * 0.25; + + raw_value /= transform.m11(); + + return raw_value; +} + +void Node::DrawAndExpandGizmoHandles(QPainter *p, int handle_radius, QRectF *rects, int count) +{ + for (int i=0; idrawRect(r); + + // Extend rect so it's easier to drag with handle + r.adjust(-handle_radius, -handle_radius, handle_radius, handle_radius); + } +} + +} diff --git a/app/node/node.h b/app/node/node.h index 5ed6826b7..6f51460e4 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -36,9 +36,12 @@ #include "node/output.h" #include "node/value.h" #include "render/audioparams.h" -#include "render/shaderinfo.h" +#include "render/job/generatejob.h" +#include "render/job/samplejob.h" +#include "render/job/shaderjob.h" +#include "render/shadercode.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A single processing unit that can be connected with others to create intricate processing systems @@ -71,6 +74,7 @@ public: kCategoryTimeline, kCategoryChannels, kCategoryTransition, + kCategoryDistort, kCategoryCount }; @@ -129,7 +133,7 @@ public: * interpreted as an empty string category. This value should be run through a translator as its largely user * oriented. */ - virtual QList Category() const = 0; + virtual QVector Category() const = 0; /** * @brief Return a description of this node's purpose (optional for subclassing, but recommended) @@ -147,7 +151,7 @@ public: /** * @brief Return a list of NodeParams */ - const QList& parameters() const; + const QVector& parameters() const; /** * @brief Return the index of a parameter @@ -158,7 +162,7 @@ public: /** * @brief Return a list of all Nodes that this Node's inputs are connected to (does not include this Node) */ - QList GetDependencies() const; + QVector GetDependencies() const; /** * @brief Returns a list of Nodes that this Node is dependent on, provided no other Nodes are dependent on them @@ -166,12 +170,12 @@ public: * * Similar to GetDependencies(), but excludes any Nodes that are used outside the dependency graph of this Node. */ - QList GetExclusiveDependencies() const; + QVector GetExclusiveDependencies() const; /** * @brief Retrieve immediate dependencies (only nodes that are directly connected to the inputs of this one) */ - QList GetImmediateDependencies() const; + QVector GetImmediateDependencies() const; /** * @brief Generate hardware accelerated code for this Node @@ -274,19 +278,19 @@ public: /** * @brief Transforms time from this node through the connections it takes to get to the specified node */ - QList TransformTimeTo(const TimeRange& time, Node* target, NodeParam::Type direction); + QVector TransformTimeTo(const TimeRange& time, Node* target, NodeParam::Type direction); /** * @brief Find nodes of a certain type that this Node takes inputs from */ template - QList FindInputNodes() const; + QVector FindInputNodes() const; template /** * @brief Find a node of a certain type that this Node outputs to */ - QList FindOutputNode(); + QVector FindOutputNode(); /** * @brief Convert a pointer to a value that can be sent between NodeParams @@ -343,6 +347,12 @@ public: */ static void CopyInputs(Node* source, Node* destination, bool include_connections = true); + /** + * @brief Clones a set of nodes and connects the new ones the way the old ones were + */ + static QVector CopyDependencyGraph(const QVector& nodes, QUndoCommand *command); + static void CopyDependencyGraph(const QVector& src, const QVector& dst, QUndoCommand *command); + /** * @brief Return whether this Node can be deleted or not */ @@ -404,18 +414,16 @@ public: void SetPosition(const QPointF& pos); - static QString ReadFileAsString(const QString& filename); + QVector GetInputsIncludingArrays() const; - QList GetInputsIncludingArrays() const; - - QList GetOutputs() const; + QVector GetOutputs() const; virtual bool HasGizmos() const; - virtual void DrawGizmos(NodeValueDatabase& db, QPainter* p, const QVector2D &scale, const QSize& viewport) const; + virtual void DrawGizmos(NodeValueDatabase& db, QPainter* p); - virtual bool GizmoPress(NodeValueDatabase& db, const QPointF& p, const QVector2D &scale, const QSize& viewport); - virtual void GizmoMove(const QPointF& p, const QVector2D &scale, const rational &time); + virtual bool GizmoPress(NodeValueDatabase& db, const QPointF& p); + virtual void GizmoMove(const QPointF& p, const rational &time); virtual void GizmoRelease(); const QString& GetLabel() const; @@ -434,10 +442,28 @@ protected: virtual void SaveInternal(QXmlStreamWriter* writer) const; - virtual QList GetInputsToHash() const; + virtual QVector GetInputsToHash() const; + + enum GizmoScaleHandles { + kGizmoScaleTopLeft, + kGizmoScaleTopCenter, + kGizmoScaleTopRight, + kGizmoScaleBottomLeft, + kGizmoScaleBottomCenter, + kGizmoScaleBottomRight, + kGizmoScaleCenterLeft, + kGizmoScaleCenterRight, + kGizmoScaleCount, + }; + + static QRectF CreateGizmoHandleRect(const QPointF& pt, int radius); + + static double GetGizmoHandleRadius(const QTransform& transform); + + static void DrawAndExpandGizmoHandles(QPainter* p, int handle_radius, QRectF* rects, int count); protected slots: - void InputChanged(const OLIVE_NAMESPACE::TimeRange &range); + void InputChanged(const olive::TimeRange &range); void InputConnectionChanged(NodeEdgePtr edge); @@ -487,14 +513,14 @@ private: void DisconnectInput(NodeInput* input); template - static void FindInputNodeInternal(const Node* n, QList& list); + static void FindInputNodeInternal(const Node* n, QVector& list); template - static void FindOutputNodeInternal(const Node* n, QList& list); + static void FindOutputNodeInternal(const Node* n, QVector& list); - QList GetDependenciesInternal(bool traverse, bool exclusive_only) const; + QVector GetDependenciesInternal(bool traverse, bool exclusive_only) const; - QList params_; + QVector params_; /** * @brief Internal variable for whether this Node can be deleted or not @@ -519,9 +545,9 @@ private: }; template -void Node::FindInputNodeInternal(const Node* n, QList& list) +void Node::FindInputNodeInternal(const Node* n, QVector &list) { - QList inputs = n->GetInputsIncludingArrays(); + QVector inputs = n->GetInputsIncludingArrays(); foreach (NodeInput* input, inputs) { if (input->is_connected()) { @@ -538,9 +564,9 @@ void Node::FindInputNodeInternal(const Node* n, QList& list) } template -QList Node::FindInputNodes() const +QVector Node::FindInputNodes() const { - QList list; + QVector list; FindInputNodeInternal(this, list); @@ -554,7 +580,7 @@ T* Node::ValueToPtr(const QVariant &ptr) } template -void Node::FindOutputNodeInternal(const Node* n, QList& list) { +void Node::FindOutputNodeInternal(const Node* n, QVector& list) { foreach (NodeEdgePtr edge, n->output()->edges()) { Node* connected = edge->input()->parentNode(); T* cast_test = dynamic_cast(connected); @@ -568,9 +594,9 @@ void Node::FindOutputNodeInternal(const Node* n, QList& list) { } template -QList Node::FindOutputNode() +QVector Node::FindOutputNode() { - QList list; + QVector list; FindOutputNodeInternal(this, list); @@ -579,6 +605,6 @@ QList Node::FindOutputNode() using NodePtr = std::shared_ptr; -OLIVE_NAMESPACE_EXIT +} #endif // NODE_H diff --git a/app/node/output.cpp b/app/node/output.cpp index 47f5f398d..3f9320c67 100644 --- a/app/node/output.cpp +++ b/app/node/output.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "common/xmlutils.h" #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeOutput::NodeOutput(const QString &id) : NodeParam(id) @@ -68,4 +68,4 @@ void NodeOutput::Save(QXmlStreamWriter *writer) const writer->writeAttribute("ptr", QString::number(reinterpret_cast(this))); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/output.h b/app/node/output.h index 42c5f5ec6..26ad2141a 100644 --- a/app/node/output.h +++ b/app/node/output.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,13 +24,14 @@ #include "common/timerange.h" #include "param.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A node parameter designed to serve data to the input of another node */ class NodeOutput : public NodeParam { + Q_OBJECT public: /** * @brief NodeOutput Constructor @@ -52,6 +53,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEOUTPUT_H diff --git a/app/node/output/CMakeLists.txt b/app/node/output/CMakeLists.txt index 49473e6b8..6a930fbe3 100644 --- a/app/node/output/CMakeLists.txt +++ b/app/node/output/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/output/track/CMakeLists.txt b/app/node/output/track/CMakeLists.txt index 8557f7fbd..660f66b0d 100644 --- a/app/node/output/track/CMakeLists.txt +++ b/app/node/output/track/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index 1cd8de5f9..28f12558e 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "node/block/gap/gap.h" #include "node/graph.h" -OLIVE_NAMESPACE_ENTER +namespace olive { const double TrackOutput::kTrackHeightDefault = 3.0; const double TrackOutput::kTrackHeightMinimum = 1.5; @@ -85,7 +85,7 @@ QString TrackOutput::id() const return QStringLiteral("org.olivevideoeditor.Olive.track"); } -QList TrackOutput::Category() const +QVector TrackOutput::Category() const { return {kCategoryTimeline}; } @@ -300,7 +300,7 @@ void TrackOutput::PrependBlock(Block *block) EndOperation(); // Everything has shifted at this point - InvalidateCache(TimeRange(0, track_length()), block_input_, block_input_); + Node::InvalidateCache(TimeRange(0, track_length()), block_input_, block_input_); } void TrackOutput::InsertBlockAtIndex(Block *block, int index) @@ -314,7 +314,7 @@ void TrackOutput::InsertBlockAtIndex(Block *block, int index) EndOperation(); - InvalidateCache(TimeRange(block->in(), track_length()), block_input_, block_input_); + Node::InvalidateCache(TimeRange(block->in(), track_length()), block_input_, block_input_); } void TrackOutput::AppendBlock(Block *block) @@ -327,7 +327,7 @@ void TrackOutput::AppendBlock(Block *block) EndOperation(); // Invalidate area that block was added to - InvalidateCache(TimeRange(block->in(), track_length()), block_input_, block_input_); + Node::InvalidateCache(TimeRange(block->in(), track_length()), block_input_, block_input_); } void TrackOutput::RippleRemoveBlock(Block *block) @@ -335,12 +335,13 @@ void TrackOutput::RippleRemoveBlock(Block *block) BeginOperation(); rational remove_in = block->in(); + rational remove_out = block->out(); block_input_->RemoveAt(GetInputIndexFromCacheIndex(block)); EndOperation(); - InvalidateCache(TimeRange(remove_in, track_length()), block_input_, block_input_); + Node::InvalidateCache(TimeRange(remove_in, qMax(track_length(), remove_out)), block_input_, block_input_); } void TrackOutput::ReplaceBlock(Block *old, Block *replace) @@ -358,9 +359,9 @@ void TrackOutput::ReplaceBlock(Block *old, Block *replace) EndOperation(); if (old->length() == replace->length()) { - InvalidateCache(TimeRange(replace->in(), replace->out()), block_input_, block_input_); + Node::InvalidateCache(TimeRange(replace->in(), replace->out()), block_input_, block_input_); } else { - InvalidateCache(TimeRange(replace->in(), RATIONAL_MAX), block_input_, block_input_); + Node::InvalidateCache(TimeRange(replace->in(), RATIONAL_MAX), block_input_, block_input_); } } @@ -434,7 +435,7 @@ void TrackOutput::Hash(QCryptographicHash &hash, const rational &time) const void TrackOutput::SetMuted(bool e) { muted_input_->set_standard_value(e); - InvalidateCache(TimeRange(0, track_length()), block_input_, block_input_); + Node::InvalidateCache(TimeRange(0, track_length()), block_input_, block_input_); } void TrackOutput::SetLocked(bool e) @@ -489,9 +490,9 @@ void TrackOutput::SetLengthInternal(const rational &r, bool invalidate) emit TrackLengthChanged(); if (invalidate) { - InvalidateCache(invalidate_range, - block_input_, - block_input_); + Node::InvalidateCache(invalidate_range, + block_input_, + block_input_); } } } @@ -594,7 +595,7 @@ void TrackOutput::BlockLengthChanged() TimeRange invalidate_region(qMin(old_out, new_out), track_length()); - InvalidateCache(invalidate_region, block_input_, block_input_); + Node::InvalidateCache(invalidate_region, block_input_, block_input_); } void TrackOutput::MutedInputValueChanged() @@ -602,4 +603,4 @@ void TrackOutput::MutedInputValueChanged() emit MutedChanged(IsMuted()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h index 6e32f1c9c..a5dd8b112 100644 --- a/app/node/output/track/track.h +++ b/app/node/output/track/track.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "node/block/block.h" #include "timeline/timelinecommon.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A time traversal Node for sorting through one channel/track of Blocks @@ -45,7 +45,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; const double& GetTrackHeight() const; @@ -217,11 +217,6 @@ public: return waveform_; } - QMutex* waveform_lock() - { - return &waveform_lock_; - } - static const double kTrackHeightDefault; static const double kTrackHeightMinimum; static const double kTrackHeightInterval; @@ -297,7 +292,6 @@ private: bool locked_; AudioVisualWaveform waveform_; - QMutex waveform_lock_; private slots: void BlockConnected(NodeEdgePtr edge); @@ -310,6 +304,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // TRACKOUTPUT_H diff --git a/app/node/output/track/tracklist.cpp b/app/node/output/track/tracklist.cpp index e18332040..d4e5ae8fe 100644 --- a/app/node/output/track/tracklist.cpp +++ b/app/node/output/track/tracklist.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "node/math/merge/merge.h" #include "node/output/viewer/viewer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TrackList::TrackList(ViewerOutput *parent, const Timeline::TrackType &type, NodeInputArray *track_input) : QObject(parent), @@ -274,4 +274,4 @@ void TrackList::TrackHeightChangedSlot(int height) emit TrackHeightChanged(static_cast(sender())->Index(), height); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/output/track/tracklist.h b/app/node/output/track/tracklist.h index 2589247e5..5dd3dbe84 100644 --- a/app/node/output/track/tracklist.h +++ b/app/node/output/track/tracklist.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "node/output/track/track.h" #include "timeline/timelinecommon.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ViewerOutput; @@ -114,6 +114,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // TRACKLIST_H diff --git a/app/node/output/viewer/CMakeLists.txt b/app/node/output/viewer/CMakeLists.txt index 86c82a689..71266320c 100644 --- a/app/node/output/viewer/CMakeLists.txt +++ b/app/node/output/viewer/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/output/viewer/viewer.cpp b/app/node/output/viewer/viewer.cpp index ca99b0837..37b6529ad 100644 --- a/app/node/output/viewer/viewer.cpp +++ b/app/node/output/viewer/viewer.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "node/traverser.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ViewerOutput::ViewerOutput() : video_frame_cache_(this), @@ -82,7 +82,7 @@ QString ViewerOutput::id() const return QStringLiteral("org.olivevideoeditor.Olive.vieweroutput"); } -QList ViewerOutput::Category() const +QVector ViewerOutput::Category() const { return {kCategoryOutput}; } @@ -102,7 +102,6 @@ void ViewerOutput::ShiftAudioCache(const rational &from, const rational &to) audio_playback_cache_.Shift(from, to); foreach (TrackOutput* track, track_lists_.at(Timeline::kTrackTypeAudio)->GetTracks()) { - QMutexLocker locker(track->waveform_lock()); track->waveform().Shift(from, to); } } @@ -164,6 +163,8 @@ void ViewerOutput::set_video_params(const VideoParams &video) } emit VideoParamsChanged(); + + video_frame_cache_.InvalidateAll(); } void ViewerOutput::set_audio_params(const AudioParams &audio) @@ -171,6 +172,9 @@ void ViewerOutput::set_audio_params(const AudioParams &audio) audio_params_ = audio; emit AudioParamsChanged(); + + // This will automatically InvalidateAll + audio_playback_cache_.SetParameters(audio_params()); } rational ViewerOutput::GetLength() @@ -341,4 +345,4 @@ void ViewerOutput::TrackHeightChangedSlot(int index, int height) emit TrackHeightChanged(static_cast(sender())->type(), index, height); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/output/viewer/viewer.h b/app/node/output/viewer/viewer.h index 94185f2ac..66d111bd0 100644 --- a/app/node/output/viewer/viewer.h +++ b/app/node/output/viewer/viewer.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -34,7 +34,7 @@ #include "timeline/timelinecommon.h" #include "timeline/trackreference.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A bridge between a node system and a ViewerPanel @@ -53,7 +53,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QList Category() const override; + virtual QVector Category() const override; virtual QString Description() const override; void ShiftVideoCache(const rational& from, const rational& to); @@ -196,6 +196,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // VIEWER_H diff --git a/app/node/param.cpp b/app/node/param.cpp index de6453a7d..3d1ce2c17 100644 --- a/app/node/param.cpp +++ b/app/node/param.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -31,7 +31,7 @@ #include "node/output.h" #include "render/color.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeParam::NodeParam(const QString &id) : id_(id), @@ -286,4 +286,4 @@ QByteArray NodeParam::ValueToBytesInternal(const QVariant &v) return bytes; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/param.h b/app/node/param.h index 553dbe248..0852fa7df 100644 --- a/app/node/param.h +++ b/app/node/param.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "common/xmlutils.h" #include "node/edge.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Node; @@ -432,6 +432,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEPARAM_H diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index 1994d8fd5..5e3108fa7 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,14 +22,14 @@ #include "node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeValueDatabase NodeTraverser::GenerateDatabase(const Node* node, const TimeRange &range) { NodeValueDatabase database; // We need to insert tables into the database for each input - QList inputs = node->GetInputsIncludingArrays(); + QVector inputs = node->GetInputsIncludingArrays(); foreach (NodeInput* input, inputs) { if (IsCancelled()) { @@ -152,12 +152,14 @@ QVariant NodeTraverser::GetCachedFrame(const Node *node, const rational &time) return QVariant(); } -void NodeTraverser::AddGlobalsToDatabase(NodeValueDatabase &db, const TimeRange& range) +void NodeTraverser::AddGlobalsToDatabase(NodeValueDatabase &db, const TimeRange& range) const { // Insert global variables NodeValueTable global; global.Push(NodeParam::kFloat, range.in().toDouble(), nullptr, QStringLiteral("time_in")); global.Push(NodeParam::kFloat, range.out().toDouble(), nullptr, QStringLiteral("time_out")); + global.Push(NodeParam::kVec2, GenerateResolution(), nullptr, QStringLiteral("resolution")); + db.Insert(QStringLiteral("global"), global); } @@ -265,4 +267,4 @@ void NodeTraverser::PostProcessTable(const Node *node, const TimeRange &range, N } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/traverser.h b/app/node/traverser.h index e9a377ae4..097fb7e66 100644 --- a/app/node/traverser.h +++ b/app/node/traverser.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,13 +21,15 @@ #ifndef NODETRAVERSER_H #define NODETRAVERSER_H +#include + #include "codec/decoder.h" #include "common/cancelableobject.h" #include "node/output/track/track.h" #include "project/item/footage/stream.h" #include "value.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeTraverser : public CancelableObject { @@ -56,13 +58,18 @@ protected: virtual QVariant GetCachedFrame(const Node *node, const rational &time); - static void AddGlobalsToDatabase(NodeValueDatabase& db, const TimeRange &range); + void AddGlobalsToDatabase(NodeValueDatabase& db, const TimeRange &range) const; + + virtual QVector2D GenerateResolution() const + { + return QVector2D(0, 0); + } private: void PostProcessTable(const Node *node, const TimeRange &range, NodeValueTable &output_params); }; -OLIVE_NAMESPACE_EXIT +} #endif // NODETRAVERSER_H diff --git a/app/node/value.cpp b/app/node/value.cpp index ef5ac05bd..3c52d3ea0 100644 --- a/app/node/value.cpp +++ b/app/node/value.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,27 +20,7 @@ #include "value.h" -OLIVE_NAMESPACE_ENTER - -NodeValueTable& NodeValueDatabase::operator[](const QString &input_id) -{ - return tables_[input_id]; -} - -NodeValueTable& NodeValueDatabase::operator[](const NodeInput *input) -{ - return tables_[input->id()]; -} - -void NodeValueDatabase::Insert(const QString &key, const NodeValueTable &value) -{ - tables_.insert(key, value); -} - -void NodeValueDatabase::Insert(const NodeInput *key, const NodeValueTable &value) -{ - tables_.insert(key->id(), value); -} +namespace olive { NodeValueTable NodeValueDatabase::Merge() const { @@ -103,41 +83,6 @@ NodeValue NodeValueTable::TakeWithMeta(const NodeParam::DataType &type, const QS return NodeValue(); } -void NodeValueTable::Push(const NodeValue &value) -{ - values_.append(value); -} - -void NodeValueTable::Push(const NodeParam::DataType &type, const QVariant &data, const Node* from, const QString &tag) -{ - Push(NodeValue(type, data, from, tag)); -} - -void NodeValueTable::Prepend(const NodeValue &value) -{ - values_.prepend(value); -} - -void NodeValueTable::Prepend(const NodeParam::DataType &type, const QVariant &data, const Node* from, const QString &tag) -{ - Prepend(NodeValue(type, data, from, tag)); -} - -const NodeValue &NodeValueTable::at(int index) const -{ - return values_.at(index); -} - -NodeValue NodeValueTable::TakeAt(int index) -{ - return values_.takeAt(index); -} - -int NodeValueTable::Count() const -{ - return values_.size(); -} - bool NodeValueTable::Has(const NodeParam::DataType &type) const { for (int i=values_.size() - 1;i>=0;i--) { @@ -163,11 +108,6 @@ void NodeValueTable::Remove(const NodeValue &v) } } -bool NodeValueTable::isEmpty() const -{ - return values_.isEmpty(); -} - NodeValueTable NodeValueTable::Merge(QList tables) { @@ -213,4 +153,4 @@ int NodeValueTable::GetInternal(const NodeParam::DataType &type, const QString & return index; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/node/value.h b/app/node/value.h index 448c1c54d..7ccc9c5e4 100644 --- a/app/node/value.h +++ b/app/node/value.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,8 +24,9 @@ #include #include "input.h" +#include "render/shadervalue.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeValue { @@ -72,17 +73,58 @@ public: NodeValue GetWithMeta(const NodeParam::DataType& type, const QString& tag = QString()) const; QVariant Take(const NodeParam::DataType& type, const QString& tag = QString()); NodeValue TakeWithMeta(const NodeParam::DataType& type, const QString& tag = QString()); - void Push(const NodeValue& value); - void Push(const NodeParam::DataType& type, const QVariant& data, const Node *from, const QString& tag = QString()); - void Prepend(const NodeValue& value); - void Prepend(const NodeParam::DataType& type, const QVariant& data, const Node *from, const QString& tag = QString()); - const NodeValue& at(int index) const; - NodeValue TakeAt(int index); - int Count() const; + + void Push(const NodeValue& value) + { + values_.append(value); + } + + void Push(const NodeParam::DataType& type, const QVariant& data, const Node *from, const QString& tag = QString()) + { + Push(NodeValue(type, data, from, tag)); + } + + void Push(const ShaderValue &value, const Node *from) + { + Push(value.type, value.data, from, value.tag); + } + + void Prepend(const NodeValue& value) + { + values_.prepend(value); + } + + void Prepend(const NodeParam::DataType& type, const QVariant& data, const Node *from, const QString& tag = QString()) + { + Prepend(NodeValue(type, data, from, tag)); + } + + void Prepend(const ShaderValue &value, const Node *from) + { + Prepend(value.type, value.data, from, value.tag); + } + + const NodeValue& at(int index) const + { + return values_.at(index); + } + NodeValue TakeAt(int index) + { + return values_.takeAt(index); + } + + int Count() const + { + return values_.size(); + } + bool Has(const NodeParam::DataType& type) const; void Remove(const NodeValue& v); - bool isEmpty() const; + bool isEmpty() const + { + return values_.isEmpty(); + } static NodeValueTable Merge(QList tables); @@ -98,11 +140,25 @@ class NodeValueDatabase public: NodeValueDatabase() = default; - NodeValueTable& operator[](const QString& input_id); - NodeValueTable& operator[](const NodeInput* input); + NodeValueTable& operator[](const QString& input_id) + { + return tables_[input_id]; + } - void Insert(const QString& key, const NodeValueTable &value); - void Insert(const NodeInput* key, const NodeValueTable& value); + NodeValueTable& operator[](const NodeInput* input) + { + return tables_[input->id()]; + } + + void Insert(const QString& key, const NodeValueTable &value) + { + tables_.insert(key, value); + } + + void Insert(const NodeInput* key, const NodeValueTable& value) + { + tables_.insert(key->id(), value); + } NodeValueTable Merge() const; @@ -128,10 +184,10 @@ private: }; -OLIVE_NAMESPACE_EXIT +} -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::NodeValue) -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::NodeValueTable) -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::NodeValueDatabase) +Q_DECLARE_METATYPE(olive::NodeValue) +Q_DECLARE_METATYPE(olive::NodeValueTable) +Q_DECLARE_METATYPE(olive::NodeValueDatabase) #endif // VALUE_H diff --git a/app/packaging/CMakeLists.txt b/app/packaging/CMakeLists.txt index 776bb311e..19e4b14b1 100644 --- a/app/packaging/CMakeLists.txt +++ b/app/packaging/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/packaging/linux/CMakeLists.txt b/app/packaging/linux/CMakeLists.txt index ffef26e04..58d53a771 100644 --- a/app/packaging/linux/CMakeLists.txt +++ b/app/packaging/linux/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/CMakeLists.txt b/app/panel/CMakeLists.txt index 75c1c7738..53b8cd1aa 100644 --- a/app/panel/CMakeLists.txt +++ b/app/panel/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/audiomonitor/CMakeLists.txt b/app/panel/audiomonitor/CMakeLists.txt index 833c406d3..c52cefa75 100644 --- a/app/panel/audiomonitor/CMakeLists.txt +++ b/app/panel/audiomonitor/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/audiomonitor/audiomonitor.cpp b/app/panel/audiomonitor/audiomonitor.cpp index d15db07b0..d937a2a07 100644 --- a/app/panel/audiomonitor/audiomonitor.cpp +++ b/app/panel/audiomonitor/audiomonitor.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "audiomonitor.h" -OLIVE_NAMESPACE_ENTER +namespace olive { AudioMonitorPanel::AudioMonitorPanel(QWidget *parent) : PanelWidget(QStringLiteral("AudioMonitor"), parent) @@ -37,4 +37,4 @@ void AudioMonitorPanel::Retranslate() SetTitle(tr("Audio Monitor")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/audiomonitor/audiomonitor.h b/app/panel/audiomonitor/audiomonitor.h index 513ec2750..2915edfca 100644 --- a/app/panel/audiomonitor/audiomonitor.h +++ b/app/panel/audiomonitor/audiomonitor.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,13 +24,14 @@ #include "widget/audiomonitor/audiomonitor.h" #include "widget/panel/panel.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief PanelWidget wrapper around an AudioMonitor */ class AudioMonitorPanel : public PanelWidget { + Q_OBJECT public: AudioMonitorPanel(QWidget* parent = nullptr); @@ -41,6 +42,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // AUDIOMONITORPANEL_H diff --git a/app/panel/curve/CMakeLists.txt b/app/panel/curve/CMakeLists.txt index 0831df991..50e8841ae 100644 --- a/app/panel/curve/CMakeLists.txt +++ b/app/panel/curve/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/curve/curve.cpp b/app/panel/curve/curve.cpp index fd6e418ae..3357dc861 100644 --- a/app/panel/curve/curve.cpp +++ b/app/panel/curve/curve.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "curve.h" -OLIVE_NAMESPACE_ENTER +namespace olive { CurvePanel::CurvePanel(QWidget *parent) : TimeBasedPanel(QStringLiteral("CurvePanel"), parent) @@ -37,7 +37,7 @@ void CurvePanel::DeleteSelected() static_cast(GetTimeBasedWidget())->DeleteSelected(); } -void CurvePanel::SetNodes(const QList &nodes) +void CurvePanel::SetNodes(const QVector &nodes) { static_cast(GetTimeBasedWidget())->SetNodes(nodes); } @@ -61,4 +61,4 @@ void CurvePanel::Retranslate() SetTitle(tr("Curve Editor")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/curve/curve.h b/app/panel/curve/curve.h index 375c42822..301e1e976 100644 --- a/app/panel/curve/curve.h +++ b/app/panel/curve/curve.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "panel/timebased/timebased.h" #include "widget/curvewidget/curvewidget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class CurvePanel : public TimeBasedPanel { @@ -35,7 +35,7 @@ public: virtual void DeleteSelected() override; public slots: - void SetNodes(const QList& nodes); + void SetNodes(const QVector &nodes); virtual void IncreaseTrackHeight() override; @@ -46,6 +46,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // CURVEPANEL_H diff --git a/app/panel/footageviewer/CMakeLists.txt b/app/panel/footageviewer/CMakeLists.txt index 127fe1a00..278eb6e9b 100644 --- a/app/panel/footageviewer/CMakeLists.txt +++ b/app/panel/footageviewer/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/footageviewer/footageviewer.cpp b/app/panel/footageviewer/footageviewer.cpp index 5ca58884a..6bfbb4be1 100644 --- a/app/panel/footageviewer/footageviewer.cpp +++ b/app/panel/footageviewer/footageviewer.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "widget/viewer/footageviewer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { FootageViewerPanel::FootageViewerPanel(QWidget *parent) : ViewerPanelBase(QStringLiteral("FootageViewerPanel"), parent) @@ -59,7 +59,12 @@ void FootageViewerPanel::SetFootage(Footage *f) static_cast(GetTimeBasedWidget())->SetFootage(f); if (f) { + // SetSubtitle() will call Retranslate(), so we don't need to call it here SetSubtitle(f->name()); + + // Pop this panel up so the user doesn't think nothing's happening if it's behind another tab + this->show(); + this->raise(); } else { Retranslate(); } @@ -72,4 +77,4 @@ void FootageViewerPanel::Retranslate() SetTitle(tr("Footage Viewer")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/footageviewer/footageviewer.h b/app/panel/footageviewer/footageviewer.h index 6b483ec2b..d4f0d0bba 100644 --- a/app/panel/footageviewer/footageviewer.h +++ b/app/panel/footageviewer/footageviewer.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "panel/viewer/viewerbase.h" #include "panel/project/footagemanagementpanel.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief Dockable wrapper around a ViewerWidget @@ -45,6 +45,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // FOOTAGE_VIEWER_PANEL_H diff --git a/app/panel/node/CMakeLists.txt b/app/panel/node/CMakeLists.txt index 23f0f7f7a..f59514568 100644 --- a/app/panel/node/CMakeLists.txt +++ b/app/panel/node/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/node/node.cpp b/app/panel/node/node.cpp index 44aad38f6..7d4177db3 100644 --- a/app/panel/node/node.cpp +++ b/app/panel/node/node.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodePanel::NodePanel(QWidget *parent) : PanelWidget(QStringLiteral("NodePanel"), parent) @@ -39,4 +39,4 @@ NodePanel::NodePanel(QWidget *parent) : Retranslate(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/node/node.h b/app/panel/node/node.h index 8580b7c1e..b0aa5e187 100644 --- a/app/panel/node/node.h +++ b/app/panel/node/node.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "widget/nodeview/nodeview.h" #include "widget/panel/panel.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A PanelWidget wrapper around a NodeView @@ -76,30 +76,30 @@ public: } public slots: - void Select(const QList& nodes) + void Select(const QVector& nodes) { node_view_->Select(nodes); } - void SelectWithDependencies(const QList& nodes) + void SelectWithDependencies(const QVector& nodes) { node_view_->SelectWithDependencies(nodes); } - void SelectBlocks(const QList& nodes) + void SelectBlocks(const QVector& nodes) { node_view_->SelectBlocks(nodes); } - void DeselectBlocks(const QList& nodes) + void DeselectBlocks(const QVector& nodes) { node_view_->DeselectBlocks(nodes); } signals: - void NodesSelected(const QList& nodes); + void NodesSelected(const QVector& nodes); - void NodesDeselected(const QList& nodes); + void NodesDeselected(const QVector& nodes); private: virtual void Retranslate() override @@ -111,6 +111,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEPANEL_H diff --git a/app/panel/panelmanager.cpp b/app/panel/panelmanager.cpp index 53903f81e..fdeff1f9d 100644 --- a/app/panel/panelmanager.cpp +++ b/app/panel/panelmanager.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "config/config.h" -OLIVE_NAMESPACE_ENTER +namespace olive { PanelManager* PanelManager::instance_ = nullptr; @@ -164,4 +164,4 @@ void PanelManager::PanelDestroyed() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/panelmanager.h b/app/panel/panelmanager.h index caa7bae07..50311a4b5 100644 --- a/app/panel/panelmanager.h +++ b/app/panel/panelmanager.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "widget/panel/panel.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief The PanelFocusManager class @@ -232,6 +232,6 @@ QList PanelManager::GetPanelsOfType() return panels; } -OLIVE_NAMESPACE_EXIT +} #endif // PANELFOCUSMANAGER_H diff --git a/app/panel/param/CMakeLists.txt b/app/panel/param/CMakeLists.txt index 04e3682a5..b827de128 100644 --- a/app/panel/param/CMakeLists.txt +++ b/app/panel/param/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/param/param.cpp b/app/panel/param/param.cpp index 2b9df7f4c..068ee3aae 100644 --- a/app/panel/param/param.cpp +++ b/app/panel/param/param.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "window/mainwindow/mainwindow.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ParamPanel::ParamPanel(QWidget* parent) : TimeBasedPanel(QStringLiteral("ParamPanel"), parent) @@ -36,14 +36,14 @@ ParamPanel::ParamPanel(QWidget* parent) : Retranslate(); } -void ParamPanel::SelectNodes(const QList &nodes) +void ParamPanel::SelectNodes(const QVector &nodes) { static_cast(GetTimeBasedWidget())->SelectNodes(nodes); Retranslate(); } -void ParamPanel::DeselectNodes(const QList &nodes) +void ParamPanel::DeselectNodes(const QVector &nodes) { static_cast(GetTimeBasedWidget())->DeselectNodes(nodes); @@ -70,4 +70,4 @@ void ParamPanel::Retranslate() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/param/param.h b/app/panel/param/param.h index 3c4f15354..a2106d812 100644 --- a/app/panel/param/param.h +++ b/app/panel/param/param.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "panel/timebased/timebased.h" #include "widget/nodeparamview/nodeparamview.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ParamPanel : public TimeBasedPanel { @@ -34,15 +34,15 @@ public: ParamPanel(QWidget* parent); public slots: - void SelectNodes(const QList& nodes); - void DeselectNodes(const QList& nodes); + void SelectNodes(const QVector& nodes); + void DeselectNodes(const QVector& nodes); virtual void DeleteSelected() override; signals: - void RequestSelectNode(const QList& target); + void RequestSelectNode(const QVector& target); - void NodeOrderChanged(const QList& nodes); + void NodeOrderChanged(const QVector& nodes); void FocusedNodeChanged(Node* n); @@ -51,6 +51,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // PARAM_H diff --git a/app/panel/pixelsampler/CMakeLists.txt b/app/panel/pixelsampler/CMakeLists.txt index e10db4b54..74c3c2913 100644 --- a/app/panel/pixelsampler/CMakeLists.txt +++ b/app/panel/pixelsampler/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/pixelsampler/pixelsamplerpanel.cpp b/app/panel/pixelsampler/pixelsamplerpanel.cpp index f83a907ac..d2fcc8d04 100644 --- a/app/panel/pixelsampler/pixelsamplerpanel.cpp +++ b/app/panel/pixelsampler/pixelsamplerpanel.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "pixelsamplerpanel.h" -OLIVE_NAMESPACE_ENTER +namespace olive { PixelSamplerPanel::PixelSamplerPanel(QWidget *parent) : PanelWidget(QStringLiteral("ProjectPanel"), parent) @@ -41,4 +41,4 @@ void PixelSamplerPanel::Retranslate() SetTitle(tr("Pixel Sampler")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/pixelsampler/pixelsamplerpanel.h b/app/panel/pixelsampler/pixelsamplerpanel.h index 6e91cce2f..0da27c12c 100644 --- a/app/panel/pixelsampler/pixelsamplerpanel.h +++ b/app/panel/pixelsampler/pixelsamplerpanel.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "widget/panel/panel.h" #include "widget/pixelsampler/pixelsampler.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PixelSamplerPanel : public PanelWidget { @@ -42,6 +42,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // PIXELSAMPLERPANEL_H diff --git a/app/panel/project/CMakeLists.txt b/app/panel/project/CMakeLists.txt index e274eaa22..2b2c18e3e 100644 --- a/app/panel/project/CMakeLists.txt +++ b/app/panel/project/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/project/footagemanagementpanel.h b/app/panel/project/footagemanagementpanel.h index 02474665b..e962e22ef 100644 --- a/app/panel/project/footagemanagementpanel.h +++ b/app/panel/project/footagemanagementpanel.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,13 +25,13 @@ #include "project/item/footage/footage.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class FootageManagementPanel { public: virtual QList GetSelectedFootage() const = 0; }; -OLIVE_NAMESPACE_EXIT +} #endif // FOOTAGEMANAGEMENTPANEL_H diff --git a/app/panel/project/project.cpp b/app/panel/project/project.cpp index 51fd9388e..5a8318e93 100644 --- a/app/panel/project/project.cpp +++ b/app/panel/project/project.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -32,7 +32,7 @@ #include "widget/projecttoolbar/projecttoolbar.h" #include "window/mainwindow/mainwindow.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectPanel::ProjectPanel(QWidget *parent) : PanelWidget(QStringLiteral("ProjectPanel"), parent) @@ -51,9 +51,7 @@ ProjectPanel::ProjectPanel(QWidget *parent) : // Make toolbar connections connect(toolbar, &ProjectToolbar::NewClicked, this, &ProjectPanel::ShowNewMenu); connect(toolbar, &ProjectToolbar::OpenClicked, Core::instance(), &Core::OpenProject); - connect(toolbar, &ProjectToolbar::SaveClicked, Core::instance(), &Core::SaveActiveProject); - connect(toolbar, &ProjectToolbar::UndoClicked, Core::instance()->undo_stack(), &QUndoStack::undo); - connect(toolbar, &ProjectToolbar::RedoClicked, Core::instance()->undo_stack(), &QUndoStack::redo); + connect(toolbar, &ProjectToolbar::SaveClicked, this, &ProjectPanel::SaveConnectedProject); // Set up main explorer object explorer_ = new ProjectExplorer(this); @@ -229,6 +227,11 @@ void ProjectPanel::UpdateSubtitle() } } +void ProjectPanel::SaveConnectedProject() +{ + Core::instance()->SaveProject(this->project()); +} + QList ProjectPanel::GetSelectedFootage() const { QList items = SelectedItems(); @@ -243,4 +246,4 @@ QList ProjectPanel::GetSelectedFootage() const return footage; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/project/project.h b/app/panel/project/project.h index e77511b2d..c2a25e699 100644 --- a/app/panel/project/project.h +++ b/app/panel/project/project.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "widget/panel/panel.h" #include "widget/projectexplorer/projectexplorer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A PanelWidget wrapper around a ProjectExplorer and a ProjectToolbar @@ -78,10 +78,10 @@ private slots: void UpdateSubtitle(); + void SaveConnectedProject(); + }; -OLIVE_NAMESPACE_EXIT - -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::ProjectPtr) +} #endif // PROJECT_PANEL_H diff --git a/app/panel/scope/CMakeLists.txt b/app/panel/scope/CMakeLists.txt index 2e456b060..1f8fdfd29 100644 --- a/app/panel/scope/CMakeLists.txt +++ b/app/panel/scope/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/scope/scope.cpp b/app/panel/scope/scope.cpp index 5daa7e9e0..753443a62 100644 --- a/app/panel/scope/scope.cpp +++ b/app/panel/scope/scope.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "panel/viewer/viewer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ScopePanel::ScopePanel(QWidget* parent) : PanelWidget(QStringLiteral("ScopePanel"), parent) @@ -105,4 +105,4 @@ void ScopePanel::Retranslate() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/scope/scope.h b/app/panel/scope/scope.h index 3e771af69..2478b5859 100644 --- a/app/panel/scope/scope.h +++ b/app/panel/scope/scope.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "widget/scope/histogram/histogram.h" #include "widget/scope/waveform/waveform.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ViewerPanel; @@ -70,6 +70,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // SCOPE_PANEL_H diff --git a/app/panel/sequenceviewer/CMakeLists.txt b/app/panel/sequenceviewer/CMakeLists.txt index 8cba8ac6f..10cb0258f 100644 --- a/app/panel/sequenceviewer/CMakeLists.txt +++ b/app/panel/sequenceviewer/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/sequenceviewer/sequenceviewer.cpp b/app/panel/sequenceviewer/sequenceviewer.cpp index 6712a99eb..44f6910f2 100644 --- a/app/panel/sequenceviewer/sequenceviewer.cpp +++ b/app/panel/sequenceviewer/sequenceviewer.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "sequenceviewer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { SequenceViewerPanel::SequenceViewerPanel(QWidget *parent) : ViewerPanel(QStringLiteral("SequenceViewerPanel"), parent) @@ -36,4 +36,4 @@ void SequenceViewerPanel::Retranslate() SetTitle(tr("Sequence Viewer")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/sequenceviewer/sequenceviewer.h b/app/panel/sequenceviewer/sequenceviewer.h index 4182bb793..e03d2c828 100644 --- a/app/panel/sequenceviewer/sequenceviewer.h +++ b/app/panel/sequenceviewer/sequenceviewer.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,10 +23,11 @@ #include "panel/viewer/viewer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SequenceViewerPanel : public ViewerPanel { + Q_OBJECT public: SequenceViewerPanel(QWidget* parent); @@ -35,6 +36,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // SEQUENCEVIEWERPANEL_H diff --git a/app/panel/table/CMakeLists.txt b/app/panel/table/CMakeLists.txt index f332aa646..389ee1533 100644 --- a/app/panel/table/CMakeLists.txt +++ b/app/panel/table/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/table/table.cpp b/app/panel/table/table.cpp index 0b3c5260f..a863078a9 100644 --- a/app/panel/table/table.cpp +++ b/app/panel/table/table.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "table.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeTablePanel::NodeTablePanel(QWidget* parent) : TimeBasedPanel(QStringLiteral("NodeTablePanel"), parent) @@ -35,4 +35,4 @@ void NodeTablePanel::Retranslate() SetTitle(tr("Table View")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/table/table.h b/app/panel/table/table.h index 85c6ea888..d7dac3f2e 100644 --- a/app/panel/table/table.h +++ b/app/panel/table/table.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "panel/timebased/timebased.h" #include "widget/nodetableview/nodetablewidget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeTablePanel : public TimeBasedPanel { @@ -33,12 +33,12 @@ public: NodeTablePanel(QWidget* parent); public slots: - void SelectNodes(const QList& nodes) + void SelectNodes(const QVector& nodes) { static_cast(GetTimeBasedWidget())->SelectNodes(nodes); } - void DeselectNodes(const QList& nodes) + void DeselectNodes(const QVector& nodes) { static_cast(GetTimeBasedWidget())->DeselectNodes(nodes); } @@ -48,6 +48,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODETABLEPANEL_H diff --git a/app/panel/taskmanager/CMakeLists.txt b/app/panel/taskmanager/CMakeLists.txt index 63f6baa3c..6c27abdcf 100644 --- a/app/panel/taskmanager/CMakeLists.txt +++ b/app/panel/taskmanager/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/taskmanager/taskmanager.cpp b/app/panel/taskmanager/taskmanager.cpp index e77f4e39f..e50193158 100644 --- a/app/panel/taskmanager/taskmanager.cpp +++ b/app/panel/taskmanager/taskmanager.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "task/taskmanager.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TaskManagerPanel::TaskManagerPanel(QWidget* parent) : PanelWidget(QStringLiteral("TaskManagerPanel"), parent) @@ -48,4 +48,4 @@ void TaskManagerPanel::Retranslate() SetTitle(tr("Task Manager")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/taskmanager/taskmanager.h b/app/panel/taskmanager/taskmanager.h index 78e272761..af1ac8a8d 100644 --- a/app/panel/taskmanager/taskmanager.h +++ b/app/panel/taskmanager/taskmanager.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "widget/taskview/taskview.h" #include "widget/panel/panel.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A PanelWidget wrapper around a TaskView widget @@ -41,6 +41,6 @@ private: TaskView* view_; }; -OLIVE_NAMESPACE_EXIT +} #endif // TASKMANAGER_H diff --git a/app/panel/timebased/CMakeLists.txt b/app/panel/timebased/CMakeLists.txt index 957f3ae6a..b450fd8eb 100644 --- a/app/panel/timebased/CMakeLists.txt +++ b/app/panel/timebased/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/timebased/timebased.cpp b/app/panel/timebased/timebased.cpp index 5e95e944d..be52e2ca5 100644 --- a/app/panel/timebased/timebased.cpp +++ b/app/panel/timebased/timebased.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "timebased.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimeBasedPanel::TimeBasedPanel(const QString &object_name, QWidget *parent) : PanelWidget(object_name, parent), @@ -214,4 +214,4 @@ void TimeBasedPanel::GoToOut() GetTimeBasedWidget()->GoToOut(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/timebased/timebased.h b/app/panel/timebased/timebased.h index 90fb83723..ef0690652 100644 --- a/app/panel/timebased/timebased.h +++ b/app/panel/timebased/timebased.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "widget/panel/panel.h" #include "widget/timebased/timebased.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimeBasedPanel : public PanelWidget { @@ -118,6 +118,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMEBASEDPANEL_H diff --git a/app/panel/timeline/CMakeLists.txt b/app/panel/timeline/CMakeLists.txt index bb7eefaf7..678db400f 100644 --- a/app/panel/timeline/CMakeLists.txt +++ b/app/panel/timeline/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/timeline/timeline.cpp b/app/panel/timeline/timeline.cpp index 2a36987b3..cdfcd13d9 100644 --- a/app/panel/timeline/timeline.cpp +++ b/app/panel/timeline/timeline.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "panel/panelmanager.h" #include "panel/project/footagemanagementpanel.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimelinePanel::TimelinePanel(QWidget *parent) : TimeBasedPanel(QStringLiteral("TimelinePanel"), parent) @@ -182,4 +182,4 @@ void TimelinePanel::Retranslate() SetTitle(tr("Timeline")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/timeline/timeline.h b/app/panel/timeline/timeline.h index b05f7b8bc..5f88651d0 100644 --- a/app/panel/timeline/timeline.h +++ b/app/panel/timeline/timeline.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "panel/timebased/timebased.h" #include "widget/timelinewidget/timelinewidget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief Panel container for a TimelineWidget @@ -91,12 +91,12 @@ protected: virtual void Retranslate() override; signals: - void BlocksSelected(const QList& selected_blocks); + void BlocksSelected(const QVector& selected_blocks); - void BlocksDeselected(const QList& deselected_blocks); + void BlocksDeselected(const QVector& deselected_blocks); }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINE_PANEL_H diff --git a/app/panel/tool/CMakeLists.txt b/app/panel/tool/CMakeLists.txt index 7244ed3ff..605393a77 100644 --- a/app/panel/tool/CMakeLists.txt +++ b/app/panel/tool/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/tool/tool.cpp b/app/panel/tool/tool.cpp index 7822ece90..1b95e12aa 100644 --- a/app/panel/tool/tool.cpp +++ b/app/panel/tool/tool.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "core.h" #include "widget/toolbar/toolbar.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ToolPanel::ToolPanel(QWidget *parent) : PanelWidget(QStringLiteral("ToolPanel"), parent) @@ -52,4 +52,4 @@ void ToolPanel::Retranslate() SetTitle(tr("Tools")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/tool/tool.h b/app/panel/tool/tool.h index 6b144e7d3..a4d673a7a 100644 --- a/app/panel/tool/tool.h +++ b/app/panel/tool/tool.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "widget/panel/panel.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A PanelWidget wrapper around a Toolbar @@ -39,6 +39,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TOOL_PANEL_H diff --git a/app/panel/viewer/CMakeLists.txt b/app/panel/viewer/CMakeLists.txt index 74bdc110a..b3b4a957c 100644 --- a/app/panel/viewer/CMakeLists.txt +++ b/app/panel/viewer/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/panel/viewer/viewer.cpp b/app/panel/viewer/viewer.cpp index d2c3853e7..a79f09b52 100644 --- a/app/panel/viewer/viewer.cpp +++ b/app/panel/viewer/viewer.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "viewer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ViewerPanel::ViewerPanel(const QString &object_name, QWidget *parent) : ViewerPanelBase(object_name, parent) @@ -41,4 +41,4 @@ void ViewerPanel::Retranslate() SetTitle(tr("Viewer")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/viewer/viewer.h b/app/panel/viewer/viewer.h index 4e35444e2..9d83e0c97 100644 --- a/app/panel/viewer/viewer.h +++ b/app/panel/viewer/viewer.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "viewerbase.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief Dockable wrapper around a ViewerWidget @@ -40,6 +40,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // VIEWER_PANEL_H diff --git a/app/panel/viewer/viewerbase.cpp b/app/panel/viewer/viewerbase.cpp index 47ebbe0e0..f58c5d11f 100644 --- a/app/panel/viewer/viewerbase.cpp +++ b/app/panel/viewer/viewerbase.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "window/mainwindow/mainwindow.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ViewerPanelBase::ViewerPanelBase(const QString& object_name, QWidget *parent) : TimeBasedPanel(object_name, parent) @@ -123,4 +123,4 @@ void ViewerPanelBase::closeEvent(QCloseEvent *e) TimeBasedPanel::closeEvent(e); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/panel/viewer/viewerbase.h b/app/panel/viewer/viewerbase.h index 36ac0aa35..536847631 100644 --- a/app/panel/viewer/viewerbase.h +++ b/app/panel/viewer/viewerbase.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "panel/timebased/timebased.h" #include "widget/viewer/viewer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ViewerPanelBase : public TimeBasedPanel { @@ -68,6 +68,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // VIEWERPANELBASE_H diff --git a/app/project/CMakeLists.txt b/app/project/CMakeLists.txt index 1b9763aba..42d59552d 100644 --- a/app/project/CMakeLists.txt +++ b/app/project/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/project/item/CMakeLists.txt b/app/project/item/CMakeLists.txt index 98dbe8b5e..801a78e72 100644 --- a/app/project/item/CMakeLists.txt +++ b/app/project/item/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/project/item/folder/CMakeLists.txt b/app/project/item/folder/CMakeLists.txt index b055fbeb5..745b4222a 100644 --- a/app/project/item/folder/CMakeLists.txt +++ b/app/project/item/folder/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/project/item/folder/folder.cpp b/app/project/item/folder/folder.cpp index 47e1a60df..69c0aaa82 100644 --- a/app/project/item/folder/folder.cpp +++ b/app/project/item/folder/folder.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "project/item/sequence/sequence.h" #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Item::Type Folder::type() const { @@ -42,7 +42,7 @@ QIcon Folder::icon() return icon::Folder; } -void Folder::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const QAtomicInt *cancelled) +void Folder::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, uint version, const QAtomicInt *cancelled) { XMLAttributeLoop(reader, attr) { if (cancelled && *cancelled) { @@ -75,7 +75,7 @@ void Folder::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const QA } add_child(child); - child->Load(reader, xml_node_data, cancelled); + child->Load(reader, xml_node_data, version, cancelled); } } @@ -104,4 +104,4 @@ void Folder::Save(QXmlStreamWriter *writer) const } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/project/item/folder/folder.h b/app/project/item/folder/folder.h index c2e3cbaba..fcd6a6d15 100644 --- a/app/project/item/folder/folder.h +++ b/app/project/item/folder/folder.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "project/item/footage/footage.h" #include "project/item/item.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief The Folder class representing a directory in a project structure @@ -44,7 +44,7 @@ public: virtual QIcon icon() override; - virtual void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled) override; + virtual void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, uint version, const QAtomicInt *cancelled) override; virtual void Save(QXmlStreamWriter* writer) const override; @@ -52,6 +52,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // FOLDER_H diff --git a/app/project/item/footage/CMakeLists.txt b/app/project/item/footage/CMakeLists.txt index 5482cce07..1a3d79e45 100644 --- a/app/project/item/footage/CMakeLists.txt +++ b/app/project/item/footage/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/project/item/footage/audiostream.cpp b/app/project/item/footage/audiostream.cpp index f824c2ec1..7b1ff0d15 100644 --- a/app/project/item/footage/audiostream.cpp +++ b/app/project/item/footage/audiostream.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "common/xmlutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { AudioStream::AudioStream() { @@ -31,9 +31,10 @@ AudioStream::AudioStream() QString AudioStream::description() const { - return QCoreApplication::translate("Stream", "%1: Audio - %2 Channels, %3Hz").arg(QString::number(index()), - QString::number(channels()), - QString::number(sample_rate())); + return QCoreApplication::translate("Stream", "%1: Audio - %2 Channel(s), %3Hz") + .arg(QString::number(index()), + QString::number(channels()), + QString::number(sample_rate())); } const int &AudioStream::channels() const @@ -66,38 +67,6 @@ void AudioStream::set_sample_rate(const int &sample_rate) sample_rate_ = sample_rate; } -bool AudioStream::try_start_conforming(const AudioParams ¶ms) -{ - QMutexLocker locker(proxy_access_lock()); - - if (!currently_conforming_.contains(params) - && !conformed_.contains(params)) { - currently_conforming_.append(params); - return true; - } - - return false; -} - -bool AudioStream::has_conformed_version(const AudioParams ¶ms) -{ - QMutexLocker locker(proxy_access_lock()); - - return conformed_.contains(params); -} - -void AudioStream::append_conformed_version(const AudioParams ¶ms) -{ - { - QMutexLocker locker(proxy_access_lock()); - - currently_conforming_.removeOne(params); - conformed_.append(params); - } - - emit ConformAppended(params); -} - QIcon AudioStream::icon() const { return icon::Audio; @@ -125,4 +94,4 @@ void AudioStream::SaveCustomParameters(QXmlStreamWriter *writer) const writer->writeTextElement(QStringLiteral("rate"), QString::number(sample_rate_)); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/project/item/footage/audiostream.h b/app/project/item/footage/audiostream.h index f85046839..6941c8177 100644 --- a/app/project/item/footage/audiostream.h +++ b/app/project/item/footage/audiostream.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "render/audioparams.h" #include "stream.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A Stream derivative containing audio-specific information @@ -49,10 +49,6 @@ public: const int& sample_rate() const; void set_sample_rate(const int& sample_rate); - bool try_start_conforming(const AudioParams& params); - bool has_conformed_version(const AudioParams& params); - void append_conformed_version(const AudioParams& params); - virtual QIcon icon() const override; protected: @@ -60,22 +56,15 @@ protected: virtual void SaveCustomParameters(QXmlStreamWriter* writer) const override; -signals: - void ConformAppended(OLIVE_NAMESPACE::AudioParams params); - private: int channels_; uint64_t layout_; int sample_rate_; - QList conformed_; - - QList currently_conforming_; - }; using AudioStreamPtr = std::shared_ptr; -OLIVE_NAMESPACE_EXIT +} #endif // AUDIOSTREAM_H diff --git a/app/project/item/footage/footage.cpp b/app/project/item/footage/footage.cpp index cd92604c6..c2d1b1c63 100644 --- a/app/project/item/footage/footage.cpp +++ b/app/project/item/footage/footage.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "core.h" #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Footage::Footage() { @@ -42,7 +42,7 @@ Footage::~Footage() ClearStreams(); } -void Footage::Load(QXmlStreamReader *reader, XMLNodeData &xml_node_data, const QAtomicInt* cancelled) +void Footage::Load(QXmlStreamReader *reader, XMLNodeData &xml_node_data, uint version, const QAtomicInt* cancelled) { while (XMLReadNextStartElement(reader)) { if (cancelled && *cancelled) { @@ -180,7 +180,6 @@ QIcon Footage::icon() QString Footage::duration() { // Find longest stream duration - StreamPtr longest_stream = nullptr; rational longest; @@ -200,18 +199,20 @@ QString Footage::duration() if (longest_stream->type() == Stream::kVideo) { VideoStreamPtr video_stream = std::static_pointer_cast(longest_stream); - int64_t duration = video_stream->duration(); - rational frame_rate_timebase = video_stream->frame_rate().flipped(); + if (video_stream->video_type() != VideoStream::kVideoTypeStill) { + int64_t duration = video_stream->duration(); + rational frame_rate_timebase = video_stream->frame_rate().flipped(); - if (video_stream->timebase() != frame_rate_timebase) { - // Convert from timebase to frame rate - rational duration_time = Timecode::timestamp_to_time(duration, video_stream->timebase()); - duration = Timecode::time_to_timestamp(duration_time, frame_rate_timebase); + if (video_stream->timebase() != frame_rate_timebase) { + // Convert from timebase to frame rate + rational duration_time = Timecode::timestamp_to_time(duration, video_stream->timebase()); + duration = Timecode::time_to_timestamp(duration_time, frame_rate_timebase); + } + + return Timecode::timestamp_to_timecode(duration, + frame_rate_timebase, + Core::instance()->GetTimecodeDisplay()); } - - return Timecode::timestamp_to_timecode(duration, - frame_rate_timebase, - Core::instance()->GetTimecodeDisplay()); } else if (longest_stream->type() == Stream::kAudio) { AudioStreamPtr audio_stream = std::static_pointer_cast(longest_stream); @@ -237,11 +238,13 @@ QString Footage::rate() return QString(); } - if (HasStreamsOfType(Stream::kVideo) - && std::static_pointer_cast(get_first_stream_of_type(Stream::kVideo))->video_type() != VideoStream::kVideoTypeStill) { + if (HasStreamsOfType(Stream::kVideo)) { // This is a video editor, prioritize video streams VideoStreamPtr video_stream = std::static_pointer_cast(get_first_stream_of_type(Stream::kVideo)); - return QCoreApplication::translate("Footage", "%1 FPS").arg(video_stream->frame_rate().toDouble()); + + if (video_stream->video_type() != VideoStream::kVideoTypeStill) { + return QCoreApplication::translate("Footage", "%1 FPS").arg(video_stream->frame_rate().toDouble()); + } } else if (HasStreamsOfType(Stream::kAudio)) { // No video streams, return audio AudioStreamPtr audio_stream = std::static_pointer_cast(streams_.first()); @@ -308,7 +311,7 @@ bool Footage::CompareFootageToItsFilename(FootagePtr footage) } else { // Footage may have changed and we'll have to re-probe it. It also may not have, in which // case nothing needs to change. - ItemPtr item = Decoder::ProbeMedia(footage->project(), footage->filename(), nullptr); + ItemPtr item = Decoder::Probe(footage->project(), footage->filename(), nullptr); if (item && item->type() == footage->type()) { // Item is the same type, that's a good sign. Let's look for any differences. @@ -342,4 +345,4 @@ void Footage::UpdateTooltip() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/project/item/footage/footage.h b/app/project/item/footage/footage.h index 3348d35cb..2ffd9e272 100644 --- a/app/project/item/footage/footage.h +++ b/app/project/item/footage/footage.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "project/item/footage/videostream.h" #include "timeline/timelinepoints.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Footage; using FootagePtr = std::shared_ptr; @@ -60,7 +60,7 @@ public: /** * @brief Load function */ - virtual void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled) override; + virtual void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, uint version, const QAtomicInt *cancelled) override; /** * @brief Save function @@ -250,6 +250,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // FOOTAGE_H diff --git a/app/project/item/footage/stream.cpp b/app/project/item/footage/stream.cpp index 8598a87e8..3e4d59fb3 100644 --- a/app/project/item/footage/stream.cpp +++ b/app/project/item/footage/stream.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "footage.h" #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Stream::Stream() : footage_(nullptr), @@ -176,11 +176,6 @@ QIcon Stream::icon() const return QIcon(); } -QMutex *Stream::proxy_access_lock() -{ - return &proxy_access_lock_; -} - void Stream::LoadCustomParameters(QXmlStreamReader* reader) { reader->skipCurrentElement(); @@ -190,4 +185,4 @@ void Stream::SaveCustomParameters(QXmlStreamWriter*) const { } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/project/item/footage/stream.h b/app/project/item/footage/stream.h index 634bce7b0..e6d850ddf 100644 --- a/app/project/item/footage/stream.h +++ b/app/project/item/footage/stream.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "common/rational.h" #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Footage; class Stream; @@ -95,7 +95,10 @@ public: virtual QIcon icon() const; - QMutex* proxy_access_lock(); + QMutex* mutex() + { + return &mutex_; + } protected: virtual void LoadCustomParameters(QXmlStreamReader *reader); @@ -118,13 +121,13 @@ private: bool enabled_; - QMutex proxy_access_lock_; + QMutex mutex_; }; -OLIVE_NAMESPACE_EXIT +} #include -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::StreamPtr) +Q_DECLARE_METATYPE(olive::StreamPtr) #endif // STREAM_H diff --git a/app/project/item/footage/videostream.cpp b/app/project/item/footage/videostream.cpp index 98cbfd1fc..0bef7bc42 100644 --- a/app/project/item/footage/videostream.cpp +++ b/app/project/item/footage/videostream.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "project/project.h" #include "render/colormanager.h" -OLIVE_NAMESPACE_ENTER +namespace olive { VideoStream::VideoStream() : premultiplied_alpha_(false), @@ -104,7 +104,9 @@ void VideoStream::LoadCustomParameters(QXmlStreamReader *reader) } else if (reader->name() == QStringLiteral("type")) { set_video_type(static_cast(reader->readElementText().toInt())); } else if (reader->name() == QStringLiteral("format")) { - set_format(static_cast(reader->readElementText().toInt())); + set_format(static_cast(reader->readElementText().toInt())); + } else if (reader->name() == QStringLiteral("channels")) { + set_channel_count(reader->readElementText().toInt()); } else if (reader->name() == QStringLiteral("pixelaspect")) { set_pixel_aspect_ratio(rational::fromString(reader->readElementText())); } else if (reader->name() == QStringLiteral("framerate")) { @@ -126,25 +128,32 @@ void VideoStream::SaveCustomParameters(QXmlStreamWriter *writer) const writer->writeTextElement(QStringLiteral("interlacing"), QString::number(interlacing_)); writer->writeTextElement(QStringLiteral("type"), QString::number(video_type_)); writer->writeTextElement(QStringLiteral("format"), QString::number(format_)); + writer->writeTextElement(QStringLiteral("channels"), QString::number(channel_count_)); writer->writeTextElement(QStringLiteral("pixelaspect"), pixel_aspect_ratio_.toString()); writer->writeTextElement(QStringLiteral("framerate"), frame_rate_.toString()); writer->writeTextElement(QStringLiteral("starttime"), QString::number(start_time_)); } -bool VideoStream::premultiplied_alpha() const +bool VideoStream::premultiplied_alpha() { + QMutexLocker locker(mutex()); + return premultiplied_alpha_; } void VideoStream::set_premultiplied_alpha(bool e) { + mutex()->lock(); premultiplied_alpha_ = e; + mutex()->unlock(); emit ParametersChanged(); } -const QString &VideoStream::colorspace(bool default_if_empty) const +const QString &VideoStream::colorspace(bool default_if_empty) { + QMutexLocker locker(mutex()); + if (colorspace_.isEmpty() && default_if_empty) { return footage()->project()->color_manager()->GetDefaultInputColorSpace(); } else { @@ -154,17 +163,13 @@ const QString &VideoStream::colorspace(bool default_if_empty) const void VideoStream::set_colorspace(const QString &color) { + mutex()->lock(); colorspace_ = color; + mutex()->unlock(); emit ParametersChanged(); } -QString VideoStream::get_colorspace_match_string() const -{ - return QStringLiteral("%1:%2").arg(footage()->project()->color_manager()->GetConfigFilename(), - colorspace()); -} - void VideoStream::ColorConfigChanged() { ColorManager* color_manager = footage()->project()->color_manager(); @@ -190,4 +195,4 @@ void VideoStream::DefaultColorSpaceChanged() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/project/item/footage/videostream.h b/app/project/item/footage/videostream.h index 7fe6ba773..e6f5f345d 100644 --- a/app/project/item/footage/videostream.h +++ b/app/project/item/footage/videostream.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,11 +21,10 @@ #ifndef VIDEOSTREAM_H #define VIDEOSTREAM_H -#include "render/pixelformat.h" #include "render/videoparams.h" #include "stream.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A Stream derivative containing video-specific information @@ -74,24 +73,32 @@ public: height_ = height; } - const PixelFormat::Format& format() const + const VideoParams::Format& format() const { return format_; } - void set_format(const PixelFormat::Format& format) + void set_format(const VideoParams::Format& format) { format_ = format; } - bool premultiplied_alpha() const; + int channel_count() const + { + return channel_count_; + } + + void set_channel_count(int c) + { + channel_count_ = c; + } + + bool premultiplied_alpha(); void set_premultiplied_alpha(bool e); - const QString& colorspace(bool default_if_empty = true) const; + const QString& colorspace(bool default_if_empty = true); void set_colorspace(const QString& color); - QString get_colorspace_match_string() const; - VideoParams::Interlacing interlacing() const { return interlacing_; @@ -155,7 +162,9 @@ private: VideoType video_type_; - PixelFormat::Format format_; + VideoParams::Format format_; + + int channel_count_; rational pixel_aspect_ratio_; @@ -167,6 +176,6 @@ private: using VideoStreamPtr = std::shared_ptr; -OLIVE_NAMESPACE_EXIT +} #endif // VIDEOSTREAM_H diff --git a/app/project/item/item.cpp b/app/project/item/item.cpp index cfb5bd915..33657825e 100644 --- a/app/project/item/item.cpp +++ b/app/project/item/item.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "item.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Item::Item() : parent_(nullptr), @@ -203,4 +203,4 @@ bool Item::ChildExistsWithNameInternal(const QString &name, Item *folder) return false; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/project/item/item.h b/app/project/item/item.h index 03739d0f8..efaaaf963 100644 --- a/app/project/item/item.h +++ b/app/project/item/item.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -33,7 +33,7 @@ #include "node/param.h" #include "project/item/footage/stream.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Project; @@ -67,7 +67,7 @@ public: DISABLE_COPY_MOVE(Item) - virtual void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled) = 0; + virtual void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, uint version, const QAtomicInt *cancelled) = 0; virtual void Save(QXmlStreamWriter* writer) const = 0; @@ -123,6 +123,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // ITEM_H diff --git a/app/project/item/sequence/CMakeLists.txt b/app/project/item/sequence/CMakeLists.txt index 0c4b43b22..de063f1e5 100644 --- a/app/project/item/sequence/CMakeLists.txt +++ b/app/project/item/sequence/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp index ab61093a1..a24d93b85 100644 --- a/app/project/item/sequence/sequence.cpp +++ b/app/project/item/sequence/sequence.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,6 +21,7 @@ #include "sequence.h" #include +#include #include "config/config.h" #include "common/channellayout.h" @@ -35,7 +36,7 @@ #include "panel/sequenceviewer/sequenceviewer.h" #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Sequence::Sequence() { @@ -44,7 +45,7 @@ Sequence::Sequence() AddNode(viewer_output_); } -void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const QAtomicInt *cancelled) +void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, uint version, const QAtomicInt *cancelled) { { XMLAttributeLoop(reader, attr) { @@ -69,7 +70,7 @@ void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const int video_width = 0, video_height = 0, preview_div = 1; rational video_timebase, video_pixel_aspect; VideoParams::Interlacing video_interlacing = VideoParams::kInterlaceNone; - PixelFormat::Format preview_format = PixelFormat::PIX_FMT_INVALID; + VideoParams::Format preview_format = VideoParams::kFormatInvalid; while (XMLReadNextStartElement(reader)) { if (cancelled && *cancelled) { @@ -85,7 +86,7 @@ void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const } else if (reader->name() == QStringLiteral("divider")) { preview_div = reader->readElementText().toInt(); } else if (reader->name() == QStringLiteral("format")) { - preview_format = static_cast(reader->readElementText().toInt()); + preview_format = static_cast(reader->readElementText().toInt()); } else if (reader->name() == QStringLiteral("pixelaspect")) { video_pixel_aspect = rational::fromString(reader->readElementText()); } else if (reader->name() == QStringLiteral("interlacing")) { @@ -96,11 +97,12 @@ void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const } set_video_params(VideoParams(video_width, video_height, video_timebase, preview_format, - video_pixel_aspect, video_interlacing, preview_div)); + VideoParams::kInternalChannelCount, video_pixel_aspect, + video_interlacing, preview_div)); } else if (reader->name() == QStringLiteral("audio")) { int rate = 0; uint64_t layout = 0; - SampleFormat::Format format = SampleFormat::SAMPLE_FMT_INVALID; + AudioParams::Format format = AudioParams::kFormatInvalid; while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("rate")) { @@ -108,7 +110,7 @@ void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const } else if (reader->name() == QStringLiteral("layout")) { layout = reader->readElementText().toULongLong(); } else if (reader->name() == QStringLiteral("format")) { - format = static_cast(reader->readElementText().toInt()); + format = static_cast(reader->readElementText().toInt()); } else { reader->skipCurrentElement(); } @@ -128,7 +130,24 @@ void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const { XMLAttributeLoop(reader, attr) { if (attr.name() == QStringLiteral("id")) { - node = NodeFactory::CreateFromID(attr.value().toString()); + QString id = attr.value().toString(); + if (version <= 201003) { + // After version 201003, the video and audio nodes were merged into one media node + if (id == QStringLiteral("org.olivevideoeditor.Olive.audioinput") + || id == QStringLiteral("org.olivevideoeditor.Olive.videoinput")) { + id = QStringLiteral("org.olivevideoeditor.Olive.mediainput"); + } + } + + if (version <= 201118) { + // After version 201118, the orthographic matrix node ID was changed from + // "org.olivevideoeditor.Olive.transform" to "org.olivevideoeditor.Olive.ortho" + if (id == QStringLiteral("org.olivevideoeditor.Olive.transform")) { + id = QStringLiteral("org.olivevideoeditor.Olive.ortho"); + } + } + + node = NodeFactory::CreateFromID(id); break; } } @@ -267,13 +286,14 @@ void Sequence::set_default_parameters() set_video_params(VideoParams(width, height, Config::Current()["DefaultSequenceFrameRate"].value(), - static_cast(Config::Current()["DefaultSequencePreviewFormat"].toInt()), + static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + VideoParams::kInternalChannelCount, Config::Current()["DefaultSequencePixelAspect"].value(), Config::Current()["DefaultSequenceInterlacing"].value(), VideoParams::generate_auto_divider(width, height))); set_audio_params(AudioParams(Config::Current()["DefaultSequenceAudioFrequency"].toInt(), Config::Current()["DefaultSequenceAudioLayout"].toULongLong(), - SampleFormat::kInternalFormat)); + AudioParams::kInternalFormat)); } void Sequence::set_parameters_from_footage(const QList footage) @@ -309,7 +329,8 @@ void Sequence::set_parameters_from_footage(const QList footage) set_video_params(VideoParams(vs->width(), vs->height(), using_timebase, - static_cast(Config::Current()["DefaultSequencePreviewFormat"].toInt()), + static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + VideoParams::kInternalChannelCount, vs->pixel_aspect_ratio(), vs->interlacing(), VideoParams::generate_auto_divider(vs->width(), vs->height()))); @@ -319,7 +340,7 @@ void Sequence::set_parameters_from_footage(const QList footage) case Stream::kAudio: if (!found_audio_params) { AudioStream* as = static_cast(s.get()); - set_audio_params(AudioParams(as->sample_rate(), as->channel_layout(), SampleFormat::kInternalFormat)); + set_audio_params(AudioParams(as->sample_rate(), as->channel_layout(), AudioParams::kInternalFormat)); found_audio_params = true; } break; @@ -348,4 +369,4 @@ void Sequence::NameChangedEvent(const QString &name) viewer_output_->set_media_name(name); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/project/item/sequence/sequence.h b/app/project/item/sequence/sequence.h index 5eeee3cb5..aab7920df 100644 --- a/app/project/item/sequence/sequence.h +++ b/app/project/item/sequence/sequence.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,7 +29,7 @@ #include "project/item/item.h" #include "timeline/timelinepoints.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Sequence; using SequencePtr = std::shared_ptr; @@ -45,7 +45,7 @@ public: /** * @brief Load function */ - virtual void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt* cancelled) override; + virtual void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, uint version, const QAtomicInt* cancelled) override; /** * @brief Save function @@ -84,6 +84,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // SEQUENCE_H diff --git a/app/project/project.cpp b/app/project/project.cpp index 6cf8342e9..84f15dd8b 100644 --- a/app/project/project.cpp +++ b/app/project/project.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,7 +29,7 @@ #include "render/diskmanager.h" #include "window/mainwindow/mainwindow.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Project::Project() : is_modified_(false), @@ -43,14 +43,14 @@ Project::Project() : this, &Project::DefaultColorSpaceChanged); } -void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, const QAtomicInt* cancelled) +void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, uint version, const QAtomicInt* cancelled) { XMLNodeData xml_node_data; while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("root")) { - root_.Load(reader, xml_node_data, cancelled); + root_.Load(reader, xml_node_data, version, cancelled); } else if (reader->name() == QStringLiteral("colormanagement")) { @@ -228,4 +228,4 @@ void Project::DefaultColorSpaceChanged() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/project/project.h b/app/project/project.h index b96dcff85..d6d801ca5 100644 --- a/app/project/project.h +++ b/app/project/project.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "project/item/folder/folder.h" #include "window/mainwindow/mainwindowlayoutinfo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A project instance containing all the data pertaining to the user's project @@ -47,7 +47,7 @@ class Project : public QObject public: Project(); - void Load(QXmlStreamReader* reader, MainWindowLayoutInfo *layout, const QAtomicInt* cancelled); + void Load(QXmlStreamReader* reader, MainWindowLayoutInfo *layout, uint version, const QAtomicInt* cancelled); void Save(QXmlStreamWriter* writer) const; @@ -103,8 +103,6 @@ private slots: }; -using ProjectPtr = std::shared_ptr; - -OLIVE_NAMESPACE_EXIT +} #endif // PROJECT_H diff --git a/app/project/projectviewmodel.cpp b/app/project/projectviewmodel.cpp index a1ba9b481..f11135e3e 100644 --- a/app/project/projectviewmodel.cpp +++ b/app/project/projectviewmodel.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "core.h" #include "node/input/media/media.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectViewModel::ProjectViewModel(QObject *parent) : QAbstractItemModel(parent), @@ -509,7 +509,7 @@ ProjectViewModel::MoveItemCommand::MoveItemCommand(ProjectViewModel *model, { source_ = static_cast(item->parent()); - setText(tr("Move Item")); + setText(QCoreApplication::translate("MoveItemCommand", "Move Item")); } Project *ProjectViewModel::MoveItemCommand::GetRelevantProject() const @@ -535,7 +535,7 @@ ProjectViewModel::RenameItemCommand::RenameItemCommand(ProjectViewModel* model, { old_name_ = item->name(); - setText(tr("Rename Item")); + setText(QCoreApplication::translate("RenameItemCommand", "Rename Item")); } Project *ProjectViewModel::RenameItemCommand::GetRelevantProject() const @@ -604,4 +604,4 @@ void ProjectViewModel::RemoveItemCommand::undo_internal() model_->AddChild(parent_, item_); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/project/projectviewmodel.h b/app/project/projectviewmodel.h index e3de6e33a..e524684ba 100644 --- a/app/project/projectviewmodel.h +++ b/app/project/projectviewmodel.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "undo/undocommand.h" #include "node/block/block.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief An adapter that interprets the data in a Project into a Qt item model for usage in ViewModel Views. @@ -39,6 +39,7 @@ OLIVE_NAMESPACE_ENTER */ class ProjectViewModel : public QAbstractItemModel { + Q_OBJECT public: enum ColumnType { /// Media name @@ -250,6 +251,6 @@ private: QVector columns_; }; -OLIVE_NAMESPACE_EXIT +} #endif // VIEWMODEL_H diff --git a/app/render/CMakeLists.txt b/app/render/CMakeLists.txt index 709a8c5e5..986160959 100644 --- a/app/render/CMakeLists.txt +++ b/app/render/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -14,35 +14,50 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -add_subdirectory(backend) +add_subdirectory(job) add_subdirectory(ocioconf) +add_subdirectory(opengl) set(OLIVE_SOURCES ${OLIVE_SOURCES} - render/audioparams.h render/audioparams.cpp - render/audioplaybackcache.h + render/audioparams.h render/audioplaybackcache.cpp - render/color.h + render/audioplaybackcache.h render/color.cpp - render/colormanager.h + render/color.h render/colormanager.cpp - render/colorprocessor.h + render/colormanager.h render/colorprocessor.cpp - render/diskmanager.h + render/colorprocessor.h + render/colorprocessorcache.h render/diskmanager.cpp - render/framehashcache.h + render/diskmanager.h render/framehashcache.cpp - render/managedcolor.h + render/framehashcache.h render/managedcolor.cpp - render/pixelformat.h - render/pixelformat.cpp - render/playbackcache.h + render/managedcolor.h render/playbackcache.cpp + render/playbackcache.h + render/previewautocacher.cpp + render/previewautocacher.h + render/renderer.cpp + render/renderer.h + render/rendercache.h + render/rendererthreadwrapper.cpp + render/rendererthreadwrapper.h + render/rendermanager.cpp + render/rendermanager.h render/rendermodes.h - render/shaderinfo.h - render/videoparams.h + render/renderprocessor.cpp + render/renderprocessor.h + render/shadercode.h + render/shadervalue.h + render/stillimagecache.h + render/texture.cpp + render/texture.h render/videoparams.cpp + render/videoparams.h PARENT_SCOPE ) diff --git a/app/render/audioparams.cpp b/app/render/audioparams.cpp index 9fb1ec2e1..fa16a4838 100644 --- a/app/render/audioparams.cpp +++ b/app/render/audioparams.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ extern "C" { #include -OLIVE_NAMESPACE_ENTER +namespace olive { const QVector AudioParams::kSupportedSampleRates = { 8000, // 8000 Hz @@ -49,6 +49,8 @@ const QVector AudioParams::kSupportedChannelLayouts = { AV_CH_LAYOUT_7POINT1 }; +const AudioParams::Format AudioParams::kInternalFormat = AudioParams::kFormatFloat32; + qint64 AudioParams::time_to_bytes(const double &time) const { Q_ASSERT(is_valid()); @@ -68,43 +70,63 @@ bool AudioParams::operator!=(const AudioParams &other) const return !(*this == other); } +QAudioFormat::SampleType AudioParams::GetQtSampleType(AudioParams::Format format) +{ + switch (format) { + case kFormatUnsigned8: + return QAudioFormat::UnSignedInt; + case kFormatSigned16: + case kFormatSigned32: + case kFormatSigned64: + return QAudioFormat::SignedInt; + case kFormatFloat32: + case kFormatFloat64: + return QAudioFormat::Float; + case kFormatInvalid: + case kFormatCount: + break; + } + + return QAudioFormat::Unknown; +} + qint64 AudioParams::time_to_bytes(const rational &time) const { return time_to_bytes(time.toDouble()); } -int AudioParams::time_to_samples(const double &time) const +qint64 AudioParams::time_to_samples(const double &time) const { Q_ASSERT(is_valid()); - return qFloor(time * sample_rate()); + return qRound64(time * sample_rate()); } -int AudioParams::time_to_samples(const rational &time) const +qint64 AudioParams::time_to_samples(const rational &time) const { return time_to_samples(time.toDouble()); } -int AudioParams::samples_to_bytes(const int &samples) const +qint64 AudioParams::samples_to_bytes(const qint64 &samples) const { Q_ASSERT(is_valid()); return samples * channel_count() * bytes_per_sample_per_channel(); } -rational AudioParams::samples_to_time(const int &samples) const +rational AudioParams::samples_to_time(const qint64 &samples) const { return rational(samples, sample_rate()); } -int AudioParams::bytes_to_samples(const int &bytes) const +qint64 AudioParams::bytes_to_samples(const qint64 &bytes) const { Q_ASSERT(is_valid()); return bytes / (channel_count() * bytes_per_sample_per_channel()); } -rational AudioParams::bytes_to_time(const int &bytes) const +rational AudioParams::bytes_to_time(const qint64 &bytes) const { Q_ASSERT(is_valid()); @@ -119,18 +141,18 @@ int AudioParams::channel_count() const int AudioParams::bytes_per_sample_per_channel() const { switch (format_) { - case SampleFormat::SAMPLE_FMT_U8: + case kFormatUnsigned8: return 1; - case SampleFormat::SAMPLE_FMT_S16: + case kFormatSigned16: return 2; - case SampleFormat::SAMPLE_FMT_S32: - case SampleFormat::SAMPLE_FMT_FLT: + case kFormatSigned32: + case kFormatFloat32: return 4; - case SampleFormat::SAMPLE_FMT_DBL: - case SampleFormat::SAMPLE_FMT_S64: + case kFormatSigned64: + case kFormatFloat64: return 8; - case SampleFormat::SAMPLE_FMT_INVALID: - case SampleFormat::SAMPLE_FMT_COUNT: + case kFormatInvalid: + case kFormatCount: break; } @@ -146,8 +168,8 @@ bool AudioParams::is_valid() const { return (sample_rate() > 0 && channel_layout() > 0 - && format_ != SampleFormat::SAMPLE_FMT_INVALID - && format_ != SampleFormat::SAMPLE_FMT_COUNT); + && format_ > kFormatInvalid + && format_ < kFormatCount); } QString AudioParams::SampleRateToString(const int &sample_rate) @@ -173,4 +195,4 @@ QString AudioParams::ChannelLayoutToString(const uint64_t &layout) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/render/audioparams.h b/app/render/audioparams.h index 521218e0e..989fbf959 100644 --- a/app/render/audioparams.h +++ b/app/render/audioparams.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,23 +21,51 @@ #ifndef AUDIOPARAMS_H #define AUDIOPARAMS_H +#include #include -#include "audio/sampleformat.h" #include "common/rational.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class AudioParams { public: + enum Format { + /// Invalid + kFormatInvalid = -1, + + /// 8-bit unsigned integer + kFormatUnsigned8, + + /// 16-bit signed integer + kFormatSigned16, + + /// 32-bit signed integer + kFormatSigned32, + + /// 64-bit signed integer + kFormatSigned64, + + /// 32-bit float + kFormatFloat32, + + /// 64-bit float + kFormatFloat64, + + /// Total format count + kFormatCount + }; + + static const Format kInternalFormat; + AudioParams() : sample_rate_(0), channel_layout_(0), - format_(SampleFormat::SAMPLE_FMT_INVALID) + format_(kFormatInvalid) { } - AudioParams(const int& sample_rate, const uint64_t& channel_layout, const SampleFormat::Format& format) : + AudioParams(const int& sample_rate, const uint64_t& channel_layout, const Format& format) : sample_rate_(sample_rate), channel_layout_(channel_layout), format_(format) @@ -59,19 +87,19 @@ public: return rational(1, sample_rate()); } - const SampleFormat::Format &format() const + const Format &format() const { return format_; } qint64 time_to_bytes(const double& time) const; qint64 time_to_bytes(const rational& time) const; - int time_to_samples(const double& time) const; - int time_to_samples(const rational& time) const; - int samples_to_bytes(const int& samples) const; - rational samples_to_time(const int& samples) const; - int bytes_to_samples(const int &bytes) const; - rational bytes_to_time(const int &bytes) const; + qint64 time_to_samples(const double& time) const; + qint64 time_to_samples(const rational& time) const; + qint64 samples_to_bytes(const qint64& samples) const; + rational samples_to_time(const qint64& samples) const; + qint64 bytes_to_samples(const qint64 &bytes) const; + rational bytes_to_time(const qint64 &bytes) const; int channel_count() const; int bytes_per_sample_per_channel() const; int bits_per_sample() const; @@ -80,6 +108,8 @@ public: bool operator==(const AudioParams& other) const; bool operator!=(const AudioParams& other) const; + static QAudioFormat::SampleType GetQtSampleType(Format format); + static const QVector kSupportedChannelLayouts; static const QVector kSupportedSampleRates; @@ -98,12 +128,12 @@ private: uint64_t channel_layout_; - SampleFormat::Format format_; + Format format_; }; -OLIVE_NAMESPACE_EXIT +} -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::AudioParams) +Q_DECLARE_METATYPE(olive::AudioParams) #endif // AUDIOPARAMS_H diff --git a/app/render/audioplaybackcache.cpp b/app/render/audioplaybackcache.cpp index eda8ae905..9a31dc5ad 100644 --- a/app/render/audioplaybackcache.cpp +++ b/app/render/audioplaybackcache.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/filefunctions.h" -OLIVE_NAMESPACE_ENTER +namespace olive { const qint64 AudioPlaybackCache::kDefaultSegmentSize = 5242880; @@ -127,7 +127,7 @@ void AudioPlaybackCache::WritePCM(const TimeRange &range, SampleBufferPtr sample seg_file.close(); - ranges_we_validated.InsertTimeRange(TimeRange(this_write_in_point, this_write_out_point)); + ranges_we_validated.insert(TimeRange(this_write_in_point, this_write_out_point)); } else { qWarning() << "Failed to write PCM data to" << seg_file.fileName(); } @@ -157,7 +157,7 @@ void AudioPlaybackCache::WriteSilence(const TimeRange &range, qint64 job_time) void AudioPlaybackCache::ShiftEvent(const rational &from_in_time, const rational &to_in_time) { - if (from_in_time == to_in_time) { + if (from_in_time == to_in_time || from_in_time >= GetLength()) { // Nothing to be done return; } @@ -538,4 +538,4 @@ qint64 AudioPlaybackCache::Playlist::GetLength() const return this->last().offset() + this->last().size(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/render/audioplaybackcache.h b/app/render/audioplaybackcache.h index 8b4419b9d..3ea9973a2 100644 --- a/app/render/audioplaybackcache.h +++ b/app/render/audioplaybackcache.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "codec/samplebuffer.h" #include "render/playbackcache.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A fully integrated system of storing and playing cached audio @@ -214,6 +214,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // AUDIOPLAYBACKCACHE_H diff --git a/app/render/backend/opengl/CMakeLists.txt b/app/render/backend/opengl/CMakeLists.txt deleted file mode 100644 index f1a46cbd7..000000000 --- a/app/render/backend/opengl/CMakeLists.txt +++ /dev/null @@ -1,38 +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 . - -set(OLIVE_SOURCES - ${OLIVE_SOURCES} - render/backend/opengl/openglbackend.h - render/backend/opengl/openglbackend.cpp - render/backend/opengl/openglcolorprocessor.h - render/backend/opengl/openglcolorprocessor.cpp - render/backend/opengl/openglframebuffer.h - render/backend/opengl/openglframebuffer.cpp - render/backend/opengl/openglproxy.h - render/backend/opengl/openglproxy.cpp - render/backend/opengl/openglrenderfunctions.h - render/backend/opengl/openglrenderfunctions.cpp - render/backend/opengl/openglshader.h - render/backend/opengl/openglshader.cpp - render/backend/opengl/opengltexture.h - render/backend/opengl/opengltexture.cpp - render/backend/opengl/opengltexturecache.h - render/backend/opengl/opengltexturecache.cpp - render/backend/opengl/openglworker.h - render/backend/opengl/openglworker.cpp - PARENT_SCOPE -) diff --git a/app/render/backend/opengl/openglcolorprocessor.cpp b/app/render/backend/opengl/openglcolorprocessor.cpp deleted file mode 100644 index bc0993f4f..000000000 --- a/app/render/backend/opengl/openglcolorprocessor.cpp +++ /dev/null @@ -1,90 +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 "openglcolorprocessor.h" - -#include -#include - -#include "openglrenderfunctions.h" - -OLIVE_NAMESPACE_ENTER - -void OpenGLColorProcessor::Enable(QOpenGLContext *context, bool alpha_is_associated) -{ - if (IsEnabled()) { - return; - } - - context_ = context; - - pipeline_ = OpenGLShader::CreateOCIO(context_, - ocio_lut_, - GetProcessor(), - alpha_is_associated); - - connect(context_, &QOpenGLContext::aboutToBeDestroyed, this, &OpenGLColorProcessor::ClearTexture, Qt::DirectConnection); -} - -bool OpenGLColorProcessor::IsEnabled() const -{ - return ocio_lut_; -} - -OpenGLShaderPtr OpenGLColorProcessor::pipeline() const -{ - return pipeline_; -} - -void OpenGLColorProcessor::ProcessOpenGL(bool flipped, const QMatrix4x4& matrix) -{ - OpenGLRenderFunctions::OCIOBlit(pipeline_, ocio_lut_, flipped, matrix); -} - -void OpenGLColorProcessor::ClearTexture() -{ - if (IsEnabled()) { - // Clean up OCIO LUT texture and shader - context_->functions()->glDeleteTextures(1, &ocio_lut_); - - disconnect(context_, &QOpenGLContext::aboutToBeDestroyed, this, &OpenGLColorProcessor::ClearTexture); - - ocio_lut_ = 0; - pipeline_ = nullptr; - } -} - -OpenGLColorProcessor::OpenGLColorProcessor(ColorManager* config, const QString &source_space, const ColorTransform &dest_space) : - ColorProcessor(config, source_space, dest_space), - ocio_lut_(0) -{ -} - -OpenGLColorProcessor::~OpenGLColorProcessor() -{ - ClearTexture(); -} - -OpenGLColorProcessorPtr OpenGLColorProcessor::Create(ColorManager *config, const QString &source_space, const ColorTransform &dest_space) -{ - return std::make_shared(config, source_space, dest_space); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/opengl/openglcolorprocessor.h b/app/render/backend/opengl/openglcolorprocessor.h deleted file mode 100644 index bd8e6dc9c..000000000 --- a/app/render/backend/opengl/openglcolorprocessor.h +++ /dev/null @@ -1,69 +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 . - -***/ - -#ifndef OPENGLCOLORPROCESSOR_H -#define OPENGLCOLORPROCESSOR_H - -#include "openglshader.h" -#include "render/colorprocessor.h" - -OLIVE_NAMESPACE_ENTER - -class OpenGLColorProcessor; -using OpenGLColorProcessorPtr = std::shared_ptr; - -class OpenGLColorProcessor : public QObject, public ColorProcessor -{ - Q_OBJECT -public: - OpenGLColorProcessor(ColorManager *config, - const QString& input, - const ColorTransform& dest); - - virtual ~OpenGLColorProcessor() override; - - static OpenGLColorProcessorPtr Create(ColorManager* config, - const QString& input, - const ColorTransform& dest); - - void Enable(QOpenGLContext* context, bool alpha_is_associated); - bool IsEnabled() const; - - OpenGLShaderPtr pipeline() const; - - void ProcessOpenGL(bool flipped = false, const QMatrix4x4& matrix = QMatrix4x4()); - -private: - QOpenGLContext* context_; - - GLuint ocio_lut_; - - OpenGLShaderPtr pipeline_; - -private slots: - void ClearTexture(); - -}; - -using OpenGLColorProcessorCache = QHash; - -OLIVE_NAMESPACE_EXIT - -#endif // OPENGLCOLORPROCESSOR_H diff --git a/app/render/backend/opengl/openglframebuffer.cpp b/app/render/backend/opengl/openglframebuffer.cpp deleted file mode 100644 index e31ce50b3..000000000 --- a/app/render/backend/opengl/openglframebuffer.cpp +++ /dev/null @@ -1,153 +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 "openglframebuffer.h" - -#include -#include - -OLIVE_NAMESPACE_ENTER - -OpenGLFramebuffer::OpenGLFramebuffer() : - context_(nullptr), - buffer_(0), - texture_(nullptr) -{ -} - -OpenGLFramebuffer::~OpenGLFramebuffer() -{ - Destroy(); -} - -void OpenGLFramebuffer::Create(QOpenGLContext *ctx) -{ - if (ctx == nullptr) { - qWarning() << "OpenGLFramebuffer::Create was passed an invalid context"; - return; - } - - // Free any previous framebuffer - Destroy(); - - context_ = ctx; - - connect(context_, &QOpenGLContext::aboutToBeDestroyed, this, &OpenGLFramebuffer::Destroy); - - // Create framebuffer object - context_->functions()->glGenFramebuffers(1, &buffer_); -} - -void OpenGLFramebuffer::Destroy() -{ - if (context_ != nullptr) { - disconnect(context_, &QOpenGLContext::aboutToBeDestroyed, this, &OpenGLFramebuffer::Destroy); - - context_->functions()->glDeleteFramebuffers(1, &buffer_); - - buffer_ = 0; - - context_ = nullptr; - } -} - -bool OpenGLFramebuffer::IsCreated() const -{ - return (buffer_ > 0); -} - -void OpenGLFramebuffer::Bind() -{ - if (context_ == nullptr) { - return; - } - context_->functions()->glBindFramebuffer(GL_FRAMEBUFFER, buffer_); -} - -void OpenGLFramebuffer::Release() -{ - if (context_ == nullptr) { - return; - } - context_->functions()->glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -void OpenGLFramebuffer::Attach(OpenGLTexture *texture, bool clear) -{ - if (context_ == nullptr) { - return; - } - - Detach(); - - texture_ = texture; - - QOpenGLFunctions* f = context_->functions(); - - // bind framebuffer for attaching - f->glBindFramebuffer(GL_FRAMEBUFFER, buffer_); - - context_->extraFunctions()->glFramebufferTexture2D( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_->texture(), 0 - ); - - if (clear) { - context_->functions()->glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - context_->functions()->glClear(GL_COLOR_BUFFER_BIT); - } - - // release framebuffer - f->glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -void OpenGLFramebuffer::Attach(OpenGLTexturePtr texture, bool clear) -{ - Attach(texture.get(), clear); -} - -void OpenGLFramebuffer::Detach() -{ - if (context_ == nullptr) { - return; - } - - if (texture_) { - QOpenGLFunctions* f = context_->functions(); - - // bind framebuffer for attaching - f->glBindFramebuffer(GL_FRAMEBUFFER, buffer_); - - context_->extraFunctions()->glFramebufferTexture2D( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0 - ); - - // release framebuffer - f->glBindFramebuffer(GL_FRAMEBUFFER, 0); - - texture_ = nullptr; - } -} - -const GLuint &OpenGLFramebuffer::buffer() const -{ - return buffer_; -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/opengl/openglproxy.cpp b/app/render/backend/opengl/openglproxy.cpp deleted file mode 100644 index 1db21e0b3..000000000 --- a/app/render/backend/opengl/openglproxy.cpp +++ /dev/null @@ -1,567 +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 "openglproxy.h" - -#include - -#include "common/clamp.h" -#include "core.h" -#include "node/block/transition/transition.h" -#include "node/node.h" -#include "openglcolorprocessor.h" -#include "openglrenderfunctions.h" -#include "render/colormanager.h" -#include "render/pixelformat.h" - -OLIVE_NAMESPACE_ENTER - -OpenGLProxy* OpenGLProxy::instance_ = nullptr; - -OpenGLProxy::OpenGLProxy(QObject *parent) : - QObject(parent), - ctx_(nullptr), - functions_(nullptr) -{ - surface_.create(); -} - -OpenGLProxy::~OpenGLProxy() -{ - Close(); - - surface_.destroy(); -} - -void OpenGLProxy::CreateInstance() -{ - instance_ = new OpenGLProxy(); - - QThread* proxy_thread = new QThread(); - proxy_thread->start(QThread::IdlePriority); - instance_->moveToThread(proxy_thread); - - if (!instance_->Init()) { - DestroyInstance(); - } -} - -void OpenGLProxy::DestroyInstance() -{ - if (instance_) { - instance_->thread()->quit(); - instance_->thread()->wait(); - instance_->thread()->deleteLater(); - instance_->deleteLater(); - instance_ = nullptr; - } -} - -bool OpenGLProxy::Init() -{ - // Create context object - ctx_ = new QOpenGLContext(); - - // Create OpenGL context (automatically destroys any existing if there is one) - if (!ctx_->create()) { - qWarning() << "Failed to create OpenGL context in thread" << thread(); - return false; - } - - ctx_->moveToThread(this->thread()); - - // The rest of the initialization needs to occur in the other thread, so we signal for it to start - QMetaObject::invokeMethod(this, "FinishInit", Qt::QueuedConnection); - - return true; -} - -QVariant OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream, const VideoParams& params, const RenderMode::Mode& mode) -{ - VideoStreamPtr video_stream = std::static_pointer_cast(stream); - - // Set up OCIO context - QString colorspace_match = video_stream->get_colorspace_match_string(); - - OpenGLColorProcessorPtr color_processor = std::static_pointer_cast(color_cache_.value(colorspace_match)); - - if (!color_processor) { - color_processor = OpenGLColorProcessor::Create(video_stream->footage()->project()->color_manager(), - video_stream->colorspace(), - video_stream->footage()->project()->color_manager()->GetReferenceColorSpace()); - color_cache_.insert(colorspace_match, color_processor); - } - - ColorManager::OCIOMethod ocio_method = ColorManager::GetOCIOMethodForMode(mode); - - // OCIO's CPU conversion is more accurate, so for online we render on CPU but offline we render GPU - if (ocio_method == ColorManager::kOCIOAccurate) { - bool has_alpha = PixelFormat::FormatHasAlphaChannel(frame->format()); - - // Convert frame to float for OCIO - frame = PixelFormat::ConvertPixelFormat(frame, - has_alpha - ? PixelFormat::PIX_FMT_RGBA32F - : PixelFormat::PIX_FMT_RGB32F); - - // If alpha is associated, disassociate for the color transform - if (has_alpha && video_stream->premultiplied_alpha()) { - ColorManager::DisassociateAlpha(frame); - } - - // Perform color transform - color_processor->ConvertFrame(frame); - - // Associate alpha - if (has_alpha) { - if (video_stream->premultiplied_alpha()) { - ColorManager::ReassociateAlpha(frame); - } else { - ColorManager::AssociateAlpha(frame); - } - } - } - - OpenGLTextureCache::ReferencePtr footage_tex_ref = texture_cache_.Get(ctx_, frame); - - if (ocio_method == ColorManager::kOCIOFast) { - if (!color_processor->IsEnabled()) { - color_processor->Enable(ctx_, video_stream->premultiplied_alpha()); - } - - VideoParams frame_params = frame->video_params(); - - PixelFormat::Format texture_fmt; - if (PixelFormat::FormatHasAlphaChannel(frame_params.format())) { - texture_fmt = PixelFormat::GetFormatWithAlphaChannel(params.format()); - } else { - texture_fmt = PixelFormat::GetFormatWithoutAlphaChannel(params.format()); - } - - VideoParams dest_params(frame_params.width(), - frame_params.height(), - texture_fmt, - frame_params.pixel_aspect_ratio(), - frame_params.interlacing(), - frame_params.divider()); - - // Create destination texture - OpenGLTextureCache::ReferencePtr associated_tex_ref = texture_cache_.Get(ctx_, dest_params); - - buffer_.Attach(associated_tex_ref->texture(), true); - buffer_.Bind(); - footage_tex_ref->texture()->Bind(); - - // Set viewport for texture size - functions_->glViewport(0, 0, associated_tex_ref->texture()->width(), associated_tex_ref->texture()->height()); - - // Blit old texture to new texture through OCIO shader - color_processor->ProcessOpenGL(); - - footage_tex_ref->texture()->Release(); - buffer_.Release(); - buffer_.Detach(); - - footage_tex_ref = associated_tex_ref; - } - - return QVariant::fromValue(footage_tex_ref); -} - -QVariant OpenGLProxy::PreCachedFrameToValue(FramePtr frame) -{ - return QVariant::fromValue(texture_cache_.Get(ctx_, frame)); -} - -OpenGLShaderPtr OpenGLProxy::ResolveShaderFromCache(const Node *node, const QString &shader_id) -{ - // Make a composite of the node ID and the shader ID (if applicable) - QString full_shader_id = QStringLiteral("%1:%2").arg(node->id(), shader_id); - OpenGLShaderPtr shader = shader_cache_.value(full_shader_id); - - if (!shader) { - // Since we have shader code, compile it now - ShaderCode code = node->GetShaderCode(shader_id); - QString vert_code = code.vert_code(); - QString frag_code = code.frag_code(); - - if (frag_code.isEmpty() && vert_code.isEmpty()) { - qWarning() << "No shader code found for" << node->id() << "- operation will be a no-op"; - } - - if (frag_code.isEmpty()) { - frag_code = OpenGLShader::CodeDefaultFragment(); - } - - if (vert_code.isEmpty()) { - vert_code = OpenGLShader::CodeDefaultVertex(); - } - - shader = OpenGLShader::Create(); - if (shader - && shader->create() - && shader->addShaderFromSourceCode(QOpenGLShader::Fragment, frag_code) - && shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vert_code) - && shader->link()) { - shader_cache_.insert(full_shader_id, shader); - } else { - qWarning() << "Failed to compile shader for" << node->id(); - shader = nullptr; - } - } - - return shader; -} - -void OpenGLProxy::Close() -{ - shader_cache_.clear(); - buffer_.Destroy(); - copy_pipeline_ = nullptr; - functions_ = nullptr; - delete ctx_; - ctx_ = nullptr; -} - -QVariant OpenGLProxy::RunNodeAccelerated(const Node *node, - const TimeRange &range, - const ShaderJob &job, - const VideoParams& params) -{ - // If this node is iterative, we'll pick up which input here - GLuint iterative_input = 0; - QList textures_to_bind; - bool input_textures_have_alpha = false; - - OpenGLShaderPtr shader = ResolveShaderFromCache(node, job.GetShaderID()); - - if (!shader) { - return QVariant(); - } - - shader->bind(); - - NodeValueMap::const_iterator it; - for (it=job.GetValues().constBegin(); it!=job.GetValues().constEnd(); it++) { - // See if the shader has takes this parameter as an input - int variable_location = shader->uniformLocation(it.key()); - - if (variable_location == -1) { - continue; - } - - // See if this value corresponds to an input (NOTE: it may not and this may be null) - NodeInput* corresponding_input = node->GetInputWithID(it.key()); - - // This variable is used in the shader, let's set it - const QVariant& value = it.value().data(); - - NodeParam::DataType data_type = (it.value().type() != NodeParam::kNone) - ? it.value().type() - : corresponding_input->data_type(); - - switch (data_type) { - case NodeInput::kInt: - // kInt technically specifies a LongLong, but OpenGL doesn't support those. This may lead to - // over/underflows if the number is large enough, but the likelihood of that is quite low. - shader->setUniformValue(variable_location, value.toInt()); - break; - case NodeInput::kFloat: - // kFloat technically specifies a double but as above, OpenGL doesn't support those. - shader->setUniformValue(variable_location, value.toFloat()); - break; - case NodeInput::kVec2: - if (corresponding_input && corresponding_input->IsArray()) { - QVector nv = value.value< QVector >(); - QVector a(nv.size()); - - for (int j=0;j(); - } - - shader->setUniformValueArray(variable_location, a.constData(), a.size()); - - int count_location = shader->uniformLocation(QStringLiteral("%1_count").arg(it.key())); - if (count_location > -1) { - shader->setUniformValue(count_location, a.size()); - } - } else { - shader->setUniformValue(variable_location, value.value()); - } - break; - case NodeInput::kVec3: - shader->setUniformValue(variable_location, value.value()); - break; - case NodeInput::kVec4: - shader->setUniformValue(variable_location, value.value()); - break; - case NodeInput::kMatrix: - shader->setUniformValue(variable_location, value.value()); - break; - case NodeInput::kCombo: - shader->setUniformValue(variable_location, value.value()); - break; - case NodeInput::kColor: - { - Color color = value.value(); - - shader->setUniformValue(variable_location, color.red(), color.green(), color.blue(), color.alpha()); - break; - } - case NodeInput::kBoolean: - shader->setUniformValue(variable_location, value.toBool()); - break; - case NodeInput::kBuffer: - case NodeInput::kTexture: - { - OpenGLTextureCache::ReferencePtr texture = value.value(); - - if (texture) { - if (PixelFormat::FormatHasAlphaChannel(texture->texture()->format())) { - input_textures_have_alpha = true; - } - } - - // Set value to bound texture - shader->setUniformValue(variable_location, textures_to_bind.size()); - - // If this texture binding is the iterative input, set it here - if (corresponding_input && corresponding_input == job.GetIterativeInput()) { - iterative_input = textures_to_bind.size(); - } - - GLuint tex_id = texture ? texture->texture()->texture() : 0; - textures_to_bind.append(tex_id); - - // Set enable flag if shader wants it - int enable_param_location = shader->uniformLocation(QStringLiteral("%1_enabled").arg(it.key())); - if (enable_param_location > -1) { - shader->setUniformValue(enable_param_location, - tex_id > 0); - } - - if (tex_id > 0) { - // Set texture resolution if shader wants it - int res_param_location = shader->uniformLocation(QStringLiteral("%1_resolution").arg(it.key())); - if (res_param_location > -1) { - int adjusted_width = texture->texture()->width() * texture->texture()->divider(); - - // Adjust virtual width by pixel aspect if necessary - if (texture->texture()->params().pixel_aspect_ratio() != 1 - || params.pixel_aspect_ratio() != 1) { - double relative_pixel_aspect = texture->texture()->params().pixel_aspect_ratio().toDouble() / params.pixel_aspect_ratio().toDouble(); - - adjusted_width = qRound(static_cast(adjusted_width) * relative_pixel_aspect); - } - - shader->setUniformValue(res_param_location, - adjusted_width, - static_cast(texture->texture()->height() * texture->texture()->divider())); - } - } - break; - } - case NodeInput::kSamples: - case NodeInput::kText: - case NodeInput::kRational: - case NodeInput::kFont: - case NodeInput::kFile: - case NodeInput::kDecimal: - case NodeInput::kNumber: - case NodeInput::kString: - case NodeInput::kVector: - case NodeInput::kShaderJob: - case NodeInput::kSampleJob: - case NodeInput::kGenerateJob: - case NodeInput::kFootage: - case NodeInput::kNone: - case NodeInput::kAny: - break; - } - } - - // Provide some standard args - shader->setUniformValue("ove_resolution", - static_cast(params.width()), - static_cast(params.height())); - - shader->release(); - - // Create the output textures - PixelFormat::Format output_format = (input_textures_have_alpha || job.GetAlphaChannelRequired()) - ? PixelFormat::GetFormatWithAlphaChannel(params.format()) - : PixelFormat::GetFormatWithoutAlphaChannel(params.format()); - VideoParams output_params(params.width(), - params.height(), - params.time_base(), - output_format, - params.pixel_aspect_ratio(), - params.interlacing(), - params.divider()); - - int real_iteration_count; - if (job.GetIterationCount() > 1 && job.GetIterativeInput()) { - real_iteration_count = job.GetIterationCount(); - } else { - real_iteration_count = 1; - } - - OpenGLTextureCache::ReferencePtr dst_refs[2]; - dst_refs[0] = texture_cache_.Get(ctx_, output_params); - - // If this node requires multiple iterations, get a texture for it too - if (real_iteration_count > 1) { - dst_refs[1] = texture_cache_.Get(ctx_, output_params); - } - - // Some nodes use multiple iterations for optimization - OpenGLTextureCache::ReferencePtr input_tex, output_tex; - - // Set up OpenGL parameters as necessary - functions_->glViewport(0, 0, params.effective_width(), params.effective_height()); - - // Bind all textures - for (int i=0; iglActiveTexture(GL_TEXTURE0 + i); - functions_->glBindTexture(GL_TEXTURE_2D, textures_to_bind.at(i)); - OpenGLRenderFunctions::PrepareToDraw(functions_); - } - - for (int iteration=0; iterationbind(); - shader->setUniformValue("ove_iteration", iteration); - shader->release(); - - // Replace iterative input - if (iteration == 0) { - output_tex = dst_refs[0]; - } else { - input_tex = dst_refs[(iteration+1)%2]; - output_tex = dst_refs[iteration%2]; - - functions_->glActiveTexture(GL_TEXTURE0 + iterative_input); - functions_->glBindTexture(GL_TEXTURE_2D, input_tex->texture()->texture()); - OpenGLRenderFunctions::PrepareToDraw(functions_); - } - - buffer_.Attach(output_tex->texture(), true); - buffer_.Bind(); - - // Blit this texture through this shader - OpenGLRenderFunctions::Blit(shader); - - buffer_.Release(); - buffer_.Detach(); - } - - // Release any textures we bound before - for (int i=textures_to_bind.size()-1; i>=0; i--) { - functions_->glActiveTexture(GL_TEXTURE0 + i); - functions_->glBindTexture(GL_TEXTURE_2D, 0); - } - - return QVariant::fromValue(output_tex); -} - -void OpenGLProxy::TextureToBuffer(const QVariant& tex_in, - FramePtr frame, - const QMatrix4x4& matrix) -{ - OpenGLTextureCache::ReferencePtr texture = tex_in.value(); - - if (!texture) { - return; - } - - OpenGLTextureCache::ReferencePtr download_tex; - - if (!frame->is_allocated()) { - // If the frame isn't allocated, we'll assume that we're allocating it to the texture dimensions - frame->set_video_params(texture->texture()->params()); - frame->allocate(); - } - - functions_->glViewport(0, 0, frame->width(), frame->height()); - - if (frame->width() != texture->texture()->width() - || frame->height() != texture->texture()->height()) { - - // Resize the texture if necessary - OpenGLTextureCache::ReferencePtr resized = texture_cache_.Get(ctx_, frame->video_params()); - - buffer_.Attach(resized->texture(), true); - buffer_.Bind(); - - texture->texture()->Bind(); - - // Blit to this new texture - OpenGLRenderFunctions::Blit(copy_pipeline_, false, matrix); - - texture->texture()->Release(); - - buffer_.Release(); - buffer_.Detach(); - - download_tex = resized; - - } else { - - download_tex = texture; - - } - - buffer_.Attach(download_tex->texture()); - buffer_.Bind(); - - functions_->glPixelStorei(GL_PACK_ROW_LENGTH, frame->linesize_pixels()); - - functions_->glReadPixels(0, - 0, - frame->width(), - frame->height(), - OpenGLRenderFunctions::GetPixelFormat(frame->format()), - OpenGLRenderFunctions::GetPixelType(frame->format()), - frame->data()); - - functions_->glPixelStorei(GL_PACK_ROW_LENGTH, 0); - - buffer_.Release(); - buffer_.Detach(); -} - -void OpenGLProxy::FinishInit() -{ - // Make context current on that surface - if (!ctx_->makeCurrent(&surface_)) { - qWarning() << "Failed to makeCurrent() on offscreen surface in thread" << thread(); - return; - } - - // Store OpenGL functions instance - functions_ = ctx_->functions(); - functions_->glBlendFunc(GL_ONE, GL_ZERO); - - buffer_.Create(ctx_); - - copy_pipeline_ = OpenGLShader::CreateDefault(); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/opengl/openglproxy.h b/app/render/backend/opengl/openglproxy.h deleted file mode 100644 index ff59f76b9..000000000 --- a/app/render/backend/opengl/openglproxy.h +++ /dev/null @@ -1,122 +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 . - -***/ - -#ifndef OPENGLPROXY_H -#define OPENGLPROXY_H - -#include -#include - -#include "common/timerange.h" -#include "node/value.h" -#include "openglcolorprocessor.h" -#include "openglframebuffer.h" -#include "opengltexturecache.h" -#include "render/shaderinfo.h" - -OLIVE_NAMESPACE_ENTER - -class OpenGLProxy : public QObject -{ - Q_OBJECT -public: - OpenGLProxy(QObject* parent = nullptr); - - virtual ~OpenGLProxy() override; - - static void CreateInstance(); - - static void DestroyInstance(); - - static OpenGLProxy* instance() - { - return instance_; - } - - /** - * @brief Initialize OpenGL instance in whatever thread this object is a part of - * - * This function creates a context (shared with share_ctx provided in the constructor) as well as various other - * OpenGL thread-specific objects necessary for rendering. This function should only ever be called from the main - * thread (i.e. the thread where share_ctx is current on) but AFTER this object has been pushed to its thread with - * moveToThread(). If this function is called from a different thread, it could fail or even segfault on some - * platforms. - * - * The reason this function must be called in the main thread (rather than initializing asynchronously in a separate - * thread) is because different platforms have different rules about creating a share context with a context that - * is still "current" in another thread. While some implementations do allow this, Windows OpenGL (wgl) explicitly - * forbids it and other platforms/drivers will segfault attempting it. While we can obviously call "doneCurrent", I - * haven't found any reliable way to prevent the main thread from making it current again before initialization is - * complete other than blocking it entirely. - * - * To get around this, we create all share contexts in the main thread and then move them to the other thread - * afterwards (which is completely legal). While annoying, this gets around the issue listed above by both preventing - * the main thread from using the context during initialization and preventing more than one shared context being made - * at the same time (which may or may not actually make a difference). - */ - bool Init(); - - void Close(); - -public slots: - QVariant RunNodeAccelerated(const OLIVE_NAMESPACE::Node *node, - const OLIVE_NAMESPACE::TimeRange &range, - const OLIVE_NAMESPACE::ShaderJob &job, - const OLIVE_NAMESPACE::VideoParams ¶ms); - - void TextureToBuffer(const QVariant& texture, - OLIVE_NAMESPACE::FramePtr frame, - const QMatrix4x4& matrix); - - QVariant FrameToValue(OLIVE_NAMESPACE::FramePtr frame, - OLIVE_NAMESPACE::StreamPtr stream, - const OLIVE_NAMESPACE::VideoParams ¶ms, - const OLIVE_NAMESPACE::RenderMode::Mode &mode); - - QVariant PreCachedFrameToValue(OLIVE_NAMESPACE::FramePtr frame); - -private: - OpenGLShaderPtr ResolveShaderFromCache(const Node* node, const QString &shader_id); - - QOpenGLContext* ctx_; - QOffscreenSurface surface_; - - QOpenGLFunctions* functions_; - - OpenGLFramebuffer buffer_; - - OpenGLColorProcessorCache color_cache_; - - OpenGLShaderPtr copy_pipeline_; - - QHash shader_cache_; - - OpenGLTextureCache texture_cache_; - - static OpenGLProxy* instance_; - -private slots: - void FinishInit(); - -}; - -OLIVE_NAMESPACE_EXIT - -#endif // OPENGLPROXY_H diff --git a/app/render/backend/opengl/openglrenderfunctions.cpp b/app/render/backend/opengl/openglrenderfunctions.cpp deleted file mode 100644 index fcdc36a64..000000000 --- a/app/render/backend/opengl/openglrenderfunctions.cpp +++ /dev/null @@ -1,232 +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 "openglrenderfunctions.h" - -#include -#include -#include - -OLIVE_NAMESPACE_ENTER - -const QVector blit_vertices = { - -1.0f, -1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, - - -1.0f, -1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - 1.0f, 1.0f, 0.0f -}; - -const QVector blit_texcoords = { - 0.0f, 0.0f, - 1.0f, 0.0f, - 1.0f, 1.0f, - - 0.0f, 0.0f, - 0.0f, 1.0f, - 1.0f, 1.0f -}; - -const QVector flipped_blit_texcoords = { - 0.0f, 1.0f, - 1.0f, 1.0f, - 1.0f, 0.0f, - - 0.0f, 1.0f, - 0.0f, 0.0f, - 1.0f, 0.0f -}; - -/** - * @brief Set up texture parameters and mipmap for drawing - * - * Internal function used just before drawing to allow mipmapped bilinear filtering when drawing textures small. - * - * @param f - * - * Currently active QOpenGLFunctions object (use context()->functions() if unsure). - */ -void OpenGLRenderFunctions::PrepareToDraw(QOpenGLFunctions* f) -{ - f->glGenerateMipmap(GL_TEXTURE_2D); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -} - -GLint OpenGLRenderFunctions::GetInternalFormat(const PixelFormat::Format &format) -{ - switch (format) { - case PixelFormat::PIX_FMT_RGB8: - return GL_RGB8; - case PixelFormat::PIX_FMT_RGBA8: - return GL_RGBA8; - case PixelFormat::PIX_FMT_RGB16U: - return GL_RGB16; - case PixelFormat::PIX_FMT_RGBA16U: - return GL_RGBA16; - case PixelFormat::PIX_FMT_RGB16F: - return GL_RGB16F; - case PixelFormat::PIX_FMT_RGBA16F: - return GL_RGBA16F; - case PixelFormat::PIX_FMT_RGB32F: - return GL_RGB32F; - case PixelFormat::PIX_FMT_RGBA32F: - return GL_RGBA32F; - - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - return GL_INVALID_VALUE; -} - -GLenum OpenGLRenderFunctions::GetPixelFormat(const PixelFormat::Format &format) -{ - if (PixelFormat::FormatHasAlphaChannel(format)) { - return GL_RGBA; - } else { - return GL_RGB; - } -} - -GLenum OpenGLRenderFunctions::GetPixelType(const PixelFormat::Format &format) -{ - switch (format) { - case PixelFormat::PIX_FMT_RGB8: - case PixelFormat::PIX_FMT_RGBA8: - return GL_UNSIGNED_BYTE; - case PixelFormat::PIX_FMT_RGB16U: - case PixelFormat::PIX_FMT_RGBA16U: - return GL_UNSIGNED_SHORT; - case PixelFormat::PIX_FMT_RGB16F: - case PixelFormat::PIX_FMT_RGBA16F: - return GL_HALF_FLOAT; - case PixelFormat::PIX_FMT_RGB32F: - case PixelFormat::PIX_FMT_RGBA32F: - return GL_FLOAT; - - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - return GL_INVALID_VALUE; -} - -void OpenGLRenderFunctions::Blit(OpenGLShaderPtr pipeline, bool flipped, QMatrix4x4 matrix) -{ - Blit(pipeline.get(), flipped, matrix); -} - -void OpenGLRenderFunctions::Blit(OpenGLShader *pipeline, bool flipped, QMatrix4x4 matrix) -{ - Blit(pipeline, - GL_TRIANGLES, - blit_vertices, - flipped ? flipped_blit_texcoords : blit_texcoords, - matrix); -} - -void OpenGLRenderFunctions::Blit(OpenGLShader *pipeline, GLenum mode, const QVector &vert, const QVector &tex, QMatrix4x4 matrix) -{ - QOpenGLFunctions* func = QOpenGLContext::currentContext()->functions(); - - PrepareToDraw(func); - - QOpenGLVertexArrayObject m_vao; - m_vao.create(); - m_vao.bind(); - - QOpenGLBuffer m_vbo; - m_vbo.create(); - m_vbo.bind(); - m_vbo.allocate(vert.constData(), vert.size() * sizeof(GLfloat)); - m_vbo.release(); - - QOpenGLBuffer m_vbo2; - m_vbo2.create(); - m_vbo2.bind(); - m_vbo2.allocate(tex.constData(), tex.size() * sizeof(GLfloat)); - m_vbo2.release(); - - pipeline->bind(); - - pipeline->setUniformValue("ove_mvpmat", matrix); - pipeline->setUniformValue("ove_maintex", 0); - - int vertex_location = pipeline->attributeLocation("a_position"); - m_vbo.bind(); - func->glEnableVertexAttribArray(vertex_location); - func->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, GL_FALSE, 0, nullptr); - m_vbo.release(); - - int tex_location = pipeline->attributeLocation("a_texcoord"); - m_vbo2.bind(); - func->glEnableVertexAttribArray(tex_location); - func->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, nullptr); - m_vbo2.release(); - - // (Size / 3) because we assume each GLfloat has an XYZ pair - func->glDrawArrays(mode, 0, blit_vertices.size() / 3); - - pipeline->release(); - - m_vbo2.destroy(); - m_vbo.destroy(); - m_vao.release(); - m_vao.destroy(); -} - -void OpenGLRenderFunctions::OCIOBlit(OpenGLShaderPtr pipeline, GLuint lut, bool flipped, QMatrix4x4 matrix) -{ - OCIOBlit(pipeline.get(), lut, flipped, matrix); -} - -void OpenGLRenderFunctions::OCIOBlit(OpenGLShader *pipeline, - GLuint lut, - bool flipped, - QMatrix4x4 matrix) -{ - QOpenGLContext* ctx = QOpenGLContext::currentContext(); - QOpenGLExtraFunctions* xf = ctx->extraFunctions(); - - xf->glActiveTexture(GL_TEXTURE1); - xf->glBindTexture(GL_TEXTURE_3D, lut); - xf->glActiveTexture(GL_TEXTURE0); - - pipeline->bind(); - - pipeline->setUniformValue("ove_ociolut", 1); - - Blit(pipeline, flipped, matrix); - - pipeline->release(); - - xf->glActiveTexture(GL_TEXTURE1); - xf->glBindTexture(GL_TEXTURE_3D, 0); - xf->glActiveTexture(GL_TEXTURE0); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/opengl/openglrenderfunctions.h b/app/render/backend/opengl/openglrenderfunctions.h deleted file mode 100644 index 7e31987f7..000000000 --- a/app/render/backend/opengl/openglrenderfunctions.h +++ /dev/null @@ -1,70 +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 . - -***/ - -#ifndef OPENGLFUNCTIONS_H -#define OPENGLFUNCTIONS_H - -#include -#include -#include - -#include "openglshader.h" -#include "render/pixelformat.h" - -OLIVE_NAMESPACE_ENTER - -class OpenGLRenderFunctions { -public: - /** - * @brief Draw texture on screen - * - * @param pipeline - * - * Shader to use for the texture drawing - * - * @param flipped - * - * Draw the texture vertically flipped (defaults to FALSE) - * - * @param matrix - * - * Transformation matrix to use when drawing (defaults to no transform) - */ - static void Blit(OpenGLShaderPtr pipeline, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4()); - static void Blit(OpenGLShader* pipeline, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4()); - static void Blit(OpenGLShader* pipeline, GLenum mode, const QVector& vert, - const QVector& tex, QMatrix4x4 matrix = QMatrix4x4()); - - static void OCIOBlit(OpenGLShaderPtr pipeline, GLuint lut, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4()); - static void OCIOBlit(OpenGLShader* pipeline, GLuint lut, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4()); - - static void PrepareToDraw(QOpenGLFunctions* f); - - static GLint GetInternalFormat(const PixelFormat::Format& format); - - static GLenum GetPixelFormat(const PixelFormat::Format& format); - - static GLenum GetPixelType(const PixelFormat::Format& format); - -}; - -OLIVE_NAMESPACE_EXIT - -#endif // OPENGLFUNCTIONS_H diff --git a/app/render/backend/opengl/openglshader.cpp b/app/render/backend/opengl/openglshader.cpp deleted file mode 100644 index 7e76f619a..000000000 --- a/app/render/backend/opengl/openglshader.cpp +++ /dev/null @@ -1,254 +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 "openglshader.h" - -#include -OLIVE_NAMESPACE_ENTER - -OpenGLShaderPtr OpenGLShader::Create() -{ - return std::make_shared(); -} - -OpenGLShaderPtr OpenGLShader::CreateDefault(const QString &function_name, const QString &shader_code) -{ - OpenGLShaderPtr program = Create(); - - // Add shaders to program - program->addShaderFromSourceCode(QOpenGLShader::Vertex, CodeDefaultVertex()); - program->addShaderFromSourceCode(QOpenGLShader::Fragment, CodeDefaultFragment(function_name, shader_code)); - program->link(); - - return program; -} - -// copied from source code to OCIODisplay -const int OCIO_LUT3D_EDGE_SIZE = 64; - -// copied from source code to OCIODisplay, expanded from 3*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE -const int OCIO_NUM_3D_ENTRIES = 3*OCIO_LUT3D_EDGE_SIZE*OCIO_LUT3D_EDGE_SIZE*OCIO_LUT3D_EDGE_SIZE; - -OpenGLShaderPtr OpenGLShader::CreateOCIO(QOpenGLContext* ctx, - GLuint& lut_texture, - OCIO::ConstProcessorRcPtr processor, - bool alpha_is_associated) -{ - QOpenGLExtraFunctions* xf = ctx->extraFunctions(); - - // Set up shader description - OCIO::GpuShaderDesc shaderDesc; - const char* ocio_func_name = "OCIODisplay"; - shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_3); - shaderDesc.setFunctionName(ocio_func_name); - shaderDesc.setLut3DEdgeLen(OCIO_LUT3D_EDGE_SIZE); - - // Compute LUT - std::vector ocio_lut_data(OCIO_NUM_3D_ENTRIES); - processor->getGpuLut3D(&ocio_lut_data[0], shaderDesc); - - // Create LUT texture - xf->glGenTextures(1, &lut_texture); - - // Bind LUT - xf->glActiveTexture(GL_TEXTURE1); - xf->glBindTexture(GL_TEXTURE_3D, lut_texture); - - // Set texture parameters - xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - // Allocate storage for texture - xf->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F, - OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, - 0, GL_RGB, GL_FLOAT, &ocio_lut_data[0]); - - // Create OCIO shader code - QString shader_text; - - // Workaround since OCIO doesn't support the GLSL version we use - shader_text.append(QStringLiteral("#define texture2D texture\n" - "#define texture3D texture\n")); - - // Append OCIO shader code - shader_text.append(processor->getGpuShaderText(shaderDesc)); - - QString shader_call; - - // Enforce alpha association - if (alpha_is_associated) { - - // If alpha is already associated, we'll need to disassociate and reassociate - shader_text.append("\n"); - - QString disassociate_func_name = "disassoc"; - shader_text.append(CodeAlphaDisassociate(disassociate_func_name)); - - QString reassociate_func_name = "reassoc"; - shader_text.append(CodeAlphaReassociate(reassociate_func_name)); - - // Make OCIO call pass through disassociate and reassociate function - shader_call = QStringLiteral("%3(%1(%2(col), ove_ociolut));").arg(ocio_func_name, - disassociate_func_name, - reassociate_func_name); - - } else { - - // If alpha is not already associated, we can just associate after OCIO - - // Add associate function - QString associate_func_name = "assoc"; - shader_text.append(CodeAlphaAssociate(associate_func_name)); - - // Make OCIO call pass through associate function - shader_call = QStringLiteral("%2(%1(col, ove_ociolut));").arg(ocio_func_name, associate_func_name); - - } - - // Add process() function, which GetPipeline() will call if specified - QString process_function_name = "process"; - shader_text.append(QStringLiteral("\n" - "uniform sampler3D ove_ociolut;\n" - "\n" - "vec4 %2(vec4 col) {\n" - " return %1\n" - "}\n").arg(shader_call, process_function_name)); - - - // Get pipeline-based shader to inject OCIO shader into - OpenGLShaderPtr shader = OpenGLShader::CreateDefault(process_function_name, shader_text); - - // Release LUT - xf->glBindTexture(GL_TEXTURE_3D, 0); - - xf->glActiveTexture(GL_TEXTURE0); - - return shader; -} - -QString OpenGLShader::CodeDefaultFragment(QString function_name, const QString &shader_code) -{ - // Create shader header - QString frag_code = QStringLiteral("#version 150\n" - "\n" - "#ifdef GL_ES\n" - "precision highp int;\n" - "precision highp float;\n" - "#endif\n" - "\n" - "uniform sampler2D ove_maintex;\n" - "uniform vec2 ove_resolution;\n" - "uniform bool ove_deinterlace;\n" - "\n" - "in vec2 ove_texcoord;\n" - "\n" - "out vec4 fragColor;\n" - "\n"); - - // Check if additional code was passed to this function, add it here - if (!function_name.isEmpty() && !shader_code.isEmpty()) { - - // If additional code was passed, add it and reference it in main(). - // - // The function in the additional code is expected to be `vec4 function_name(vec4 color)`. - // The texture coordinate can be acquired through `ove_texcoord`. - - frag_code.append(shader_code); - - } else { - - // No function to call - function_name = QString(); - - } - - // Our function_name arg will either resolve to the function added to this or to nothing, in - // which case they'll just be benign brackets. - frag_code.append(QStringLiteral("\n" - "void main() {\n" - " vec2 using_texcoord = ove_texcoord;\n" - " if (ove_deinterlace) {\n" - " // A very basic deinterlace that halves the vertical\n" - " // resolution and linearly interpolates the two fields\n" - " // by reading the texture coord between them.\n" - " float half_vert = round(ove_resolution.y / 2.0);\n" - " using_texcoord.y = (round(using_texcoord.y * half_vert) + 0.25) / half_vert;\n" - " }\n" - " vec4 color = %1(texture(ove_maintex, using_texcoord));\n" - " fragColor = color;\n" - "}\n").arg(function_name)); - - return frag_code; -} - -QString OpenGLShader::CodeDefaultVertex() -{ - // Generate vertex shader - return QStringLiteral("#version 150\n" - "\n" - "#ifdef GL_ES\n" - "precision highp int;\n" - "precision highp float;\n" - "#endif\n" - "\n" - "uniform mat4 ove_mvpmat;\n" - "\n" - "in vec4 a_position;\n" - "in vec2 a_texcoord;\n" - "\n" - "out vec2 ove_texcoord;\n" - "\n" - "void main() {\n" - " gl_Position = ove_mvpmat * a_position;\n" - " ove_texcoord = a_texcoord;\n" - "}\n"); -} - -QString OpenGLShader::CodeAlphaDisassociate(const QString &function_name) -{ - return QStringLiteral("vec4 %1(vec4 col) {\n" - " if (col.a > 0.0) {\n" - " return vec4(col.rgb / col.a, col.a);" - " }\n" - " return col;\n" - "}\n").arg(function_name); -} - -QString OpenGLShader::CodeAlphaReassociate(const QString &function_name) -{ - return QStringLiteral("vec4 %1(vec4 col) {\n" - " if (col.a > 0.0) {\n" - " return vec4(col.rgb * col.a, col.a);" - " }\n" - " return col;\n" - "}\n").arg(function_name); -} - -QString OpenGLShader::CodeAlphaAssociate(const QString &function_name) -{ - return QStringLiteral("vec4 %1(vec4 col) {\n" - " return vec4(col.rgb * col.a, col.a);\n" - "}\n").arg(function_name); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/opengl/openglshader.h b/app/render/backend/opengl/openglshader.h deleted file mode 100644 index 452dc3c3d..000000000 --- a/app/render/backend/opengl/openglshader.h +++ /dev/null @@ -1,65 +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 . - -***/ - -#ifndef OPENGLSHADER_H -#define OPENGLSHADER_H - -#include -#include - -#include -namespace OCIO = OCIO_NAMESPACE::v1; - -#include "common/define.h" - -OLIVE_NAMESPACE_ENTER - -class OpenGLShader; -using OpenGLShaderPtr = std::shared_ptr; - -/** - * @brief A simple QOpenGLShaderProgram derivative with static functions for creating - */ -class OpenGLShader : public QOpenGLShaderProgram { -public: - OpenGLShader() = default; - - static OpenGLShaderPtr Create(); - - static OpenGLShaderPtr CreateDefault(const QString &function_name = QString(), - const QString &shader_code = QString()); - - static OpenGLShaderPtr CreateOCIO(QOpenGLContext* ctx, - GLuint& lut_texture, - OCIO::ConstProcessorRcPtr processor, - bool alpha_is_associated); - - static QString CodeDefaultFragment(QString function_name = QString(), - const QString &shader_code = QString()); - static QString CodeDefaultVertex(); - static QString CodeAlphaDisassociate(const QString& function_name); - static QString CodeAlphaReassociate(const QString& function_name); - static QString CodeAlphaAssociate(const QString& function_name); - -}; - -OLIVE_NAMESPACE_EXIT - -#endif // OPENGLSHADER_H diff --git a/app/render/backend/opengl/opengltexture.cpp b/app/render/backend/opengl/opengltexture.cpp deleted file mode 100644 index 9954e863c..000000000 --- a/app/render/backend/opengl/opengltexture.cpp +++ /dev/null @@ -1,191 +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 "opengltexture.h" - -#include -#include -#include - -#include "openglrenderfunctions.h" -#include "render/pixelformat.h" - -OLIVE_NAMESPACE_ENTER - -OpenGLTexture::OpenGLTexture() : - created_ctx_(nullptr), - texture_(0) -{ -} - -OpenGLTexture::~OpenGLTexture() -{ - Destroy(); -} - -bool OpenGLTexture::IsCreated() const -{ - return (texture_); -} - -void OpenGLTexture::Create(QOpenGLContext *ctx, const VideoParams ¶ms, const void* data, int linesize) -{ - if (!ctx) { - qWarning() << "OpenGLTexture::Create was passed an invalid context"; - return; - } - - Destroy(); - - created_ctx_ = ctx; - params_ = params; - - connect(created_ctx_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Destroy()), Qt::DirectConnection); - - // Create main texture - CreateInternal(created_ctx_, &texture_, data, linesize); -} - -void OpenGLTexture::Create(QOpenGLContext *ctx, const VideoParams ¶ms) -{ - Create(ctx, params, nullptr, 0); -} - -void OpenGLTexture::Create(QOpenGLContext *ctx, FramePtr frame) -{ - Create(ctx, frame.get()); -} - -void OpenGLTexture::Create(QOpenGLContext *ctx, Frame *frame) -{ - Create(ctx, frame->video_params(), frame->data(), frame->linesize_pixels()); -} - -void OpenGLTexture::Destroy() -{ - if (created_ctx_) { - disconnect(created_ctx_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Destroy())); - - created_ctx_->functions()->glDeleteTextures(1, &texture_); - texture_ = 0; - - created_ctx_ = nullptr; - } -} - -void OpenGLTexture::Bind() -{ - created_ctx_->functions()->glBindTexture(GL_TEXTURE_2D, texture_); -} - -void OpenGLTexture::Release() -{ - created_ctx_->functions()->glBindTexture(GL_TEXTURE_2D, 0); -} - -void OpenGLTexture::SetPixelAspectRatio(const rational &r) -{ - params_ = VideoParams(params_.width(), - params_.height(), - params_.time_base(), - params_.format(), - r, - params_.interlacing(), - params_.divider()); -} - -void OpenGLTexture::Upload(FramePtr frame) -{ - Upload(frame.get()); -} - -void OpenGLTexture::Upload(Frame *frame) -{ - Upload(frame->data(), frame->linesize_pixels()); -} - -void OpenGLTexture::Upload(const void *data, int linesize) -{ - if (!IsCreated()) { - qWarning() << "OpenGLTexture::Upload() called while it wasn't created"; - return; - } - - Bind(); - - created_ctx_->functions()->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize); - - created_ctx_->functions()->glTexSubImage2D(GL_TEXTURE_2D, - 0, - 0, - 0, - width(), - height(), - OpenGLRenderFunctions::GetPixelFormat(format()), - OpenGLRenderFunctions::GetPixelType(format()), - data); - - created_ctx_->functions()->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - - Release(); -} - -void OpenGLTexture::CreateInternal(QOpenGLContext* create_ctx, GLuint* tex, const void *data, int linesize) -{ - QOpenGLFunctions* f = create_ctx->functions(); - - // Create texture - f->glGenTextures(1, tex); - - // Verify texture - if (texture_ == 0) { - qWarning() << "OpenGL texture creation failed"; - return; - } - - // Bind texture - f->glBindTexture(GL_TEXTURE_2D, *tex); - - // Set linesize - f->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize); - - // Allocate storage for texture - f->glTexImage2D(GL_TEXTURE_2D, - 0, - OpenGLRenderFunctions::GetInternalFormat(format()), - width(), - height(), - 0, - OpenGLRenderFunctions::GetPixelFormat(format()), - OpenGLRenderFunctions::GetPixelType(format()), - data); - - // Return linesize to default - f->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - - // Set texture filtering to bilinear - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - // Release texture - f->glBindTexture(GL_TEXTURE_2D, 0); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/opengl/opengltexture.h b/app/render/backend/opengl/opengltexture.h deleted file mode 100644 index 301383da9..000000000 --- a/app/render/backend/opengl/opengltexture.h +++ /dev/null @@ -1,118 +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 . - -***/ - -#ifndef OPENGLTEXTURE_H -#define OPENGLTEXTURE_H - -#include -#include - -#include "codec/frame.h" -#include "render/pixelformat.h" - -OLIVE_NAMESPACE_ENTER - -/** - * @brief A class wrapper around an OpenGL texture - */ -class OpenGLTexture : public QObject -{ - Q_OBJECT -public: - OpenGLTexture(); - virtual ~OpenGLTexture() override; - - DISABLE_COPY_MOVE(OpenGLTexture) - - void Create(QOpenGLContext* ctx, const VideoParams& params, const void *data, int linesize); - void Create(QOpenGLContext* ctx, const VideoParams& params); - void Create(QOpenGLContext* ctx, FramePtr frame); - void Create(QOpenGLContext* ctx, Frame* frame); - - bool IsCreated() const; - - void Bind(); - - void Release(); - - const VideoParams& params() const - { - return params_; - } - - const int& width() const - { - return params_.effective_width(); - } - - const int& height() const - { - return params_.effective_height(); - } - - const PixelFormat::Format &format() const - { - return params_.format(); - } - - const GLuint& texture() const - { - return texture_; - } - - const int& divider() const - { - return params_.divider(); - } - - /** - * @brief Changes the pixel aspect ratio metadata of this textuer - * - * This metadata is important for our render pipeline, but we don't need to do any re-allocation - * to set it like we do with other VideoParam changes, so we provide a function to change only - * the PAR here. - */ - void SetPixelAspectRatio(const rational& r); - - void Upload(FramePtr frame); - void Upload(Frame* frame); - void Upload(const void *data, int linesize); - -public slots: - void Destroy(); - -private: - void CreateInternal(QOpenGLContext *create_ctx, GLuint *tex, const void *data, int linesize); - - QOpenGLContext* created_ctx_; - - GLuint texture_; - - VideoParams params_; - -}; - -using OpenGLTexturePtr = std::shared_ptr; - -OLIVE_NAMESPACE_EXIT - -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::OpenGLTexturePtr) - -#endif // OPENGLTEXTURE_H diff --git a/app/render/backend/opengl/opengltexturecache.cpp b/app/render/backend/opengl/opengltexturecache.cpp deleted file mode 100644 index e00fc8f42..000000000 --- a/app/render/backend/opengl/opengltexturecache.cpp +++ /dev/null @@ -1,121 +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 "opengltexturecache.h" - -OLIVE_NAMESPACE_ENTER - -OpenGLTextureCache::~OpenGLTextureCache() -{ - foreach (Reference* ref, existing_references_) { - ref->ParentKilled(); - } -} - -OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext *ctx, FramePtr frame) -{ - return Get(ctx, frame.get()); -} - -OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext *ctx, Frame *frame) -{ - return Get(ctx, frame->video_params(), frame->data(), frame->linesize_pixels()); -} - -OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext* ctx, const VideoParams ¶ms, const void *data, int linesize) -{ - OpenGLTexturePtr texture = nullptr; - - lock_.lock(); - - // Iterate through textures and see if we have one that matches these parameters - for (int i=0;iwidth() == params.effective_width() - && test->height() == params.effective_height() - && test->format() == params.format()) { - texture = test; - available_textures_.removeAt(i); - break; - } - } - - // If we didn't find a texture, we'll need to create one - if (!texture) { - texture = std::make_shared(); - texture->Create(ctx, params); - } - - texture->SetPixelAspectRatio(params.pixel_aspect_ratio()); - - ReferencePtr ref = std::make_shared(this, texture); - existing_references_.append(ref.get()); - - lock_.unlock(); - - if (data) { - texture->Upload(data, linesize); - } - - return ref; -} - -OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext *ctx, const VideoParams ¶ms) -{ - return Get(ctx, params, nullptr, 0); -} - -void OpenGLTextureCache::Relinquish(OpenGLTextureCache::Reference *ref) -{ - OpenGLTexturePtr tex = ref->texture(); - - lock_.lock(); - - existing_references_.removeOne(ref); - available_textures_.append(tex); - - lock_.unlock(); -} - -OpenGLTextureCache::Reference::Reference(OpenGLTextureCache *parent, OpenGLTexturePtr texture) : - parent_(parent), - texture_(texture) -{ -} - -OpenGLTextureCache::Reference::~Reference() -{ - if (parent_) { - parent_->Relinquish(this); - } -} - -OpenGLTexturePtr OpenGLTextureCache::Reference::texture() -{ - return texture_; -} - -void OpenGLTextureCache::Reference::ParentKilled() -{ - parent_ = nullptr; -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/opengl/opengltexturecache.h b/app/render/backend/opengl/opengltexturecache.h deleted file mode 100644 index 276cdd150..000000000 --- a/app/render/backend/opengl/opengltexturecache.h +++ /dev/null @@ -1,80 +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 . - -***/ - -#ifndef OPENGLTEXTURECACHE_H -#define OPENGLTEXTURECACHE_H - -#include - -#include "openglframebuffer.h" -#include "opengltexture.h" -#include "render/videoparams.h" - -OLIVE_NAMESPACE_ENTER - -class OpenGLTextureCache -{ -public: - class Reference { - public: - Reference(OpenGLTextureCache* parent, OpenGLTexturePtr texture); - ~Reference(); - - DISABLE_COPY_MOVE(Reference) - - OpenGLTexturePtr texture(); - - void ParentKilled(); - - private: - OpenGLTextureCache* parent_; - - OpenGLTexturePtr texture_; - }; - - using ReferencePtr = std::shared_ptr; - - OpenGLTextureCache() = default; - - ~OpenGLTextureCache(); - - DISABLE_COPY_MOVE(OpenGLTextureCache) - - ReferencePtr Get(QOpenGLContext *ctx, FramePtr frame); - ReferencePtr Get(QOpenGLContext *ctx, Frame* frame); - ReferencePtr Get(QOpenGLContext *ctx, const VideoParams& params, const void *data, int linesize); - ReferencePtr Get(QOpenGLContext *ctx, const VideoParams& params); - -private: - void Relinquish(Reference* ref); - - QMutex lock_; - - QList available_textures_; - - QList existing_references_; - -}; - -OLIVE_NAMESPACE_EXIT - -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::OpenGLTextureCache::ReferencePtr) - -#endif // OPENGLTEXTURECACHE_H diff --git a/app/render/backend/opengl/openglworker.cpp b/app/render/backend/opengl/openglworker.cpp deleted file mode 100644 index ec518ffc7..000000000 --- a/app/render/backend/opengl/openglworker.cpp +++ /dev/null @@ -1,90 +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 "openglworker.h" - -OLIVE_NAMESPACE_ENTER - -OpenGLWorker::OpenGLWorker(RenderBackend *parent) : - RenderWorker(parent) -{ -} - -void OpenGLWorker::TextureToFrame(const QVariant &texture, FramePtr frame, const QMatrix4x4& mat) const -{ - QMetaObject::invokeMethod(OpenGLProxy::instance(), - "TextureToBuffer", - Qt::BlockingQueuedConnection, - Q_ARG(const QVariant&, texture), - OLIVE_NS_ARG(FramePtr, frame), - Q_ARG(const QMatrix4x4&, mat)); -} - -QVariant OpenGLWorker::FootageFrameToTexture(StreamPtr stream, FramePtr frame) const -{ - QVariant value; - - QMetaObject::invokeMethod(OpenGLProxy::instance(), - "FrameToValue", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QVariant, value), - OLIVE_NS_ARG(FramePtr, frame), - OLIVE_NS_ARG(StreamPtr, stream), - OLIVE_NS_CONST_ARG(VideoParams&, video_params()), - OLIVE_NS_CONST_ARG(RenderMode::Mode&, render_mode())); - - return value; -} - -QVariant OpenGLWorker::CachedFrameToTexture(FramePtr frame) const -{ - QVariant value; - - QMetaObject::invokeMethod(OpenGLProxy::instance(), - "PreCachedFrameToValue", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QVariant, value), - OLIVE_NS_ARG(FramePtr, frame)); - - return value; -} - -QVariant OpenGLWorker::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) -{ - QVariant value; - - QMetaObject::invokeMethod(OpenGLProxy::instance(), - "RunNodeAccelerated", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QVariant, value), - OLIVE_NS_CONST_ARG(Node*, node), - OLIVE_NS_CONST_ARG(TimeRange&, range), - OLIVE_NS_CONST_ARG(ShaderJob&, job), - OLIVE_NS_CONST_ARG(VideoParams&, video_params())); - - return value; -} - -bool OpenGLWorker::TextureHasAlpha(const QVariant &v) const -{ - return PixelFormat::FormatHasAlphaChannel(v.value()->texture()->format()); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/opengl/openglworker.h b/app/render/backend/opengl/openglworker.h deleted file mode 100644 index 75eed65f8..000000000 --- a/app/render/backend/opengl/openglworker.h +++ /dev/null @@ -1,49 +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 . - -***/ - -#ifndef OPENGLWORKER_H -#define OPENGLWORKER_H - -#include "openglproxy.h" -#include "render/backend/renderworker.h" - -OLIVE_NAMESPACE_ENTER - -class OpenGLWorker : public RenderWorker -{ -public: - OpenGLWorker(RenderBackend* parent); - -protected: - virtual void TextureToFrame(const QVariant& texture, FramePtr frame, const QMatrix4x4 &mat) const override; - - virtual QVariant FootageFrameToTexture(StreamPtr stream, FramePtr frame) const override; - - virtual QVariant CachedFrameToTexture(FramePtr frame) const override; - - virtual QVariant ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job) override; - - virtual bool TextureHasAlpha(const QVariant& v) const override; - -}; - -OLIVE_NAMESPACE_EXIT - -#endif // OPENGLWORKER_H diff --git a/app/render/backend/renderbackend.cpp b/app/render/backend/renderbackend.cpp deleted file mode 100644 index 6e469e07e..000000000 --- a/app/render/backend/renderbackend.cpp +++ /dev/null @@ -1,888 +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 "renderbackend.h" - -#include -#include -#include - -#include "config/config.h" -#include "core.h" -#include "task/conform/conform.h" -#include "task/taskmanager.h" -#include "window/mainwindow/mainwindow.h" - -OLIVE_NAMESPACE_ENTER - -QVector RenderBackend::instances_; -QMutex RenderBackend::instance_lock_; -RenderBackend* RenderBackend::active_instance_ = nullptr; -QThreadPool RenderBackend::thread_pool_; - -RenderBackend::RenderBackend(QObject *parent) : - QObject(parent), - viewer_node_(nullptr), - video_force_download_resolution_(false), - autocache_enabled_(false), - autocache_paused_(false), - generate_audio_previews_(false), - render_mode_(RenderMode::kOnline), - autocache_has_changed_(false), - use_custom_autocache_range_(false), - ignore_next_mouse_button_(false) -{ - instance_lock_.lock(); - instances_.append(this); - instance_lock_.unlock(); - - // Set default autocache range - SetAutoCachePlayhead(rational()); -} - -RenderBackend::~RenderBackend() -{ - Close(); -} - -void RenderBackend::SetViewerNode(ViewerOutput *viewer_node) -{ - if (viewer_node_ == viewer_node) { - return; - } - - ViewerOutput* old_viewer = viewer_node_; - if (!viewer_node) { - // If setting to null, set it here before we wait for jobs to finish to prevent WorkerFinished() - // from calling RunNextJob() again and preventing us from finishing - viewer_node_ = nullptr; - } - - if (old_viewer) { - // Cancel any remaining tickets - ClearQueue(); - - // Wait for any currently running jobs to finish - foreach (RenderTicketPtr ticket, running_tickets_) { - ticket->WaitForFinished(); - } - - // Clear autocache lists - { - // This can be cleared normally (hashes will be discarded and need to be calculated again) - autocache_hash_tasks_.clear(); - - // We need to wait for these since they work directly on the FrameHashCache. Most of the time - // this is fine, but not if the FrameHashCache gets deleted after this function. - foreach (QFutureWatcher* watcher, autocache_hash_process_tasks_) { - watcher->waitForFinished(); - } - autocache_hash_process_tasks_.clear(); - - // This can be cleared normally (frames will be discarded and need to be rendered again) - autocache_video_tasks_.clear(); - - // This can be cleared normally (PCM data will be discarded and need to be rendered again) - autocache_audio_tasks_.clear(); - - // We'll need to wait for these since they work directly on the FrameHashCache. Frames will - // be in the cache for later use. - { - QMap*, QByteArray>::const_iterator i; - for (i=autocache_video_download_tasks_.constBegin(); i!=autocache_video_download_tasks_.constEnd(); i++) { - i.key()->waitForFinished(); - } - autocache_video_download_tasks_.clear(); - } - - // No longer caching any hashes - autocache_currently_caching_hashes_.clear(); - } - - // Delete all of our copied nodes - foreach (Node* c, copy_map_) { - c->deleteLater(); - } - copy_map_.clear(); - copied_viewer_node_ = nullptr; - graph_update_queue_.clear(); - - // Disconnect signal (will be a no-op if the signal was never connected) - disconnect(old_viewer, - &ViewerOutput::GraphChangedFrom, - this, - &RenderBackend::NodeGraphChanged); - - disconnect(old_viewer->video_frame_cache(), - &PlaybackCache::Invalidated, - this, - &RenderBackend::AutoCacheVideoInvalidated); - - disconnect(old_viewer->audio_playback_cache(), - &PlaybackCache::Invalidated, - this, - &RenderBackend::AutoCacheAudioInvalidated); - - foreach (const WorkerData& worker, workers_) { - worker.worker->ClearDecoders(); - } - } - - if (viewer_node) { - // If setting to non-null, set it now - viewer_node_ = viewer_node; - - // Copy graph - copied_viewer_node_ = static_cast(viewer_node_->copy()); - copy_map_.insert(viewer_node_, copied_viewer_node_); - - // We begin an operation and never end it which prevents the copy from unnecessarily - // invalidating its own cache - copied_viewer_node_->BeginOperation(); - - NodeGraphChanged(viewer_node_->texture_input()); - NodeGraphChanged(viewer_node_->samples_input()); - ProcessUpdateQueue(); - - if (autocache_enabled_) { - connect(viewer_node_, - &ViewerOutput::GraphChangedFrom, - this, - &RenderBackend::NodeGraphChanged); - - connect(viewer_node_->video_frame_cache(), - &PlaybackCache::Invalidated, - this, - &RenderBackend::AutoCacheVideoInvalidated); - - connect(viewer_node_->audio_playback_cache(), - &PlaybackCache::Invalidated, - this, - &RenderBackend::AutoCacheAudioInvalidated); - } - } -} - -void RenderBackend::AutoCacheRange(const TimeRange &range) -{ - Q_ASSERT(autocache_enabled_); - - autocache_has_changed_ = true; - use_custom_autocache_range_ = true; - custom_autocache_range_ = range; - - AutoCacheRequeueFrames(); -} - -RenderTicketPtr RenderBackend::Hash(const QVector ×, bool prioritize) -{ - Q_ASSERT(viewer_node_); - - SetActiveInstance(); - - RenderTicketPtr ticket = std::make_shared(RenderTicket::kTypeHash, - QVariant::fromValue(times)); - - if (prioritize) { - render_queue_.push_front(ticket); - } else { - render_queue_.push_back(ticket); - } - - QMetaObject::invokeMethod(this, "RunNextJob", Qt::QueuedConnection); - - return ticket; -} - -RenderTicketPtr RenderBackend::RenderFrame(const rational &time, bool prioritize, const QByteArray& hash) -{ - Q_ASSERT(viewer_node_); - - SetActiveInstance(); - - RenderTicketPtr ticket = std::make_shared(RenderTicket::kTypeVideo, - QVariant::fromValue(time)); - - ticket->setProperty("hash", hash); - - if (prioritize) { - render_queue_.push_front(ticket); - } else { - render_queue_.push_back(ticket); - } - - QMetaObject::invokeMethod(this, "RunNextJob", Qt::QueuedConnection); - - return ticket; -} - -RenderTicketPtr RenderBackend::RenderAudio(const TimeRange &r, bool prioritize) -{ - Q_ASSERT(viewer_node_); - - SetActiveInstance(); - - RenderTicketPtr ticket = std::make_shared(RenderTicket::kTypeAudio, - QVariant::fromValue(r)); - - if (prioritize) { - render_queue_.push_front(ticket); - } else { - render_queue_.push_back(ticket); - } - - QMetaObject::invokeMethod(this, "RunNextJob", Qt::QueuedConnection); - - return ticket; -} - -void RenderBackend::SetVideoParams(const VideoParams ¶ms) -{ - video_params_ = params; -} - -void RenderBackend::SetAudioParams(const AudioParams ¶ms) -{ - audio_params_ = params; -} - -void RenderBackend::IgnoreNextMouseButton() -{ - ignore_next_mouse_button_ = true; -} - -std::list RenderBackend::SplitRangeIntoChunks(const TimeRange &r) -{ - // FIXME: Magic number - const int chunk_size = 2; - - std::list split_ranges; - - int start_time = qFloor(r.in().toDouble() / static_cast(chunk_size)) * chunk_size; - int end_time = qCeil(r.out().toDouble() / static_cast(chunk_size)) * chunk_size; - - for (int i=start_time; iCancel(); - } - render_queue_.clear(); -} - -void RenderBackend::NodeGraphChanged(NodeInput *source) -{ - // We need to determine: - // - If we don't have this input, assume that it's coming soon and ignore it - // - If we do, is this input a child of another input we're already copying? - // - Or are any of the queued inputs children of this one? - - // First we need to find our copy of the input being queued - Node* our_copy_node = copy_map_.value(source->parentNode()); - - // If we don't have this node yet, assume it's coming in a later copy in which case it'll be - // copied then - if (!our_copy_node) { - // Assert that there are updates coming - Q_ASSERT(!graph_update_queue_.isEmpty()); - return; - } - - // If we're here, we must have this node. Determine if we're already copying a "parent" of this - for (int i=0; iIsArray() && static_cast(source)->sub_params().contains(queued_input)) - || queued_input->parentNode()->OutputsTo(source, true, true)) { - // In which case, we don't need to queue it and can queue our own - graph_update_queue_.removeAt(i); - disconnect(queued_input, &NodeInput::destroyed, this, &RenderBackend::QueuedInputRemoved); - i--; - } - - // Check if the source is a member of this array, in which case it'll be copied eventually anyway - if (queued_input->IsArray() - && static_cast(queued_input)->sub_params().contains(source)) { - return; - } - - // Check if this dependency graph is already queued - if (source->parentNode()->OutputsTo(queued_input, true, true)) { - // In which case, no further copy is necessary - return; - } - } - - graph_update_queue_.append(source); - connect(source, &NodeInput::destroyed, this, &RenderBackend::QueuedInputRemoved); -} - -void RenderBackend::Close() -{ - SetViewerNode(nullptr); - - for (int i=0;ideleteLater(); - } - workers_.clear(); -} - -void RenderBackend::RunNextJob() -{ - // If queue is empty, nothing to be done - if (render_queue_.empty()) { - - // If we're the active instance, unset it - instance_lock_.lock(); - if (active_instance_ == this) { - active_instance_ = nullptr; - } - instance_lock_.unlock(); - - 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; - - foreach (const WorkerData& data, workers_) { - if (data.busy) { - all_workers_available = false; - break; - } - } - - if (all_workers_available) { - // Process queue - ProcessUpdateQueue(); - } else { - return; - } - } - - // If we have no workers allocated, allocate them now - if (workers_.isEmpty()) { - // Allocate workers here - workers_.resize(thread_pool_.maxThreadCount()); - - for (int i=0;iSetVideoParams(video_params_); - worker->SetAudioParams(audio_params_); - worker->SetForceDownloadResolution(video_force_download_resolution_); - worker->SetVideoDownloadMatrix(video_download_matrix_); - worker->SetRenderMode(render_mode_); - worker->SetPreviewGenerationEnabled(generate_audio_previews_); - worker->SetCopyMap(©_map_); - worker->SetCachePath(viewer_node_->video_frame_cache()->GetCacheDirectory()); - - // Move ticket from queue to running list - RenderTicketPtr ticket = render_queue_.front(); - render_queue_.pop_front(); - running_tickets_.push_back(ticket); - - // Create watcher to remove from running list - RenderTicketWatcher* watcher = new RenderTicketWatcher(); - connect(watcher, &RenderTicketWatcher::Finished, this, &RenderBackend::TicketFinished); - watcher->SetTicket(ticket); - - // Set job time to now - ticket->SetJobTime(); - - switch (ticket->GetType()) { - case RenderTicket::kTypeHash: - Q_ASSERT(video_params_.is_valid()); - - QtConcurrent::run(&thread_pool_, - worker, - &RenderWorker::Hash, - ticket, - copied_viewer_node_, - ticket->GetTime().value >()); - break; - case RenderTicket::kTypeVideo: - { - Q_ASSERT(video_params_.is_valid()); - - rational frame = ticket->GetTime().value(); - - QtConcurrent::run(&thread_pool_, - worker, - &RenderWorker::RenderFrame, - ticket, - copied_viewer_node_, - frame); - - QByteArray frame_hash = ticket->property("hash").toByteArray(); - if (!frame_hash.isEmpty()) { - autocache_currently_caching_hashes_.append(frame_hash); - } - break; - } - case RenderTicket::kTypeAudio: - Q_ASSERT(audio_params_.is_valid()); - - QtConcurrent::run(&thread_pool_, - worker, - &RenderWorker::RenderAudio, - ticket, - copied_viewer_node_, - ticket->GetTime().value()); - break; - } - - if (render_queue_.empty()) { - // No more jobs, can exit here - break; - } - } - } -} - -void RenderBackend::TicketFinished() -{ - RenderTicketPtr ticket = static_cast(sender())->GetTicket(); - delete sender(); - - running_tickets_.remove(ticket); -} - -void RenderBackend::WorkerGeneratedWaveform(RenderTicketPtr ticket, TrackOutput *track, AudioVisualWaveform samples, TimeRange range) -{ - QList valid_ranges = viewer_node_->audio_playback_cache()->GetValidRanges(range, - ticket->GetJobTime()); - if (!valid_ranges.isEmpty()) { - // Generate visual waveform in this background thread - track->waveform_lock()->lock(); - - track->waveform().set_channel_count(audio_params_.channel_count()); - - foreach (const TimeRange& r, valid_ranges) { - track->waveform().OverwriteSums(samples, r.in(), r.in() - range.in(), r.length()); - } - - track->waveform_lock()->unlock(); - - emit track->PreviewChanged(); - } -} - -void RenderBackend::AutoCacheVideoInvalidated(const TimeRange &range) -{ - ClearVideoQueue(); - - // Hash these frames since that should be relatively quick. - if (ignore_next_mouse_button_ || !(qApp->mouseButtons() & Qt::LeftButton)) { - ignore_next_mouse_button_ = false; - RenderTicketWatcher* watcher = new RenderTicketWatcher(); - QVector frames = viewer_node_->video_frame_cache()->GetFrameListFromTimeRange({range}); - autocache_hash_tasks_.insert(watcher, frames); - connect(watcher, &RenderTicketWatcher::Finished, this, &RenderBackend::AutoCacheHashesGenerated); - watcher->SetTicket(Hash(frames)); - } -} - -void RenderBackend::AutoCacheAudioInvalidated(const TimeRange &range) -{ - // Start a task to re-render the audio at this range - RenderTicketWatcher* watcher = new RenderTicketWatcher(); - autocache_audio_tasks_.insert(watcher, range); - connect(watcher, &RenderTicketWatcher::Finished, this, &RenderBackend::AutoCacheAudioRendered); - watcher->SetTicket(RenderAudio(range, true)); -} - -void RenderBackend::SetHashes(FrameHashCache* cache, const QVector& times, const QVector& hashes, qint64 job_time) -{ - std::vector existing_hashes; - - for (int i=0; iCachePathName(hash)); - - if (hash_exists) { - existing_hashes.push_back(hash); - } - } - - QMetaObject::invokeMethod(cache, "SetHash", Qt::QueuedConnection, - OLIVE_NS_ARG(rational, time), - Q_ARG(QByteArray, hash), - Q_ARG(qint64, job_time), - Q_ARG(bool, hash_exists)); - } -} - -void RenderBackend::AutoCacheHashesGenerated() -{ - RenderTicketWatcher* watcher = static_cast(sender()); - - if (autocache_hash_tasks_.contains(watcher)) { - if (!watcher->WasCancelled()) { - QFutureWatcher* hw = new QFutureWatcher(); - connect(hw, &QFutureWatcher::finished, this, &RenderBackend::AutoCacheHashesProcessed); - autocache_hash_process_tasks_.append(hw); - hw->setFuture(QtConcurrent::run(this, - &RenderBackend::SetHashes, - viewer_node_->video_frame_cache(), - autocache_hash_tasks_.value(watcher), - watcher->Get().value >(), - watcher->GetTicket()->GetJobTime())); - } - - autocache_hash_tasks_.remove(watcher); - } - - delete watcher; -} - -void RenderBackend::AutoCacheHashesProcessed() -{ - QFutureWatcher* watcher = static_cast*>(sender()); - - if (autocache_hash_process_tasks_.contains(watcher)) { - autocache_hash_process_tasks_.removeOne(watcher); - - AutoCacheRequeueFrames(); - } - - delete watcher; -} - -void RenderBackend::AutoCacheAudioRendered() -{ - RenderTicketWatcher* watcher = static_cast(sender()); - - if (autocache_audio_tasks_.contains(watcher)) { - if (!watcher->WasCancelled()) { - viewer_node_->audio_playback_cache()->WritePCM(autocache_audio_tasks_.value(watcher), - watcher->Get().value(), - watcher->GetTicket()->GetJobTime()); - } - - autocache_audio_tasks_.remove(watcher); - } - - delete watcher; -} - -void RenderBackend::AutoCacheVideoRendered() -{ - RenderTicketWatcher* watcher = static_cast(sender()); - - if (autocache_video_tasks_.contains(watcher)) { - if (!watcher->WasCancelled()) { - const QByteArray& hash = autocache_video_tasks_.value(watcher); - - // Download frame in another thread - QFutureWatcher* w = new QFutureWatcher(); - autocache_video_download_tasks_.insert(w, hash); - connect(w, &QFutureWatcher::finished, this, &RenderBackend::AutoCacheVideoDownloaded); - w->setFuture(QtConcurrent::run(viewer_node_->video_frame_cache(), - &FrameHashCache::SaveCacheFrame, - hash, - watcher->Get().value())); - } - - autocache_video_tasks_.remove(watcher); - } - - delete watcher; -} - -void RenderBackend::AutoCacheVideoDownloaded() -{ - QFutureWatcher* watcher = static_cast*>(sender()); - - if (autocache_video_download_tasks_.contains(watcher)) { - if (!watcher->isCanceled()) { - if (watcher->result()) { - const QByteArray& hash = autocache_video_download_tasks_.value(watcher); - - autocache_currently_caching_hashes_.removeOne(hash); - - viewer_node_->video_frame_cache()->ValidateFramesWithHash(hash); - } else { - qCritical() << "Failed to download video frame"; - } - } - - autocache_video_download_tasks_.remove(watcher); - } - - delete watcher; -} - -void RenderBackend::QueuedInputRemoved() -{ - NodeInput* i = static_cast(sender()); - disconnect(i, &NodeInput::destroyed, this, &RenderBackend::QueuedInputRemoved); - graph_update_queue_.removeOne(i); -} - -//#define PRINT_UPDATE_QUEUE_INFO -void RenderBackend::ProcessUpdateQueue() -{ -#ifdef PRINT_UPDATE_QUEUE_INFO - qint64 t = QDateTime::currentMSecsSinceEpoch(); - qDebug() << "Processing update queue of" << graph_update_queue_.size() << "elements:"; -#endif - - while (!graph_update_queue_.isEmpty()) { - NodeInput* i = graph_update_queue_.takeFirst(); -#ifdef PRINT_UPDATE_QUEUE_INFO - qDebug() << " " << i->parentNode()->id() << i->id(); -#endif - disconnect(i, &NodeInput::destroyed, this, &RenderBackend::QueuedInputRemoved); - - CopyNodeInputValue(i); - } - -#ifdef PRINT_UPDATE_QUEUE_INFO - qDebug() << "Update queue took:" << (QDateTime::currentMSecsSinceEpoch() - t); -#endif -} - -void RenderBackend::WorkerFinished() -{ - RenderWorker* worker = static_cast(sender()); - - // Set busy state to false - for (int i=0;iparentNode()); - Q_ASSERT(our_copy_node); - NodeInput* our_copy = our_copy_node->GetInputWithID(input->id()); - - // Copy the standard/keyframe values between these two inputs - NodeInput::CopyValues(input, - our_copy, - false, - false); - - // Handle connections - if (input->is_connected() || our_copy->is_connected()) { - // If one of the inputs is connected, it's likely this change came from connecting or - // disconnecting whatever was connected to it - - // We start by removing all old dependencies from the map - QList old_deps = our_copy->GetExclusiveDependencies(); - foreach (Node* i, old_deps) { - copy_map_.take(copy_map_.key(i))->deleteLater(); - } - - // And clear any other edges - while (!our_copy->edges().isEmpty()) { - NodeParam::DisconnectEdge(our_copy->edges().first()); - } - - // Then we copy all node dependencies and connections (if there are any) - CopyNodeMakeConnection(input, our_copy); - } - - // Call on sub-elements too - if (input->IsArray()) { - foreach (NodeInput* i, static_cast(input)->sub_params()) { - CopyNodeInputValue(i); - } - } -} - -Node* RenderBackend::CopyNodeConnections(Node* src_node) -{ - // Check if this node is already in the map - Node* dst_node = copy_map_.value(src_node); - - // If not, create it now - if (!dst_node) { - dst_node = src_node->copy(); - - if (dst_node->IsTrack()) { - // Hack that ensures the track type is set since we don't bother copying the whole timeline - static_cast(dst_node)->set_track_type(static_cast(src_node)->track_type()); - } - - copy_map_.insert(src_node, dst_node); - } - - // Make sure its values are copied - Node::CopyInputs(src_node, dst_node, false); - - // Copy all connections - QList src_node_inputs = src_node->GetInputsIncludingArrays(); - QList dst_node_inputs = dst_node->GetInputsIncludingArrays(); - - for (int i=0;iis_connected()) { - Node* dst_node = CopyNodeConnections(src_input->get_connected_node()); - - NodeOutput* corresponding_output = dst_node->GetOutputWithID(src_input->get_connected_output()->id()); - - NodeParam::ConnectEdge(corresponding_output, - dst_input); - } -} - -void RenderBackend::ClearQueueOfType(RenderTicket::Type type) -{ - std::list::iterator i = render_queue_.begin(); - - while (i != render_queue_.end()) { - if ((*i)->GetType() == type) { - (*i)->Cancel(); - i = render_queue_.erase(i); - } else { - i++; - } - } -} - -void RenderBackend::SetActiveInstance() -{ - QMutexLocker locker(&instance_lock_); - - if (active_instance_ != this) { - // Signal active instance to stop - QMetaObject::invokeMethod(active_instance_, "ClearVideoQueue", Qt::QueuedConnection); - - active_instance_ = this; - } -} - -void RenderBackend::AutoCacheRequeueFrames() -{ - if (viewer_node_ - && viewer_node_->video_frame_cache()->HasInvalidatedRanges() - && autocache_hash_tasks_.isEmpty() - && autocache_hash_process_tasks_.isEmpty() - && autocache_has_changed_ - && (!autocache_paused_ || use_custom_autocache_range_)) { - TimeRange using_range; - - if (use_custom_autocache_range_) { - using_range = custom_autocache_range_; - use_custom_autocache_range_ = false; - } else { - using_range = autocache_range_; - } - - QVector invalidated_ranges = viewer_node_->video_frame_cache()->GetInvalidatedFrames(using_range); - - ClearVideoQueue(); - - // QMaps are automatically sorted by time which is always best for rendering - QList queued_hashes; - - foreach (const rational& t, invalidated_ranges) { - const QByteArray& hash = viewer_node_->video_frame_cache()->GetHash(t); - - if (t >= using_range.in() - && t < using_range.out() - && !queued_hashes.contains(hash) - && !autocache_currently_caching_hashes_.contains(hash)) { - // Don't render any hash more than once - queued_hashes.append(hash); - - RenderTicketWatcher* watcher = new RenderTicketWatcher(); - connect(watcher, &RenderTicketWatcher::Finished, this, &RenderBackend::AutoCacheVideoRendered); - autocache_video_tasks_.insert(watcher, hash); - - watcher->SetTicket(RenderFrame(t, false, hash)); - } - } - - autocache_has_changed_ = false; - } -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/renderbackend.h b/app/render/backend/renderbackend.h deleted file mode 100644 index c7e29e317..000000000 --- a/app/render/backend/renderbackend.h +++ /dev/null @@ -1,259 +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 . - -***/ - -#ifndef RENDERBACKEND_H -#define RENDERBACKEND_H - -#include - -#include "config/config.h" -#include "dialog/rendercancel/rendercancel.h" -#include "decodercache.h" -#include "node/graph.h" -#include "node/output/viewer/viewer.h" -#include "render/backend/colorprocessorcache.h" -#include "renderticket.h" -#include "renderticketwatcher.h" -#include "renderworker.h" - -OLIVE_NAMESPACE_ENTER - -class RenderBackend : public QObject -{ - Q_OBJECT -public: - RenderBackend(QObject* parent = nullptr); - - virtual ~RenderBackend() override; - - void Close(); - - ViewerOutput* GetViewerNode() const - { - return viewer_node_; - } - - void SetViewerNode(ViewerOutput* viewer_node); - - void SetAutoCacheEnabled(bool e) - { - autocache_enabled_ = e; - } - - bool IsAutoCachePaused() const - { - return autocache_paused_; - } - - void SetAutoCachePaused(bool paused) - { - autocache_paused_ = paused; - - if (autocache_paused_) { - // Pause the autocache - ClearVideoQueue(); - } else { - // Unpause the cache - AutoCacheRequeueFrames(); - } - } - - void AutoCacheRange(const TimeRange& range); - - void AutoCacheRequeueFrames(); - - void SetAutoCachePlayhead(const rational& playhead) - { - autocache_range_ = TimeRange(playhead - Config::Current()["DiskCacheBehind"].value(), - playhead + Config::Current()["DiskCacheAhead"].value()); - - autocache_has_changed_ = true; - use_custom_autocache_range_ = false; - - AutoCacheRequeueFrames(); - } - - void SetRenderMode(RenderMode::Mode e) - { - render_mode_ = e; - } - - void SetPreviewGenerationEnabled(bool e) - { - generate_audio_previews_ = e; - } - - void ProcessUpdateQueue(); - - /** - * @brief Asynchronously generate a hash at a given time - */ - RenderTicketPtr Hash(const QVector ×, bool prioritize = false); - - /** - * @brief Asynchronously generate a frame at a given time - */ - RenderTicketPtr RenderFrame(const rational& time, bool prioritize = false, const QByteArray& hash = QByteArray()); - - /** - * @brief Asynchronously generate a chunk of audio - */ - RenderTicketPtr RenderAudio(const TimeRange& r, bool prioritize = false); - - const VideoParams& GetVideoParams() const - { - return video_params_; - } - - const AudioParams& GetAudioParams() const - { - return audio_params_; - } - - void SetVideoParams(const VideoParams& params); - - void SetAudioParams(const AudioParams& params); - - void SetForceDownloadResolution(bool e) - { - video_force_download_resolution_ = e; - } - - void SetVideoDownloadMatrix(const QMatrix4x4& mat) - { - video_download_matrix_ = mat; - } - - void IgnoreNextMouseButton(); - - static std::list SplitRangeIntoChunks(const TimeRange& r); - -public slots: - void NodeGraphChanged(NodeInput *source); - - void ClearVideoQueue(); - - void ClearAudioQueue(); - - void ClearQueue(); - -signals: - -protected: - virtual RenderWorker* CreateNewWorker() = 0; - -private: - void CopyNodeInputValue(NodeInput* input); - Node *CopyNodeConnections(Node *src_node); - void CopyNodeMakeConnection(NodeInput *src_input, NodeInput *dst_input); - - void ClearQueueOfType(RenderTicket::Type type); - - void SetHashes(FrameHashCache* cache, const QVector& times, const QVector& hashes, qint64 job_time); - - ViewerOutput* viewer_node_; - - // VIDEO MEMBERS - VideoParams video_params_; - bool video_force_download_resolution_; - QMatrix4x4 video_download_matrix_; - - // AUDIO MEMBERS - AudioParams audio_params_; - - QList graph_update_queue_; - QHash copy_map_; - ViewerOutput* copied_viewer_node_; - - std::list render_queue_; - - std::list running_tickets_; - - struct WorkerData { - RenderWorker* worker; - bool busy; - }; - - QVector workers_; - - bool autocache_enabled_; - bool autocache_paused_; - - bool generate_audio_previews_; - - RenderMode::Mode render_mode_; - - TimeRange autocache_range_; - - bool autocache_has_changed_; - - bool use_custom_autocache_range_; - TimeRange custom_autocache_range_; - - static QVector instances_; - static QMutex instance_lock_; - static RenderBackend* active_instance_; - static QThreadPool thread_pool_; - void SetActiveInstance(); - - QMap > autocache_hash_tasks_; - - QList*> autocache_hash_process_tasks_; - - QMap autocache_audio_tasks_; - - QMap autocache_video_tasks_; - - QMap*, QByteArray> autocache_video_download_tasks_; - - QVector autocache_currently_caching_hashes_; - - bool ignore_next_mouse_button_; - -private slots: - void WorkerFinished(); - - void RunNextJob(); - - void TicketFinished(); - - void WorkerGeneratedWaveform(OLIVE_NAMESPACE::RenderTicketPtr ticket, OLIVE_NAMESPACE::TrackOutput* track, OLIVE_NAMESPACE::AudioVisualWaveform samples, OLIVE_NAMESPACE::TimeRange range); - - void AutoCacheVideoInvalidated(const OLIVE_NAMESPACE::TimeRange &range); - - void AutoCacheAudioInvalidated(const OLIVE_NAMESPACE::TimeRange &range); - - void AutoCacheHashesGenerated(); - - void AutoCacheHashesProcessed(); - - void AutoCacheAudioRendered(); - - void AutoCacheVideoRendered(); - - void AutoCacheVideoDownloaded(); - - void QueuedInputRemoved(); - -}; - -OLIVE_NAMESPACE_EXIT - -#endif // RENDERBACKEND_H diff --git a/app/render/backend/renderworker.cpp b/app/render/backend/renderworker.cpp deleted file mode 100644 index 7c3e2bddd..000000000 --- a/app/render/backend/renderworker.cpp +++ /dev/null @@ -1,471 +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 "renderworker.h" - -#include -#include -#include - -#include "audio/audiovisualwaveform.h" -#include "common/functiontimer.h" -#include "config/config.h" -#include "node/block/clip/clip.h" -#include "task/conform/conform.h" - -OLIVE_NAMESPACE_ENTER - -// FIXME: Hardcoded value. It seems to work fine, but is there a possibility we should make -// this a dynamic value somehow or a configurable value? -const int RenderWorker::kMaxDecoderLife = 6000; - -RenderWorker::RenderWorker(RenderBackend* parent) : - parent_(parent), - video_force_download_resolution_(false), - available_(true), - generate_audio_previews_(false), - render_mode_(RenderMode::kOnline) -{ - cleanup_timer_ = new QTimer(); - cleanup_timer_->setInterval(kMaxDecoderLife); - connect(cleanup_timer_, &QTimer::timeout, this, &RenderWorker::ClearOldDecoders, Qt::DirectConnection); - cleanup_timer_->moveToThread(qApp->thread()); - QMetaObject::invokeMethod(cleanup_timer_, "start", Qt::QueuedConnection); -} - -RenderWorker::~RenderWorker() -{ - QMetaObject::invokeMethod(cleanup_timer_, "stop", Qt::QueuedConnection); - cleanup_timer_->deleteLater(); -} - -void RenderWorker::Hash(RenderTicketPtr ticket, ViewerOutput *viewer, const QVector ×) -{ - ticket_ = ticket; - - QVector hashes(times.size()); - - for (int i=0;itexture_input()->get_connected_node(), - video_params_, - times.at(i)); - } - - ticket->Finish(QVariant::fromValue(hashes)); - - emit FinishedJob(); -} - -QByteArray RenderWorker::HashNode(const Node *n, const VideoParams ¶ms, const rational &time) -{ - QCryptographicHash hasher(QCryptographicHash::Sha1); - - // Embed video parameters into this hash - hasher.addData(reinterpret_cast(¶ms.effective_width()), sizeof(int)); - hasher.addData(reinterpret_cast(¶ms.effective_height()), sizeof(int)); - hasher.addData(reinterpret_cast(¶ms.format()), sizeof(PixelFormat::Format)); - - if (n) { - n->Hash(hasher, time); - } - - return hasher.result(); -} - -void RenderWorker::ClearOldDecoders() -{ - QMutexLocker locker(&decoder_lock_); - - QHash::iterator i = decoder_age_.begin(); - - while (i != decoder_age_.end()) { - if (i.value() < QDateTime::currentMSecsSinceEpoch() - kMaxDecoderLife) { - // This decoder is old, remove it - decoder_cache_.remove(i.key()); - - i = decoder_age_.erase(i); - } else { - i++; - } - } -} - -void RenderWorker::RenderFrame(RenderTicketPtr ticket, ViewerOutput* viewer, const rational &time) -{ - ticket_ = ticket; - - NodeValueTable table = ProcessInput(viewer->texture_input(), - TimeRange(time, time + video_params_.time_base())); - - QVariant texture = table.Get(NodeParam::kTexture); - - PixelFormat::Format output_format; - if (!texture.isNull() && TextureHasAlpha(texture)) { - output_format = PixelFormat::GetFormatWithAlphaChannel(video_params_.format()); - } else { - output_format = PixelFormat::GetFormatWithoutAlphaChannel(video_params_.format()); - } - - FramePtr frame = Frame::Create(); - frame->set_timestamp(time); - - 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(), - video_params_.time_base(), - output_format, - video_params_.pixel_aspect_ratio(), - video_params_.interlacing(), - video_params_.divider())); - frame->allocate(); - } - - if (texture.isNull()) { - // Blank frame out - memset(frame->data(), 0, frame->allocated_size()); - } else { - // Dump texture contents to frame - TextureToFrame(texture, frame, video_download_matrix_); - } - - ticket->Finish(QVariant::fromValue(frame)); - - emit FinishedJob(); -} - -void RenderWorker::RenderAudio(RenderTicketPtr ticket, ViewerOutput* viewer, const TimeRange &range) -{ - ticket_ = ticket; - - NodeValueTable table = ProcessInput(viewer->samples_input(), range); - - QVariant samples = table.Get(NodeParam::kSamples); - - ticket->Finish(samples); - - emit FinishedJob(); -} - -void RenderWorker::ClearDecoders() -{ - decoder_cache_.clear(); -} - -NodeValueTable RenderWorker::GenerateBlockTable(const TrackOutput *track, const TimeRange &range) -{ - if (track->track_type() == Timeline::kTrackTypeAudio) { - - QList active_blocks = track->BlocksAtTimeRange(range); - - // All these blocks will need to output to a buffer so we create one here - SampleBufferPtr block_range_buffer = SampleBuffer::CreateAllocated(audio_params_, - audio_params_.time_to_samples(range.length())); - block_range_buffer->fill(0); - - NodeValueTable merged_table; - - // Loop through active blocks retrieving their audio - foreach (Block* b, active_blocks) { - TimeRange range_for_block(qMax(b->in(), range.in()), - qMin(b->out(), range.out())); - - int destination_offset = audio_params_.time_to_samples(range_for_block.in() - range.in()); - int max_dest_sz = audio_params_.time_to_samples(range_for_block.length()); - - // Destination buffer - NodeValueTable table = GenerateTable(b, range_for_block); - SampleBufferPtr samples_from_this_block = table.Take(NodeParam::kSamples).value(); - - if (!samples_from_this_block) { - // If we retrieved no samples from this block, do nothing - continue; - } - - // FIXME: Doesn't handle reversing - if (b->speed_input()->is_keyframing() || b->speed_input()->is_connected()) { - // FIXME: We'll need to calculate the speed hoo boy - } else { - double speed_value = b->speed_input()->get_standard_value().toDouble(); - - if (qIsNull(speed_value)) { - // Just silence, don't think there's any other practical application of 0 speed audio - samples_from_this_block->fill(0); - } else if (!qFuzzyCompare(speed_value, 1.0)) { - // Multiply time - samples_from_this_block->speed(speed_value); - } - } - - int copy_length = qMin(max_dest_sz, samples_from_this_block->sample_count()); - - // Copy samples into destination buffer - block_range_buffer->set(samples_from_this_block->const_data(), destination_offset, copy_length); - - NodeValueTable::Merge({merged_table, table}); - } - - if (generate_audio_previews_) { - // Find original track object - TrackOutput* original_track = nullptr; - - // Have to do a manual loop since our track is const and QHash won't take it - QHash::const_iterator i; - for (i=copy_map_->constBegin(); i!=copy_map_->constEnd(); i++) { - if (i.value() == track) { - original_track = static_cast(i.key()); - break; - } - } - - if (original_track) { - // Generate a visual waveform and send it back to the main thread - AudioVisualWaveform visual_waveform; - visual_waveform.set_channel_count(audio_params_.channel_count()); - visual_waveform.OverwriteSamples(block_range_buffer, audio_params_.sample_rate()); - - emit WaveformGenerated(ticket_, original_track, visual_waveform, range); - } - } - - merged_table.Push(NodeParam::kSamples, QVariant::fromValue(block_range_buffer), track); - - return merged_table; - - } else { - return NodeTraverser::GenerateBlockTable(track, range); - } -} - -QVariant RenderWorker::ProcessSamples(const Node *node, const TimeRange &range, const SampleJob& job) -{ - if (!job.samples() || !job.samples()->is_allocated()) { - return QVariant(); - } - - SampleBufferPtr output_buffer = SampleBuffer::CreateAllocated(job.samples()->audio_params(), job.samples()->sample_count()); - NodeValueDatabase value_db; - - for (int i=0;isample_count();i++) { - // Calculate the exact rational time at this sample - double sample_to_second = static_cast(i) / static_cast(audio_params_.sample_rate()); - - rational this_sample_time = rational::fromDouble(range.in().toDouble() + sample_to_second); - - // Update all non-sample and non-footage inputs - NodeValueMap::const_iterator j; - for (j=job.GetValues().constBegin(); j!=job.GetValues().constEnd(); j++) { - NodeValueTable value; - NodeInput* corresponding_input = node->GetInputWithID(j.key()); - - if (corresponding_input) { - value = ProcessInput(corresponding_input, TimeRange(this_sample_time, this_sample_time)); - } else { - value.Push(j.value()); - } - - value_db.Insert(j.key(), value); - } - - AddGlobalsToDatabase(value_db, TimeRange(this_sample_time, this_sample_time)); - - node->ProcessSamples(value_db, - job.samples(), - output_buffer, - i); - } - - return QVariant::fromValue(output_buffer); -} - -QVariant RenderWorker::ProcessFrameGeneration(const Node* node, const GenerateJob &job) -{ - FramePtr frame = Frame::Create(); - - PixelFormat::Format output_fmt; - if (job.GetAlphaChannelRequired()) { - output_fmt = PixelFormat::GetFormatWithAlphaChannel(video_params_.format()); - } else { - output_fmt = PixelFormat::GetFormatWithoutAlphaChannel(video_params_.format()); - } - - frame->set_video_params(VideoParams(video_params_.width(), - video_params_.height(), - video_params_.time_base(), - output_fmt, - video_params_.pixel_aspect_ratio(), - video_params_.interlacing(), - video_params_.divider())); - frame->allocate(); - - node->GenerateFrame(frame, job); - - return CachedFrameToTexture(frame); -} - -QVariant RenderWorker::GetCachedFrame(const Node* node, const rational& time) -{ - if (render_mode_ == RenderMode::kOffline - && !cache_path_.isEmpty() - && node->id() == QStringLiteral("org.olivevideoeditor.Olive.videoinput")) { - QByteArray hash = HashNode(node, video_params(), time); - - FramePtr f = FrameHashCache::LoadCacheFrame(cache_path_, hash); - - if (f) { - // The cached frame won't load with the correct divider by default, so we enforce it here - f->set_video_params(VideoParams(f->width() * video_params_.divider(), - f->height() * video_params_.divider(), - f->video_params().time_base(), - f->video_params().format(), - f->video_params().pixel_aspect_ratio(), - f->video_params().interlacing(), - video_params_.divider())); - - return CachedFrameToTexture(f); - } - } - - return QVariant(); -} - -DecoderPtr RenderWorker::ResolveDecoderFromInput(StreamPtr stream) -{ - // Access a map of Node inputs and decoder instances and retrieve a frame! - QMutexLocker locker(&decoder_lock_); - - DecoderPtr decoder = decoder_cache_.value(stream.get()); - - if (!decoder && stream) { - // Create a new Decoder here - decoder = Decoder::CreateFromID(stream->footage()->decoder()); - decoder->set_stream(stream); - - if (decoder->Open()) { - decoder_cache_.insert(stream.get(), decoder); - } else { - decoder = nullptr; - qWarning() << "Failed to open decoder for" << stream->footage()->filename() - << "::" << stream->index(); - } - } - - decoder_age_.insert(stream.get(), QDateTime::currentMSecsSinceEpoch()); - - return decoder; -} - -QVariant RenderWorker::ProcessVideoFootage(StreamPtr stream, const rational &input_time) -{ - VideoStreamPtr video_stream = std::static_pointer_cast(stream); - rational time_match = (video_stream->video_type() == VideoStream::kVideoTypeStill) ? 0 : input_time; - QString colorspace_match = video_stream->get_colorspace_match_string(); - - QVariant value; - bool found_cache = false; - - if (still_image_cache_.contains(stream.get())) { - const CachedStill& cs = still_image_cache_[stream.get()]; - - if (cs.colorspace == colorspace_match - && cs.alpha_is_associated == video_stream->premultiplied_alpha() - && cs.divider == video_params_.divider() - && cs.time == time_match) { - value = cs.texture; - found_cache = true; - } else { - still_image_cache_.remove(stream.get()); - } - } - - if (!found_cache) { - - DecoderPtr decoder = ResolveDecoderFromInput(stream); - - if (decoder) { - FramePtr frame = decoder->RetrieveVideo(input_time, - video_params().divider()); - - if (frame) { - // Return a texture from the derived class - value = FootageFrameToTexture(stream, frame); - - if (!value.isNull()) { - // Put this into the image cache instead - still_image_cache_.insert(stream.get(), {value, - colorspace_match, - video_stream->premultiplied_alpha(), - video_params_.divider(), - time_match}); - } - } - } - - } - - return value; -} - -QVariant RenderWorker::ProcessAudioFootage(StreamPtr stream, const TimeRange &input_time) -{ - QVariant value; - - DecoderPtr decoder = ResolveDecoderFromInput(stream); - - if (decoder) { - // See if we have a conformed version of this audio - if (!decoder->HasConformedVersion(audio_params())) { - - // If not, the audio needs to be conformed - // For online rendering/export, it's a waste of time to render the audio until we have - // all we need, so we try to handle the conform ourselves - AudioStreamPtr as = std::static_pointer_cast(stream); - - // Check if any other threads are conforming this audio - if (as->try_start_conforming(audio_params())) { - - // If not, conform it ourselves - decoder->ConformAudio(&IsCancelled(), audio_params()); - - } else { - - // If another thread is conforming already, hackily try to wait until it's done. - do { - QThread::msleep(1000); - } while (!as->has_conformed_version(audio_params()) && !IsCancelled()); - - } - - } - - if (decoder->HasConformedVersion(audio_params())) { - SampleBufferPtr frame = decoder->RetrieveAudio(input_time.in(), input_time.length(), - audio_params()); - - if (frame) { - value = QVariant::fromValue(frame); - } - } - } - - return value; -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/renderworker.h b/app/render/backend/renderworker.h deleted file mode 100644 index 84f9fbe94..000000000 --- a/app/render/backend/renderworker.h +++ /dev/null @@ -1,208 +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 . - -***/ - -#ifndef RENDERWORKER_H -#define RENDERWORKER_H - -#include - -#include "decodercache.h" -#include "node/traverser.h" -#include "node/output/viewer/viewer.h" -#include "renderticket.h" - -OLIVE_NAMESPACE_ENTER - -class RenderBackend; - -class RenderWorker : public QObject, public NodeTraverser -{ - Q_OBJECT -public: - RenderWorker(RenderBackend* parent); - - virtual ~RenderWorker() override; - - bool IsAvailable() const - { - return available_; - } - - void SetAvailable(bool a) - { - available_ = a; - } - - void SetVideoParams(const VideoParams& params) - { - video_params_ = params; - } - - void SetAudioParams(const AudioParams& params) - { - audio_params_ = params; - } - - void SetForceDownloadResolution(bool e) - { - video_force_download_resolution_ = e; - } - - void SetVideoDownloadMatrix(const QMatrix4x4& mat) - { - video_download_matrix_ = mat; - } - - void SetCopyMap(QHash* copy_map) - { - copy_map_ = copy_map; - } - - void SetRenderMode(const RenderMode::Mode& mode) - { - render_mode_ = mode; - } - - void SetPreviewGenerationEnabled(bool e) - { - generate_audio_previews_ = e; - } - - void SetCachePath(const QString& s) - { - cache_path_ = s; - } - - void Hash(RenderTicketPtr ticket, ViewerOutput* viewer, const QVector& times); - - /** - * @brief Render the frame at this time - * - * Produces a fully rendered frame from the connected viewer at this time. - * - * @return - * - * A frame corresponding to the set video parameters. If no nodes are active at the time, this - * function will still return a blank frame with the same parameters. If no viewer node is set, - * nullptr is returned. - */ - void RenderFrame(RenderTicketPtr ticket, ViewerOutput* viewer, const rational &time); - - void RenderAudio(RenderTicketPtr ticket, ViewerOutput* viewer, const TimeRange& range); - - void ClearDecoders(); - -protected: - virtual void TextureToFrame(const QVariant& texture, FramePtr frame, const QMatrix4x4 &mat) const = 0; - - virtual QVariant FootageFrameToTexture(StreamPtr stream, FramePtr frame) const = 0; - - virtual QVariant CachedFrameToTexture(FramePtr frame) const = 0; - - virtual NodeValueTable GenerateBlockTable(const TrackOutput *track, const TimeRange &range) override; - - virtual QVariant ProcessVideoFootage(StreamPtr stream, const rational &input_time) override; - - virtual QVariant ProcessAudioFootage(StreamPtr stream, const TimeRange &input_time) override; - - virtual QVariant ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) override; - - virtual QVariant ProcessFrameGeneration(const Node *node, const GenerateJob& job) override; - - virtual QVariant GetCachedFrame(const Node *node, const rational &time) override; - - virtual bool TextureHasAlpha(const QVariant& v) const = 0; - - const VideoParams& video_params() const - { - return video_params_; - } - - const AudioParams& audio_params() const - { - return audio_params_; - } - - const RenderMode::Mode& render_mode() const - { - return render_mode_; - } - -signals: - void AudioConformUnavailable(StreamPtr stream, TimeRange range, - rational stream_time, AudioParams params); - - void FinishedJob(); - - void WaveformGenerated(OLIVE_NAMESPACE::RenderTicketPtr ticket, OLIVE_NAMESPACE::TrackOutput* track, OLIVE_NAMESPACE::AudioVisualWaveform samples, OLIVE_NAMESPACE::TimeRange range); - -private: - DecoderPtr ResolveDecoderFromInput(StreamPtr stream); - - static QByteArray HashNode(const Node* n, const VideoParams& params, const rational& time); - - RenderBackend* parent_; - - RenderTicketPtr ticket_; - - VideoParams video_params_; - - AudioParams audio_params_; - - struct CachedStill { - QVariant texture; - QString colorspace; - bool alpha_is_associated; - int divider; - rational time; - }; - - QHash still_image_cache_; - - bool video_force_download_resolution_; - QMatrix4x4 video_download_matrix_; - - QMutex decoder_lock_; - DecoderCache decoder_cache_; - QHash decoder_age_; - - TimeRange audio_render_time_; - bool available_; - - bool generate_audio_previews_; - - QHash* copy_map_; - - RenderMode::Mode render_mode_; - - QTimer* cleanup_timer_; - - QString cache_path_; - - static const int kMaxDecoderLife; - -private slots: - void ClearOldDecoders(); - -}; - -OLIVE_NAMESPACE_EXIT - -#endif // RENDERWORKER_H diff --git a/app/render/color.cpp b/app/render/color.cpp index e8e4cbfca..8167701db 100644 --- a/app/render/color.cpp +++ b/app/render/color.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,54 +20,57 @@ #include "color.h" +#include + #include "common/clamp.h" +#include "common/oiioutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -Color Color::fromHsv(const float &h, const float &s, const float &v) +Color Color::fromHsv(const double &h, const double &s, const double &v) { - float C = s * v; - float X = C * (1.0f - abs(fmod(h / 60.0f, 2.0f) - 1.0f)); - float m = v - C; - float Rs, Gs, Bs; + double C = s * v; + double X = C * (1.0 - abs(fmod(h / 60.0, 2.0) - 1.0)); + double m = v - C; + double Rs, Gs, Bs; - if(h >= 0.0f && h < 60.0f) { + if(h >= 0.0 && h < 60.0) { Rs = C; Gs = X; - Bs = 0.0f; + Bs = 0.0; } - else if(h >= 60.0f && h < 120.0f) { + else if(h >= 60.0 && h < 120.0) { Rs = X; Gs = C; - Bs = 0.0f; + Bs = 0.0; } - else if(h >= 120.0f && h < 180.0f) { - Rs = 0.0f; + else if(h >= 120.0 && h < 180.0) { + Rs = 0.0; Gs = C; Bs = X; } - else if(h >= 180.0f && h < 240.0f) { - Rs = 0.0f; + else if(h >= 180.0 && h < 240.0) { + Rs = 0.0; Gs = X; Bs = C; } - else if(h >= 240.0f && h < 300.0f) { + else if(h >= 240.0 && h < 300.0) { Rs = X; - Gs = 0.0f; + Gs = 0.0; Bs = C; } else { Rs = C; - Gs = 0.0f; + Gs = 0.0; Bs = X; } return Color(Rs + m, Gs + m, Bs + m); } -Color::Color(const char *data, const PixelFormat::Format &format) +Color::Color(const char *data, const VideoParams::Format &format, int ch_layout) { - *this = fromData(data, format); + *this = fromData(data, format, ch_layout); } Color::Color(const QColor &c) @@ -78,11 +81,11 @@ Color::Color(const QColor &c) set_alpha(c.alphaF()); } -void Color::toHsv(float *hue, float *sat, float *val) const +void Color::toHsv(double *hue, double *sat, double *val) const { - float fCMax = qMax(qMax(red(), green()), blue()); - float fCMin = qMin(qMin(red(), green()), blue()); - float fDelta = fCMax - fCMin; + double fCMax = qMax(qMax(red(), green()), blue()); + double fCMin = qMin(qMin(red(), green()), blue()); + double fDelta = fCMax - fCMin; if(fDelta > 0) { if(fCMax == red()) { @@ -111,31 +114,31 @@ void Color::toHsv(float *hue, float *sat, float *val) const } } -float Color::hsv_hue() const +double Color::hsv_hue() const { - float h, s, v; + double h, s, v; toHsv(&h, &s, &v); return h; } -float Color::hsv_saturation() const +double Color::hsv_saturation() const { - float h, s, v; + double h, s, v; toHsv(&h, &s, &v); return s; } -float Color::value() const +double Color::value() const { - float h, s, v; + double h, s, v; toHsv(&h, &s, &v); return v; } -void Color::toHsl(float *hue, float *sat, float *lightness) const +void Color::toHsl(double *hue, double *sat, double *lightness) const { - float fCMin = qMin(red(), qMin(green(), blue())); - float fCMax = qMax(red(), qMax(green(), blue())); + double fCMin = qMin(red(), qMin(green(), blue())); + double fCMax = qMax(red(), qMax(green(), blue())); *lightness = 0.5 * (fCMin + fCMax); @@ -173,49 +176,45 @@ void Color::toHsl(float *hue, float *sat, float *lightness) const } } -float Color::hsl_hue() const +double Color::hsl_hue() const { - float h, s, l; + double h, s, l; toHsl(&h, &s, &l); return h; } -float Color::hsl_saturation() const +double Color::hsl_saturation() const { - float h, s, l; + double h, s, l; toHsl(&h, &s, &l); return s; } -float Color::lightness() const +double Color::lightness() const { - float h, s, l; + double h, s, l; toHsl(&h, &s, &l); return l; } -void Color::toData(char *data, const PixelFormat::Format &format) const +void Color::toData(char *data, const VideoParams::Format &format, int ch_layout) const { - OIIO::convert_types(PixelFormat::GetOIIOTypeDesc(PixelFormat::PIX_FMT_RGB32F), - data_, - PixelFormat::GetOIIOTypeDesc(format), - data, - PixelFormat::FormatHasAlphaChannel(format) ? kRGBAChannels : kRGBChannels); + OIIO::convert_pixel_values(OIIO::TypeDesc::DOUBLE, + data_, + OIIOUtils::GetOIIOBaseTypeFromFormat(format), + data, + ch_layout); } -Color Color::fromData(const char *data, const PixelFormat::Format &format) +Color Color::fromData(const char *data, const VideoParams::Format &format, int ch_layout) { Color c; - OIIO::convert_types(PixelFormat::GetOIIOTypeDesc(format), - data, - PixelFormat::GetOIIOTypeDesc(PixelFormat::PIX_FMT_RGB32F), - c.data_, - PixelFormat::FormatHasAlphaChannel(format) ? kRGBAChannels : kRGBChannels); - - if (!PixelFormat::FormatHasAlphaChannel(format)) { - c.set_alpha(1.0f); - } + OIIO::convert_pixel_values(OIIOUtils::GetOIIOBaseTypeFromFormat(format), + data, + OIIO::TypeDesc::DOUBLE, + c.data_, + ch_layout); return c; } @@ -225,22 +224,22 @@ QColor Color::toQColor() const QColor c; // QColor only supports values from 0.0 to 1.0 and are only used for UI representations - c.setRedF(clamp(red(), 0.0f, 1.0f)); - c.setGreenF(clamp(green(), 0.0f, 1.0f)); - c.setBlueF(clamp(blue(), 0.0f, 1.0f)); - c.setAlphaF(clamp(alpha(), 0.0f, 1.0f)); + c.setRedF(clamp(red(), 0.0, 1.0)); + c.setGreenF(clamp(green(), 0.0, 1.0)); + c.setBlueF(clamp(blue(), 0.0, 1.0)); + c.setAlphaF(clamp(alpha(), 0.0, 1.0)); return c; } -float Color::GetRoughLuminance() const +double Color::GetRoughLuminance() const { - return (2*red()+blue()+3*green())/6.0f; + return (2*red()+blue()+3*green())/6.0; } const Color &Color::operator+=(const Color &rhs) { - for (int i=0;i #include "common/define.h" -#include "render/pixelformat.h" +#include "render/videoparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** - * @brief High precision 32-bit float based RGBA color value + * @brief High precision 64-bit float based RGBA color value */ class Color { public: Color() { - for (int i=0;igetDefaultLumaCoefs(rgb); } @@ -322,69 +307,6 @@ Color ColorManager::GetDefaultLumaCoefs() const return c; } -ColorManager::OCIOMethod ColorManager::GetOCIOMethodForMode(RenderMode::Mode mode) -{ - return static_cast(Core::GetPreferenceForRenderMode(mode, QStringLiteral("OCIOMethod")).toInt()); -} - -void ColorManager::SetOCIOMethodForMode(RenderMode::Mode mode, ColorManager::OCIOMethod method) -{ - Core::SetPreferenceForRenderMode(mode, QStringLiteral("OCIOMethod"), method); -} - -void ColorManager::AssociateAlphaPixFmtFilter(ColorManager::AlphaAction action, FramePtr f) -{ - if (!PixelFormat::FormatHasAlphaChannel(f->format())) { - // This frame has no alpha channel, do nothing - return; - } - - int pixel_count = f->width() * f->height() * kRGBAChannels; - - switch (static_cast(f->format())) { - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - qWarning() << "Alpha association functions received an invalid pixel format"; - break; - case PixelFormat::PIX_FMT_RGB8: - case PixelFormat::PIX_FMT_RGBA8: - case PixelFormat::PIX_FMT_RGB16U: - case PixelFormat::PIX_FMT_RGBA16U: - qWarning() << "Alpha association functions only works on float-based pixel formats at this time"; - break; - case PixelFormat::PIX_FMT_RGB16F: - case PixelFormat::PIX_FMT_RGBA16F: - { - AssociateAlphaInternal(action, reinterpret_cast(f->data()), pixel_count); - break; - } - case PixelFormat::PIX_FMT_RGB32F: - case PixelFormat::PIX_FMT_RGBA32F: - { - AssociateAlphaInternal(action, reinterpret_cast(f->data()), pixel_count); - break; - } - } -} - -template -void ColorManager::AssociateAlphaInternal(ColorManager::AlphaAction action, T *data, int pix_count) -{ - for (int i=0;i 0) { - for (int j=0;j +#include #include "codec/frame.h" #include "colorprocessor.h" #define OCIO_SET_C_LOCALE_FOR_SCOPE ColorManager::SetLocale d("C") -OLIVE_NAMESPACE_ENTER +namespace olive { class ColorManager : public QObject { @@ -50,12 +51,6 @@ public: void SetConfigAndDefaultInput(const QString& filename, const QString& s); - static void DisassociateAlpha(FramePtr f); - - static void AssociateAlpha(FramePtr f); - - static void ReassociateAlpha(FramePtr f); - QStringList ListAvailableDisplays(); QString GetDefaultDisplay(); @@ -82,18 +77,9 @@ public: static QStringList ListAvailableColorspaces(OCIO::ConstConfigRcPtr config); - void GetDefaultLumaCoefs(float* rgb) const; + void GetDefaultLumaCoefs(double *rgb) const; Color GetDefaultLumaCoefs() const; - enum OCIOMethod { - kOCIOFast, - kOCIOAccurate - }; - - static OCIOMethod GetOCIOMethodForMode(RenderMode::Mode mode); - - static void SetOCIOMethodForMode(RenderMode::Mode mode, OCIOMethod method); - class SetLocale { public: @@ -106,6 +92,11 @@ public: }; + QMutex* mutex() + { + return &mutex_; + } + signals: void ConfigChanged(); @@ -118,27 +109,18 @@ private: OCIO::ConstConfigRcPtr config_; - enum AlphaAction { - kAssociate, - kDisassociate, - kReassociate - }; - - static void AssociateAlphaPixFmtFilter(AlphaAction action, FramePtr f); - - template - static void AssociateAlphaInternal(AlphaAction action, T* data, int pix_count); - QString config_filename_; QString default_input_color_space_; QString reference_space_; + QMutex mutex_; + static OCIO::ConstConfigRcPtr default_config_; }; -OLIVE_NAMESPACE_EXIT +} #endif // COLORSERVICE_H diff --git a/app/render/colorprocessor.cpp b/app/render/colorprocessor.cpp index 4b98a5133..90ce7c15f 100644 --- a/app/render/colorprocessor.cpp +++ b/app/render/colorprocessor.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,31 +21,50 @@ #include "colorprocessor.h" #include "common/define.h" +#include "common/ocioutils.h" #include "colormanager.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const ColorTransform &transform) { + QMutexLocker locker(config->mutex()); + const QString& output = (transform.output().isEmpty()) ? config->GetDefaultDisplay() : transform.output(); if (transform.is_display()) { const QString& view = (transform.view().isEmpty()) ? config->GetDefaultView(output) : transform.view(); - OCIO::DisplayTransformRcPtr display_transform = OCIO::DisplayTransform::Create(); + auto display_transform = OCIO::DisplayViewTransform::Create(); - display_transform->setInputColorSpaceName(input.toUtf8()); + display_transform->setSrc(input.toUtf8()); display_transform->setDisplay(output.toUtf8()); display_transform->setView(view.toUtf8()); - if (!transform.look().isEmpty()) { - display_transform->setLooksOverride(transform.look().toUtf8()); - display_transform->setLooksOverrideEnabled(true); - } - OCIO_SET_C_LOCALE_FOR_SCOPE; - processor_ = config->GetConfig()->getProcessor(display_transform); + + if (transform.look().isEmpty()) { + processor_ = config->GetConfig()->getProcessor(display_transform); + } else { + auto group = OCIO::GroupTransform::Create(); + + const char* out_cs = OCIO::LookTransform::GetLooksResultColorSpace(config->GetConfig(), + config->GetConfig()->getCurrentContext(), + transform.look().toUtf8()); + + auto lt = OCIO::LookTransform::Create(); + lt->setSrc(input.toUtf8()); + lt->setDst(out_cs); + lt->setLooks(transform.look().toUtf8()); + lt->setSkipColorSpaceConversion(false); + group->appendTransform(lt); + + display_transform->setSrc(out_cs); + group->appendTransform(display_transform); + + processor_ = config->GetConfig()->getProcessor(group); + } } else { @@ -54,25 +73,49 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const output.toUtf8()); } + + cpu_processor_ = processor_->getDefaultCPUProcessor(); + id_ = GenerateID(config, input, transform); } void ColorProcessor::ConvertFrame(Frame *f) { - OCIO::PackedImageDesc img(reinterpret_cast(f->data()), + OCIO::BitDepth ocio_bit_depth = OCIOUtils::GetOCIOBitDepthFromPixelFormat(f->format()); + + if (ocio_bit_depth == OCIO::BIT_DEPTH_UNKNOWN) { + qCritical() << "Tried to color convert frame with no format"; + return; + } + + OCIO::PackedImageDesc img(f->data(), f->width(), f->height(), - PixelFormat::ChannelCount(f->format()), + VideoParams::kRGBAChannelCount, + ocio_bit_depth, OCIO::AutoStride, OCIO::AutoStride, f->linesize_bytes()); - processor_->apply(img); + cpu_processor_->apply(img); } -Color ColorProcessor::ConvertColor(Color in) +Color ColorProcessor::ConvertColor(const Color& in) { - processor_->applyRGBA(in.data()); - return in; + // I've been bamboozled + float c[4] = {float(in.red()), float(in.green()), float(in.blue()), float(in.alpha())}; + + cpu_processor_->applyRGBA(c); + + return Color(c[0], c[1], c[2], c[3]); +} + +QString ColorProcessor::GenerateID(ColorManager *config, const QString &input, const ColorTransform &transform) +{ + return QStringLiteral("%1:%2:%3:%4:%5").arg(config->GetConfigFilename(), + input, + transform.display(), + transform.view(), + transform.look()); } ColorProcessorPtr ColorProcessor::Create(ColorManager *config, const QString& input, const ColorTransform &transform) @@ -90,4 +133,4 @@ void ColorProcessor::ConvertFrame(FramePtr f) ConvertFrame(f.get()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/render/colorprocessor.h b/app/render/colorprocessor.h index 6912cd66d..0704b89e0 100644 --- a/app/render/colorprocessor.h +++ b/app/render/colorprocessor.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,10 +22,11 @@ #define COLORPROCESSOR_H #include "codec/frame.h" +#include "common/ocioutils.h" #include "render/color.h" #include "render/colortransform.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ColorManager; @@ -51,15 +52,28 @@ public: void ConvertFrame(FramePtr f); void ConvertFrame(Frame* f); - Color ConvertColor(Color in); + Color ConvertColor(const Color &in); + + const QString& id() const + { + return id_; + } + + static QString GenerateID(ColorManager* config, const QString& input, const ColorTransform& dest_space); private: OCIO::ConstProcessorRcPtr processor_; + OCIO::ConstCPUProcessorRcPtr cpu_processor_; + + QString id_; + }; -using ColorProcessorChain = QList; +using ColorProcessorChain = QVector; -OLIVE_NAMESPACE_EXIT +} + +Q_DECLARE_METATYPE(olive::ColorProcessorPtr) #endif // COLORPROCESSOR_H diff --git a/app/render/backend/colorprocessorcache.h b/app/render/colorprocessorcache.h similarity index 92% rename from app/render/backend/colorprocessorcache.h rename to app/render/colorprocessorcache.h index 065fc4c06..9c9c40b6b 100644 --- a/app/render/backend/colorprocessorcache.h +++ b/app/render/colorprocessorcache.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,10 +24,10 @@ #include "project/item/footage/stream.h" #include "render/colorprocessor.h" -OLIVE_NAMESPACE_ENTER +namespace olive { using ColorProcessorCache = QHash; -OLIVE_NAMESPACE_EXIT +} #endif // COLORPROCESSORCACHE_H diff --git a/app/render/colortransform.h b/app/render/colortransform.h index cd183dda3..61a4c74ba 100644 --- a/app/render/colortransform.h +++ b/app/render/colortransform.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,14 +21,12 @@ #ifndef COLORTRANSFORM_H #define COLORTRANSFORM_H -#include -namespace OCIO = OCIO_NAMESPACE::v1; - #include #include "common/define.h" +#include "common/ocioutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ColorTransform { @@ -81,6 +79,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // COLORTRANSFORM_H diff --git a/app/render/diskmanager.cpp b/app/render/diskmanager.cpp index bd75bf077..40d385e76 100644 --- a/app/render/diskmanager.cpp +++ b/app/render/diskmanager.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -33,7 +33,7 @@ #include "core.h" #include "dialog/diskcache/diskcachedialog.h" -OLIVE_NAMESPACE_ENTER +namespace olive { DiskManager* DiskManager::instance_ = nullptr; @@ -364,4 +364,4 @@ void DiskCacheFolder::SaveDiskCacheIndex() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/render/diskmanager.h b/app/render/diskmanager.h index 9064a0d33..c4073d71f 100644 --- a/app/render/diskmanager.h +++ b/app/render/diskmanager.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,7 +29,7 @@ #include "common/define.h" #include "project/project.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class DiskCacheFolder : public QObject { @@ -165,6 +165,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // DISKMANAGER_H diff --git a/app/render/framehashcache.cpp b/app/render/framehashcache.cpp index 387baa12e..9328c58dd 100644 --- a/app/render/framehashcache.cpp +++ b/app/render/framehashcache.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -32,7 +32,7 @@ #include "common/timecodefunctions.h" #include "render/diskmanager.h" -OLIVE_NAMESPACE_ENTER +namespace olive { FrameHashCache::FrameHashCache(QObject *parent) : PlaybackCache(parent) @@ -50,22 +50,16 @@ QByteArray FrameHashCache::GetHash(const rational &time) void FrameHashCache::SetHash(const rational &time, const QByteArray &hash, const qint64& job_time, bool frame_exists) { - bool is_current = false; - for (int i=jobs_.size()-1; i>=0; i--) { const JobIdentifier& job = jobs_.at(i); if (job.range.Contains(time) - && job_time >= job.job_time) { - is_current = true; - break; + && job_time < job.job_time) { + // Hash here has changed since this frame started rendering, discard it + return; } } - if (!is_current) { - return; - } - time_hash_map_.insert(time, hash); TimeRange validated_range; @@ -82,15 +76,13 @@ void FrameHashCache::SetTimebase(const rational &tb) void FrameHashCache::ValidateFramesWithHash(const QByteArray &hash) { - QMap::const_iterator iterator; - const TimeRangeList& invalidated_ranges = GetInvalidatedRanges(); - for (iterator=time_hash_map_.begin();iterator!=time_hash_map_.end();iterator++) { + for (auto iterator=time_hash_map_.begin();iterator!=time_hash_map_.end();iterator++) { if (iterator.value() == hash) { TimeRange frame_range(iterator.key(), iterator.key() + timebase_); - if (invalidated_ranges.ContainsTimeRange(frame_range)) { + if (invalidated_ranges.contains(frame_range)) { Validate(frame_range); } } @@ -101,9 +93,7 @@ QList FrameHashCache::GetFramesWithHash(const QByteArray &hash) { QList times; - QMap::const_iterator iterator; - - for (iterator=time_hash_map_.begin();iterator!=time_hash_map_.end();iterator++) { + for (auto iterator=time_hash_map_.begin();iterator!=time_hash_map_.end();iterator++) { if (iterator.value() == hash) { times.append(iterator.key()); } @@ -116,7 +106,7 @@ QList FrameHashCache::TakeFramesWithHash(const QByteArray &hash) { QList times; - QMap::iterator iterator = time_hash_map_.begin(); + auto iterator = time_hash_map_.begin(); while (iterator != time_hash_map_.end()) { if (iterator.value() == hash) { @@ -167,7 +157,7 @@ QVector FrameHashCache::GetFrameListFromTimeRange(TimeRangeList range_ } times.append(snapped); - range_list.RemoveTimeRange(TimeRange(snapped, next)); + range_list.remove(TimeRange(snapped, next)); } return times; @@ -243,32 +233,27 @@ FramePtr FrameHashCache::LoadCacheFrame(const QString &fn) int height = dw.max.y - dw.min.y + 1; bool has_alpha = file.header().channels().findChannel("A"); - PixelFormat::Format image_format; + VideoParams::Format image_format; if (pix_type == Imf::HALF) { - if (has_alpha) { - image_format = PixelFormat::PIX_FMT_RGBA16F; - } else { - image_format = PixelFormat::PIX_FMT_RGB16F; - } + image_format = VideoParams::kFormatFloat16; } else { - if (has_alpha) { - image_format = PixelFormat::PIX_FMT_RGBA32F; - } else { - image_format = PixelFormat::PIX_FMT_RGB32F; - } + image_format = VideoParams::kFormatFloat32; } + int channel_count = has_alpha ? VideoParams::kRGBAChannelCount : VideoParams::kRGBChannelCount; + frame = Frame::Create(); frame->set_video_params(VideoParams(width, height, image_format, + channel_count, rational::fromDouble(file.header().pixelAspectRatio()))); frame->allocate(); - int bpc = PixelFormat::BytesPerChannel(image_format); + int bpc = VideoParams::GetBytesPerChannel(image_format); - size_t xs = PixelFormat::ChannelCount(image_format) * bpc; + size_t xs = channel_count * bpc; size_t ys = frame->linesize_bytes(); Imf::FrameBuffer framebuffer; @@ -289,7 +274,7 @@ FramePtr FrameHashCache::LoadCacheFrame(const QString &fn) void FrameHashCache::LengthChangedEvent(const rational &old, const rational &newlen) { if (newlen < old) { - QMap::iterator i = time_hash_map_.begin(); + auto i = time_hash_map_.begin(); while (i != time_hash_map_.end()) { if (i.key() >= newlen) { @@ -308,7 +293,7 @@ struct HashTimePair { void FrameHashCache::ShiftEvent(const rational &from, const rational &to) { - QMap::iterator i = time_hash_map_.begin(); + auto i = time_hash_map_.begin(); // POSITIVE if moving forward -> // NEGATIVE if moving backward <- @@ -359,10 +344,9 @@ void FrameHashCache::HashDeleted(const QString& s, const QByteArray &hash) } TimeRangeList ranges_to_invalidate; - QMap::const_iterator i; - for (i=time_hash_map_.constBegin(); i!=time_hash_map_.constEnd(); i++) { + for (auto i=time_hash_map_.constBegin(); i!=time_hash_map_.constEnd(); i++) { if (i.value() == hash) { - ranges_to_invalidate.InsertTimeRange(TimeRange(i.key(), i.key() + timebase_)); + ranges_to_invalidate.insert(TimeRange(i.key(), i.key() + timebase_)); } } @@ -406,13 +390,15 @@ QString FrameHashCache::CachePathName(const QString &cache_path, const QByteArra bool FrameHashCache::SaveCacheFrame(const QString &filename, char *data, const VideoParams &vparam, int linesize_bytes) const { - Q_ASSERT(PixelFormat::FormatIsFloat(vparam.format())); + if (!VideoParams::FormatIsFloat(vparam.format())) { + qCritical() << "Tried to cache frame with non-float pixel format"; + return false; + } // Floating point types are stored in EXR Imf::PixelType pix_type; - if (vparam.format() == PixelFormat::PIX_FMT_RGB16F - || vparam.format() == PixelFormat::PIX_FMT_RGBA16F) { + if (vparam.format() == VideoParams::kFormatFloat16) { pix_type = Imf::HALF; } else { pix_type = Imf::FLOAT; @@ -423,7 +409,7 @@ bool FrameHashCache::SaveCacheFrame(const QString &filename, char *data, const V header.channels().insert("R", Imf::Channel(pix_type)); header.channels().insert("G", Imf::Channel(pix_type)); header.channels().insert("B", Imf::Channel(pix_type)); - if (PixelFormat::FormatHasAlphaChannel(vparam.format())) { + if (vparam.channel_count() == VideoParams::kRGBAChannelCount) { header.channels().insert("A", Imf::Channel(pix_type)); } @@ -433,16 +419,16 @@ bool FrameHashCache::SaveCacheFrame(const QString &filename, char *data, const V Imf::OutputFile out(filename.toUtf8(), header, 0); - int bpc = PixelFormat::BytesPerChannel(vparam.format()); + int bpc = VideoParams::GetBytesPerChannel(vparam.format()); - size_t xs = PixelFormat::ChannelCount(vparam.format()) * bpc; + size_t xs = vparam.channel_count() * bpc; size_t ys = linesize_bytes; Imf::FrameBuffer framebuffer; framebuffer.insert("R", Imf::Slice(pix_type, data, xs, ys)); framebuffer.insert("G", Imf::Slice(pix_type, data + bpc, xs, ys)); framebuffer.insert("B", Imf::Slice(pix_type, data + 2*bpc, xs, ys)); - if (PixelFormat::FormatHasAlphaChannel(vparam.format())) { + if (vparam.channel_count() == VideoParams::kRGBAChannelCount) { framebuffer.insert("A", Imf::Slice(pix_type, data + 3*bpc, xs, ys)); } out.setFrameBuffer(framebuffer); @@ -452,4 +438,4 @@ bool FrameHashCache::SaveCacheFrame(const QString &filename, char *data, const V return true; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/render/framehashcache.h b/app/render/framehashcache.h index 1d8360043..3ff6eb9b7 100644 --- a/app/render/framehashcache.h +++ b/app/render/framehashcache.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,11 +25,11 @@ #include "common/rational.h" #include "common/timerange.h" -#include "render/pixelformat.h" +#include "codec/frame.h" #include "render/playbackcache.h" #include "render/videoparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class FrameHashCache : public PlaybackCache { @@ -76,7 +76,7 @@ public: QVector GetInvalidatedFrames(const TimeRange& intersecting); public slots: - void SetHash(const OLIVE_NAMESPACE::rational& time, const QByteArray& hash, const qint64 &job_time, bool frame_exists); + void SetHash(const olive::rational& time, const QByteArray& hash, const qint64 &job_time, bool frame_exists); protected: virtual void LengthChangedEvent(const rational& old, const rational& newlen) override; @@ -97,6 +97,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // VIDEORENDERFRAMECACHE_H diff --git a/app/render/job/CMakeLists.txt b/app/render/job/CMakeLists.txt new file mode 100644 index 000000000..1a3d982ca --- /dev/null +++ b/app/render/job/CMakeLists.txt @@ -0,0 +1,24 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2020 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 . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + render/job/acceleratedjob.h + render/job/generatejob.h + render/job/samplejob.h + render/job/shaderjob.h + PARENT_SCOPE +) diff --git a/app/render/job/acceleratedjob.h b/app/render/job/acceleratedjob.h new file mode 100644 index 000000000..e4b981e21 --- /dev/null +++ b/app/render/job/acceleratedjob.h @@ -0,0 +1,101 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 ACCELERATEDJOB_H +#define ACCELERATEDJOB_H + +#include "node/input.h" +#include "node/inputarray.h" +#include "render/shadervalue.h" +#include "node/value.h" + +namespace olive { + +class AcceleratedJob { +public: + AcceleratedJob() = default; + + ShaderValue GetValue(NodeInput* input) const + { + return value_map_.value(input->id()); + } + + ShaderValue GetValue(const QString& input) const + { + return value_map_.value(input); + } + + void InsertValue(NodeInput* input, NodeValueDatabase& value) + { + ShaderValue shader_val; + + shader_val.type = input->data_type(); + shader_val.array = input->IsArray(); + + if (input->IsArray()) { + NodeInputArray* array = static_cast(input); + QVector values(array->GetSize()); + + for (int j=0;jGetSize();j++) { + NodeInput* subparam = array->At(j); + + values[j] = value[subparam].Take(subparam->data_type()); + } + + shader_val.data = QVariant::fromValue(values); + } else { + NodeValue node_val = value[input].TakeWithMeta(input->data_type()); + shader_val.data = node_val.data(); + shader_val.tag = node_val.tag(); + } + + InsertValue(input->id(), shader_val); + } + + void InsertValue(const QString& input, const ShaderValue& value) + { + value_map_.insert(input, value); + } + + void InsertValue(NodeInput* input, const ShaderValue& value) + { + value_map_.insert(input->id(), value); + } + + void InsertValue(NodeInput* input, const NodeValue& value) + { + ShaderValue s(value.data(), value.type()); + s.tag = value.tag(); + value_map_.insert(input->id(), s); + } + + const NodeValueMap &GetValues() const + { + return value_map_; + } + +private: + NodeValueMap value_map_; + +}; + +} + +#endif // ACCELERATEDJOB_H diff --git a/app/render/job/generatejob.h b/app/render/job/generatejob.h new file mode 100644 index 000000000..dc71a873f --- /dev/null +++ b/app/render/job/generatejob.h @@ -0,0 +1,54 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 GENERATEJOB_H +#define GENERATEJOB_H + +#include "acceleratedjob.h" + +namespace olive { + +class GenerateJob : public AcceleratedJob { +public: + GenerateJob() + { + alpha_channel_required_ = false; + } + + bool GetAlphaChannelRequired() const + { + return alpha_channel_required_; + } + + void SetAlphaChannelRequired(bool e) + { + alpha_channel_required_ = e; + } + +private: + bool alpha_channel_required_; + +}; + +} + +Q_DECLARE_METATYPE(olive::GenerateJob) + +#endif // GENERATEJOB_H diff --git a/app/render/job/samplejob.h b/app/render/job/samplejob.h new file mode 100644 index 000000000..80cf5657e --- /dev/null +++ b/app/render/job/samplejob.h @@ -0,0 +1,65 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 SAMPLEJOB_H +#define SAMPLEJOB_H + +#include "acceleratedjob.h" +#include "codec/samplebuffer.h" + +namespace olive { + +class SampleJob : public AcceleratedJob { +public: + SampleJob() + { + samples_ = nullptr; + } + + SampleJob(const NodeValue& value) + { + samples_ = value.data().value(); + } + + SampleJob(NodeInput* from, NodeValueDatabase& db) + { + samples_ = db[from].Take(NodeParam::kSamples).value(); + } + + SampleBufferPtr samples() const + { + return samples_; + } + + bool HasSamples() const + { + return samples_ && samples_->is_allocated(); + } + +private: + SampleBufferPtr samples_; + +}; + +} + +Q_DECLARE_METATYPE(olive::SampleJob) + +#endif // SAMPLEJOB_H diff --git a/app/render/job/shaderjob.h b/app/render/job/shaderjob.h new file mode 100644 index 000000000..64848c563 --- /dev/null +++ b/app/render/job/shaderjob.h @@ -0,0 +1,100 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 SHADERJOB_H +#define SHADERJOB_H + +#include + +#include "generatejob.h" +#include "render/texture.h" + +namespace olive { + +class ShaderJob : public GenerateJob { +public: + ShaderJob() + { + iterations_ = 1; + iterative_input_ = nullptr; + } + + const QString& GetShaderID() const + { + return shader_id_; + } + + void SetShaderID(const QString& id) + { + shader_id_ = id; + } + + void SetIterations(int iterations, NodeInput* iterative_input) + { + SetIterations(iterations, iterative_input->id()); + } + + void SetIterations(int iterations, const QString& iterative_input) + { + iterations_ = iterations; + iterative_input_ = iterative_input; + } + + int GetIterationCount() const + { + return iterations_; + } + + const QString& GetIterativeInput() const + { + return iterative_input_; + } + + Texture::Interpolation GetInterpolation(const QString& id) const + { + return interpolation_.value(id, Texture::kDefaultInterpolation); + } + + void SetInterpolation(NodeInput* input, Texture::Interpolation interp) + { + interpolation_.insert(input->id(), interp); + } + + void SetInterpolation(const QString& id, Texture::Interpolation interp) + { + interpolation_.insert(id, interp); + } + +private: + QString shader_id_; + + int iterations_; + + QString iterative_input_; + + QHash interpolation_; + +}; + +} + +Q_DECLARE_METATYPE(olive::ShaderJob) + +#endif // SHADERJOB_H diff --git a/app/render/managedcolor.cpp b/app/render/managedcolor.cpp index f4d86e197..e12e02dc9 100644 --- a/app/render/managedcolor.cpp +++ b/app/render/managedcolor.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,19 +20,19 @@ #include "managedcolor.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ManagedColor::ManagedColor() { } -ManagedColor::ManagedColor(const float &r, const float &g, const float &b, const float &a) : +ManagedColor::ManagedColor(const double &r, const double &g, const double &b, const double &a) : Color(r, g, b, a) { } -ManagedColor::ManagedColor(const char *data, const PixelFormat::Format &format) : - Color(data, format) +ManagedColor::ManagedColor(const char *data, const VideoParams::Format &format, int channel_layout) : + Color(data, format, channel_layout) { } @@ -61,4 +61,4 @@ void ManagedColor::set_color_output(const ColorTransform &color_output) color_transform_ = color_output; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/render/managedcolor.h b/app/render/managedcolor.h index c214f57b4..19a475a9a 100644 --- a/app/render/managedcolor.h +++ b/app/render/managedcolor.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,14 +24,14 @@ #include "color.h" #include "colortransform.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ManagedColor : public Color { public: ManagedColor(); - ManagedColor(const float& r, const float& g, const float& b, const float& a = 1.0f); - ManagedColor(const char *data, const PixelFormat::Format &format); + ManagedColor(const double& r, const double& g, const double& b, const double& a = 1.0); + ManagedColor(const char *data, const VideoParams::Format &format, int channel_layout); ManagedColor(const Color& c); const QString& color_input() const; @@ -47,6 +47,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // MANAGEDCOLOR_H diff --git a/app/render/ocioconf/CMakeLists.txt b/app/render/ocioconf/CMakeLists.txt index faa7b5e40..f325b2773 100644 --- a/app/render/ocioconf/CMakeLists.txt +++ b/app/render/ocioconf/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/node/input/media/video/CMakeLists.txt b/app/render/opengl/CMakeLists.txt similarity index 87% rename from app/node/input/media/video/CMakeLists.txt rename to app/render/opengl/CMakeLists.txt index f37e07c36..9bed6c499 100644 --- a/app/node/input/media/video/CMakeLists.txt +++ b/app/render/opengl/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -16,7 +16,7 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} - node/input/media/video/video.h - node/input/media/video/video.cpp + render/opengl/openglrenderer.cpp + render/opengl/openglrenderer.h PARENT_SCOPE ) diff --git a/app/render/opengl/openglrenderer.cpp b/app/render/opengl/openglrenderer.cpp new file mode 100644 index 000000000..a92bb10f2 --- /dev/null +++ b/app/render/opengl/openglrenderer.cpp @@ -0,0 +1,715 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 "openglrenderer.h" + +#include +#include + +namespace olive { + +const QVector blit_vertices = { + -1.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + + -1.0f, -1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 0.0f +}; + +const QVector blit_texcoords = { + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + + 0.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f +}; + +class ErrorPrinter { +public: + ErrorPrinter(const char* name, QOpenGLFunctions* f) + { + GLuint err = f->glGetError(); + if (err > 0) + qDebug() << name << "entered with" << err; + + name_ = name; + functions_ = f; + } + + ~ErrorPrinter() + { + GLuint err = functions_->glGetError(); + if (err > 0) + qDebug() << name_ << "exited with" << err; + } + +private: + const char* name_; + + QOpenGLFunctions* functions_; + +}; + +#define PRINT_GL_ERRORS ErrorPrinter __e(__FUNCTION__, functions_) + +OpenGLRenderer::OpenGLRenderer(QObject* parent) : + Renderer(parent), + context_(nullptr) +{ +} + +OpenGLRenderer::~OpenGLRenderer() +{ + Destroy(); + PostDestroy(); +} + +void OpenGLRenderer::Init(QOpenGLContext *existing_ctx) +{ + if (context_) { + qCritical() << "Can't initialize already initialized OpenGLRenderer"; + return; + } + + context_ = existing_ctx; +} + +bool OpenGLRenderer::Init() +{ + if (context_) { + qCritical() << "Can't initialize already initialized OpenGLRenderer"; + return false; + } + + surface_.create(); + + context_ = new QOpenGLContext(this); + if (!context_->create()) { + qCritical() << "Failed to create OpenGL context"; + return false; + } + + context_->moveToThread(this->thread()); + + return true; +} + +void OpenGLRenderer::PostDestroy() +{ + // Destroy surface if we created it + if (surface_.isValid()) { + surface_.destroy(); + } +} + +void OpenGLRenderer::PostInit() +{ + // Make context current on that surface + if (context_->parent() == this && !context_->makeCurrent(&surface_)) { + qCritical() << "Failed to makeCurrent() on offscreen surface in thread" << thread(); + return; + } + + functions_ = context_->functions(); + + // Store OpenGL functions instance + functions_->glBlendFunc(GL_ONE, GL_ZERO); + + // Set up framebuffer used for various things + functions_->glGenFramebuffers(1, &framebuffer_); +} + +void OpenGLRenderer::DestroyInternal() +{ + if (context_) { + // Delete framebuffer + functions_->glDeleteFramebuffers(1, &framebuffer_); + + // Delete context if it belongs to us + if (context_->parent() == this) { + delete context_; + } + context_ = nullptr; + } +} + +void OpenGLRenderer::ClearDestination(double r, double g, double b, double a) +{ + functions_->glClearColor(r, g, b, a); + functions_->glClear(GL_COLOR_BUFFER_BIT); +} + +QVariant OpenGLRenderer::CreateNativeTexture2D(int width, int height, VideoParams::Format format, int channel_count, const void *data, int linesize) +{ + + GLuint texture; + functions_->glGenTextures(1, &texture); + + functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize); + + GLint current_tex; + functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_tex); + + functions_->glBindTexture(GL_TEXTURE_2D, texture); + + { + + PRINT_GL_ERRORS; + functions_->glTexImage2D(GL_TEXTURE_2D, 0, GetInternalFormat(format, channel_count), + width, height, 0, GetPixelFormat(channel_count), + GetPixelType(format), data); + } + + functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + functions_->glBindTexture(GL_TEXTURE_2D, current_tex); + + return texture; +} + +QVariant OpenGLRenderer::CreateNativeTexture3D(int width, int height, int depth, VideoParams::Format format, int channel_count, const void *data, int linesize) +{ + PRINT_GL_ERRORS; + + GLuint texture; + functions_->glGenTextures(1, &texture); + + functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize); + + GLint current_tex; + functions_->glGetIntegerv(GL_TEXTURE_BINDING_3D, ¤t_tex); + + functions_->glBindTexture(GL_TEXTURE_3D, texture); + + context_->extraFunctions()->glTexImage3D(GL_TEXTURE_3D, 0, GetInternalFormat(format, channel_count), + width, height, depth, 0, GetPixelFormat(channel_count), + GetPixelType(format), data); + + functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + functions_->glBindTexture(GL_TEXTURE_3D, current_tex); + + return texture; +} + +void OpenGLRenderer::AttachTextureAsDestination(Texture* texture) +{ + PRINT_GL_ERRORS; + + functions_->glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_); + functions_->glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + texture->id().value(), + 0); +} + +void OpenGLRenderer::DetachTextureAsDestination() +{ + functions_->glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void OpenGLRenderer::DestroyNativeTexture(QVariant texture) +{ + GLuint t = texture.value(); + functions_->glDeleteTextures(1, &t); +} + +QVariant OpenGLRenderer::CreateNativeShader(ShaderCode code) +{ + PRINT_GL_ERRORS; + + QOpenGLShaderProgram* program = new QOpenGLShaderProgram(context_); + + QString vert_code = code.vert_code(); + QString frag_code = code.frag_code(); + + QString shader_preamble; + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) { + shader_preamble = QStringLiteral("#version 300 es\n" + "\n" + "precision highp int;\n" + "precision highp float;\n" + "\n"); + } else { + shader_preamble = QStringLiteral("#version 150\n" + "\n"); + } + + vert_code.prepend(shader_preamble); + frag_code.prepend(shader_preamble); + + if (!program->addShaderFromSourceCode(QOpenGLShader::Vertex, vert_code)) { + qCritical() << "Failed to add vertex code to shader"; + goto error; + } + + if (!program->addShaderFromSourceCode(QOpenGLShader::Fragment, frag_code)) { + qCritical() << "Failed to add fragment code to shader"; + goto error; + } + + if (!program->link()) { + qCritical() << "Failed to link shader"; + goto error; + } + + return Node::PtrToValue(program); + +error: + delete program; + return QVariant(); +} + +void OpenGLRenderer::DestroyNativeShader(QVariant shader) +{ + delete Node::ValueToPtr(shader); +} + +void OpenGLRenderer::UploadToTexture(Texture *texture, const void *data, int linesize) +{ + PRINT_GL_ERRORS; + + GLuint t = texture->id().value(); + const VideoParams& p = texture->params(); + + // Store currently bound texture so it can be restored later + GLint current_tex; + functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_tex); + + functions_->glBindTexture(GL_TEXTURE_2D, t); + + functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize); + + functions_->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, + p.effective_width(), p.effective_height(), + GetPixelFormat(p.channel_count()), GetPixelType(p.format()), + data); + + functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + functions_->glBindTexture(GL_TEXTURE_2D, current_tex); +} + +void OpenGLRenderer::DownloadFromTexture(Texture* texture, void *data, int linesize) +{ + const VideoParams& p = texture->params(); + + GLint current_tex; + functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_tex); + + AttachTextureAsDestination(texture); + + functions_->glPixelStorei(GL_PACK_ROW_LENGTH, linesize); + + { + PRINT_GL_ERRORS; + functions_->glReadPixels(0, + 0, + p.width(), + p.height(), + (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) ? GL_RGBA : GetPixelFormat(p.channel_count()), + GetPixelType(p.format()), + data); + } + + functions_->glPixelStorei(GL_PACK_ROW_LENGTH, 0); + + DetachTextureAsDestination(); + + functions_->glBindTexture(GL_TEXTURE_2D, current_tex); +} + +struct TextureToBind { + TexturePtr texture; + Texture::Interpolation interpolation; +}; + +void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, VideoParams destination_params, bool clear_destination) +{ + // If this node is iterative, we'll pick up which input here + QString iterative_name; + GLuint iterative_input = 0; + QVector textures_to_bind; + + QOpenGLShaderProgram* shader = Node::ValueToPtr(s); + + shader->bind(); + + NodeValueMap::const_iterator it; + for (it=job.GetValues().constBegin(); it!=job.GetValues().constEnd(); it++) { + // See if the shader has takes this parameter as an input + int variable_location = shader->uniformLocation(it.key()); + + if (variable_location == -1) { + continue; + } + + // This variable is used in the shader, let's set it + const ShaderValue& value = it.value(); + + if (value.array) { + qWarning() << "FIXME: Array support is currently a stub"; + } + + switch (value.type) { + case NodeInput::kInt: + // kInt technically specifies a LongLong, but OpenGL doesn't support those. This may lead to + // over/underflows if the number is large enough, but the likelihood of that is quite low. + shader->setUniformValue(variable_location, value.data.toInt()); + break; + case NodeInput::kFloat: + // kFloat technically specifies a double but as above, OpenGL doesn't support those. + shader->setUniformValue(variable_location, value.data.toFloat()); + break; + case NodeInput::kVec2: + shader->setUniformValue(variable_location, value.data.value()); + break; + case NodeInput::kVec3: + shader->setUniformValue(variable_location, value.data.value()); + break; + case NodeInput::kVec4: + shader->setUniformValue(variable_location, value.data.value()); + break; + case NodeInput::kMatrix: + shader->setUniformValue(variable_location, value.data.value()); + break; + case NodeInput::kCombo: + shader->setUniformValue(variable_location, value.data.value()); + break; + case NodeInput::kColor: + { + Color color = value.data.value(); + shader->setUniformValue(variable_location, + color.red(), color.green(), color.blue(), color.alpha()); + break; + } + case NodeInput::kBoolean: + shader->setUniformValue(variable_location, value.data.toBool()); + break; + case NodeInput::kBuffer: + case NodeInput::kTexture: + { + TexturePtr texture = value.data.value(); + + // Set value to bound texture + shader->setUniformValue(variable_location, textures_to_bind.size()); + + // If this texture binding is the iterative input, set it here + if (it.key() == job.GetIterativeInput()) { + iterative_input = textures_to_bind.size(); + iterative_name = it.key(); + } + + textures_to_bind.append({texture, job.GetInterpolation(it.key())}); + + // Set enable flag if shader wants it + GLuint tex_id = texture ? texture->id().value() : 0; + int enable_param_location = shader->uniformLocation(QStringLiteral("%1_enabled").arg(it.key())); + if (enable_param_location > -1) { + shader->setUniformValue(enable_param_location, + tex_id > 0); + } + break; + } + case NodeInput::kSamples: + case NodeInput::kText: + case NodeInput::kRational: + case NodeInput::kFont: + case NodeInput::kFile: + case NodeInput::kDecimal: + case NodeInput::kNumber: + case NodeInput::kString: + case NodeInput::kVector: + case NodeInput::kShaderJob: + case NodeInput::kSampleJob: + case NodeInput::kGenerateJob: + case NodeInput::kFootage: + case NodeInput::kNone: + case NodeInput::kAny: + break; + } + } + + // Bind all textures + for (int i=0; iid().value() : 0; + + functions_->glActiveTexture(GL_TEXTURE0 + i); + + GLenum target = (texture && texture->type() == Texture::k3D) ? GL_TEXTURE_3D : GL_TEXTURE_2D; + functions_->glBindTexture(target, tex_id); + + PrepareInputTexture(target, t.interpolation); + } + + // Ensure matrix is set, at least to identity + shader->setUniformValue("ove_mvpmat", + job.GetValue(QStringLiteral("ove_mvpmat")).data.value()); + + // Set the viewport to the "physical" resolution of the destination + functions_->glViewport(0, 0, + destination_params.effective_width(), + destination_params.effective_height()); + + // Bind vertex array object + QOpenGLVertexArrayObject vao_; + vao_.create(); + vao_.bind(); + + // Set buffers + QOpenGLBuffer vert_vbo_; + vert_vbo_.create(); + vert_vbo_.bind(); + vert_vbo_.allocate(blit_vertices.constData(), blit_vertices.size() * sizeof(GLfloat)); + vert_vbo_.release(); + + QOpenGLBuffer frag_vbo_; + frag_vbo_.create(); + frag_vbo_.bind(); + frag_vbo_.allocate(blit_texcoords.constData(), blit_texcoords.size() * sizeof(GLfloat)); + frag_vbo_.release(); + + int vertex_location = shader->attributeLocation("a_position"); + vert_vbo_.bind(); + functions_->glEnableVertexAttribArray(vertex_location); + functions_->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + vert_vbo_.release(); + + int tex_location = shader->attributeLocation("a_texcoord"); + frag_vbo_.bind(); + functions_->glEnableVertexAttribArray(tex_location); + functions_->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + frag_vbo_.release(); + + // Some shaders optimize through multiple iterations which requires ping-ponging textures + // - If there are only two iterations, we can just create one backend texture and then the + // destination can be the second + // - If there are more than two iterations, we need to ping pong back and forth between two + // textures. We can still use the destination as the last iteration, but we'll need textures + // for the iterative process. + int real_iteration_count; + if (job.GetIterationCount() > 1 && !job.GetIterativeInput().isEmpty()) { + real_iteration_count = job.GetIterationCount(); + } else { + real_iteration_count = 1; + } + + TexturePtr output_tex, input_tex; + if (real_iteration_count > 1) { + // Create one texture to bounce off + output_tex = CreateTexture(destination_params); + + if (real_iteration_count > 2) { + // Create a second texture bounce off + input_tex = CreateTexture(destination_params); + } + } + + for (int iteration=0; iterationsetUniformValue("ove_iteration", iteration); + + // Replace iterative input + if (iteration == real_iteration_count-1) { + // This is the last iteration, draw to the destination + if (destination) { + // If we have a destination texture, draw to it + AttachTextureAsDestination(destination); + } else if (iteration > 0) { + // Otherwise, if we were iterating before, detach texture now + DetachTextureAsDestination(); + } + + // Clear the destination if the caller requested it + if (clear_destination) { + ClearDestination(); + } + } else { + // Always draw to output_tex, which gets swapped with input_tex every iteration + AttachTextureAsDestination(output_tex.get()); + } + + if (iteration > 0) { + // If this is not the first iteration, replace the iterative texture with the one we + // last drew + functions_->glActiveTexture(GL_TEXTURE0 + iterative_input); + functions_->glBindTexture(GL_TEXTURE_2D, input_tex->id().value()); + + // At this time, we only support iterating 2D textures + PrepareInputTexture(GL_TEXTURE_2D, job.GetInterpolation(iterative_name)); + } + + // Swap so that the next iteration, the texture we draw now will be the input texture next + std::swap(output_tex, input_tex); + + // Blit this texture through this shader + { + PRINT_GL_ERRORS; + functions_->glDrawArrays(GL_TRIANGLES, 0, blit_vertices.size() / 3); + } + } + + if (destination) { + // Reset framebuffer to default if we were drawing to a texture + DetachTextureAsDestination(); + } + + // Release any textures we bound before + for (int i=textures_to_bind.size()-1; i>=0; i--) { + TexturePtr texture = textures_to_bind.at(i).texture; + GLenum target = (texture && texture->type() == Texture::k3D) ? GL_TEXTURE_3D : GL_TEXTURE_2D; + functions_->glActiveTexture(GL_TEXTURE0 + i); + functions_->glBindTexture(target, 0); + } + + // Release shader + shader->release(); + + // Release vertex array object + frag_vbo_.destroy(); + vert_vbo_.destroy(); + vao_.release(); + vao_.destroy(); +} + +GLint OpenGLRenderer::GetInternalFormat(VideoParams::Format format, int channel_layout) +{ + switch (format) { + case VideoParams::kFormatUnsigned8: + switch (channel_layout) { + case 1: + return GL_R8; + case 2: + return GL_RG8; + case 3: + return GL_RGB8; + case 4: + return GL_RGBA8; + } + break; + case VideoParams::kFormatUnsigned16: + switch (channel_layout) { + case 1: + return GL_R16; + case 2: + return GL_RG16; + case 3: + return GL_RGB16; + case 4: + return GL_RGBA16; + } + break; + case VideoParams::kFormatFloat16: + switch (channel_layout) { + case 1: + return GL_R16F; + case 2: + return GL_RG16F; + case 3: + return GL_RGB16F; + case 4: + return GL_RGBA16F; + } + break; + case VideoParams::kFormatFloat32: + switch (channel_layout) { + case 1: + return GL_R32F; + case 2: + return GL_RG32F; + case 3: + return GL_RGB32F; + case 4: + return GL_RGBA32F; + } + break; + case VideoParams::kFormatInvalid: + case VideoParams::kFormatCount: + break; + } + + return GL_INVALID_VALUE; +} + +GLenum OpenGLRenderer::GetPixelType(VideoParams::Format format) +{ + switch (format) { + case VideoParams::kFormatUnsigned8: + return GL_UNSIGNED_BYTE; + case VideoParams::kFormatUnsigned16: + return GL_UNSIGNED_SHORT; + case VideoParams::kFormatFloat16: + return GL_HALF_FLOAT; + case VideoParams::kFormatFloat32: + return GL_FLOAT; + + case VideoParams::kFormatInvalid: + case VideoParams::kFormatCount: + break; + } + + return GL_INVALID_VALUE; +} + +GLenum OpenGLRenderer::GetPixelFormat(int channel_count) +{ + switch (channel_count) { + case 1: + return GL_RED; + case 3: + return GL_RGB; + case 4: + return GL_RGBA; + default: + return GL_INVALID_VALUE; + } +} + +void OpenGLRenderer::PrepareInputTexture(GLenum target, Texture::Interpolation interp) +{ + switch (interp) { + case Texture::kNearest: + functions_->glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + functions_->glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + case Texture::kLinear: + functions_->glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + functions_->glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + case Texture::kMipmappedLinear: + functions_->glGenerateMipmap(target); + functions_->glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + functions_->glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + } + + functions_->glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + functions_->glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +} diff --git a/app/render/opengl/openglrenderer.h b/app/render/opengl/openglrenderer.h new file mode 100644 index 000000000..49aa07252 --- /dev/null +++ b/app/render/opengl/openglrenderer.h @@ -0,0 +1,101 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 OPENGLCONTEXT_H +#define OPENGLCONTEXT_H + +#include +#include +#include +#include +#include +#include + +#include "render/renderer.h" + +namespace olive { + +class OpenGLRenderer : public Renderer +{ + Q_OBJECT +public: + OpenGLRenderer(QObject* parent = nullptr); + + virtual ~OpenGLRenderer() override; + + void Init(QOpenGLContext* existing_ctx); + + virtual bool Init() override; + + virtual void PostDestroy() override; + +public slots: + virtual void PostInit() override; + + virtual void DestroyInternal() override; + + virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override; + + virtual QVariant CreateNativeTexture2D(int width, int height, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override; + virtual QVariant CreateNativeTexture3D(int width, int height, int depth, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override; + + virtual void DestroyNativeTexture(QVariant texture) override; + + virtual QVariant CreateNativeShader(olive::ShaderCode code) override; + + virtual void DestroyNativeShader(QVariant shader) override; + + virtual void UploadToTexture(olive::Texture* texture, const void* data, int linesize) override; + + virtual void DownloadFromTexture(olive::Texture* texture, void* data, int linesize) override; + +protected slots: + virtual void Blit(QVariant shader, + olive::ShaderJob job, + olive::Texture* destination, + olive::VideoParams destination_params, + bool clear_destination) override; + +private: + static GLint GetInternalFormat(VideoParams::Format format, int channel_layout); + + static GLenum GetPixelType(VideoParams::Format format); + + static GLenum GetPixelFormat(int channel_count); + + void AttachTextureAsDestination(olive::Texture* texture); + + void DetachTextureAsDestination(); + + void PrepareInputTexture(GLenum target, Texture::Interpolation interp); + + QOpenGLContext* context_; + + QOpenGLFunctions* functions_; + + QOffscreenSurface surface_; + + GLuint framebuffer_; + +}; + +} + +#endif // OPENGLCONTEXT_H diff --git a/app/render/pixelformat.cpp b/app/render/pixelformat.cpp deleted file mode 100644 index 01abf0aff..000000000 --- a/app/render/pixelformat.cpp +++ /dev/null @@ -1,298 +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 "pixelformat.h" - -#include "OpenImageIO/imagebuf.h" -#include -#include -#include - -#include "codec/oiio/oiiodecoder.h" -#include "common/define.h" -#include "core.h" - -OLIVE_NAMESPACE_ENTER - -bool PixelFormat::FormatHasAlphaChannel(const PixelFormat::Format &format) -{ - switch (format) { - case PixelFormat::PIX_FMT_RGBA8: - case PixelFormat::PIX_FMT_RGBA16U: - case PixelFormat::PIX_FMT_RGBA16F: - case PixelFormat::PIX_FMT_RGBA32F: - return true; - case PixelFormat::PIX_FMT_RGB8: - case PixelFormat::PIX_FMT_RGB16U: - case PixelFormat::PIX_FMT_RGB16F: - case PixelFormat::PIX_FMT_RGB32F: - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - return false; -} - -bool PixelFormat::FormatIsFloat(const PixelFormat::Format &format) -{ - switch (format) { - case PixelFormat::PIX_FMT_RGB16F: - case PixelFormat::PIX_FMT_RGBA16F: - case PixelFormat::PIX_FMT_RGB32F: - case PixelFormat::PIX_FMT_RGBA32F: - return true; - - case PixelFormat::PIX_FMT_RGB8: - case PixelFormat::PIX_FMT_RGBA8: - case PixelFormat::PIX_FMT_RGB16U: - case PixelFormat::PIX_FMT_RGBA16U: - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - return false; -} - -OIIO::TypeDesc::BASETYPE PixelFormat::GetOIIOTypeDesc(const PixelFormat::Format &format) -{ - switch (format) { - case PixelFormat::PIX_FMT_RGB8: - case PixelFormat::PIX_FMT_RGBA8: - return OIIO::TypeDesc::UINT8; - case PixelFormat::PIX_FMT_RGB16U: - case PixelFormat::PIX_FMT_RGBA16U: - return OIIO::TypeDesc::UINT16; - case PixelFormat::PIX_FMT_RGB16F: - case PixelFormat::PIX_FMT_RGBA16F: - return OIIO::TypeDesc::HALF; - case PixelFormat::PIX_FMT_RGB32F: - case PixelFormat::PIX_FMT_RGBA32F: - return OIIO::TypeDesc::FLOAT; - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - return OIIO::TypeDesc::UNKNOWN; -} - -QString PixelFormat::GetName(const PixelFormat::Format &format) -{ - switch (format) { - case PixelFormat::PIX_FMT_RGB8: - case PixelFormat::PIX_FMT_RGBA8: - return tr("8-bit"); - case PixelFormat::PIX_FMT_RGB16U: - case PixelFormat::PIX_FMT_RGBA16U: - return tr("16-bit Integer"); - case PixelFormat::PIX_FMT_RGB16F: - case PixelFormat::PIX_FMT_RGBA16F: - return tr("Half-Float (16-bit)"); - case PixelFormat::PIX_FMT_RGB32F: - case PixelFormat::PIX_FMT_RGBA32F: - return tr("Full-Float (32-bit)"); - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - return tr("Unknown (%1)").arg(format); -} - -PixelFormat* PixelFormat::instance_ = nullptr; - -void PixelFormat::CreateInstance() -{ - instance_ = new PixelFormat(); -} - -void PixelFormat::DestroyInstance() -{ - delete instance_; -} - -PixelFormat *PixelFormat::instance() -{ - return instance_; -} - -PixelFormat::Format PixelFormat::GetConfiguredFormatForMode(RenderMode::Mode mode) -{ - return static_cast(Core::GetPreferenceForRenderMode(mode, QStringLiteral("PixelFormat")).toInt()); -} - -void PixelFormat::SetConfiguredFormatForMode(RenderMode::Mode mode, PixelFormat::Format format) -{ - if (format != GetConfiguredFormatForMode(mode)) { - Core::SetPreferenceForRenderMode(mode, QStringLiteral("PixelFormat"), format); - - emit FormatChanged(); - } -} - -PixelFormat::Format PixelFormat::OIIOFormatToOliveFormat(OIIO::TypeDesc desc, bool has_alpha) -{ - if (desc == OIIO::TypeDesc::UINT8) { - return has_alpha ? PixelFormat::PIX_FMT_RGBA8 : PixelFormat::PIX_FMT_RGB8; - } else if (desc == OIIO::TypeDesc::UINT16) { - return has_alpha ? PixelFormat::PIX_FMT_RGBA16U : PixelFormat::PIX_FMT_RGB16U; - } else if (desc == OIIO::TypeDesc::HALF) { - return has_alpha ? PixelFormat::PIX_FMT_RGBA16F : PixelFormat::PIX_FMT_RGB16F; - } else if (desc == OIIO::TypeDesc::FLOAT) { - return has_alpha ? PixelFormat::PIX_FMT_RGBA32F : PixelFormat::PIX_FMT_RGB32F; - } - - return PixelFormat::PIX_FMT_INVALID; -} - -PixelFormat::Format PixelFormat::GetFormatWithAlphaChannel(PixelFormat::Format f) -{ - switch (f) { - case PIX_FMT_INVALID: - case PIX_FMT_COUNT: - break; - case PIX_FMT_RGB8: - case PIX_FMT_RGBA8: - return PIX_FMT_RGBA8; - case PIX_FMT_RGB16U: - case PIX_FMT_RGBA16U: - return PIX_FMT_RGBA16U; - case PIX_FMT_RGB16F: - case PIX_FMT_RGBA16F: - return PIX_FMT_RGBA16F; - case PIX_FMT_RGB32F: - case PIX_FMT_RGBA32F: - return PIX_FMT_RGBA32F; - } - - return PIX_FMT_INVALID; -} - -PixelFormat::Format PixelFormat::GetFormatWithoutAlphaChannel(PixelFormat::Format f) -{ - switch (f) { - case PIX_FMT_INVALID: - case PIX_FMT_COUNT: - break; - case PIX_FMT_RGB8: - case PIX_FMT_RGBA8: - return PIX_FMT_RGB8; - case PIX_FMT_RGB16U: - case PIX_FMT_RGBA16U: - return PIX_FMT_RGB16U; - case PIX_FMT_RGB16F: - case PIX_FMT_RGBA16F: - return PIX_FMT_RGB16F; - case PIX_FMT_RGB32F: - case PIX_FMT_RGBA32F: - return PIX_FMT_RGB32F; - } - - return PIX_FMT_INVALID; -} - -int PixelFormat::GetBufferSize(const PixelFormat::Format &format, const int &width, const int &height) -{ - return BytesPerPixel(format) * width * height; -} - -int PixelFormat::BytesPerPixel(const PixelFormat::Format &format) -{ - return BytesPerChannel(format) * ChannelCount(format); -} - -int PixelFormat::BytesPerChannel(const PixelFormat::Format &format) -{ - switch (format) { - case PixelFormat::PIX_FMT_RGB8: - case PixelFormat::PIX_FMT_RGBA8: - return 1; - case PixelFormat::PIX_FMT_RGB16U: - case PixelFormat::PIX_FMT_RGB16F: - case PixelFormat::PIX_FMT_RGBA16U: - case PixelFormat::PIX_FMT_RGBA16F: - return 2; - case PixelFormat::PIX_FMT_RGB32F: - case PixelFormat::PIX_FMT_RGBA32F: - return 4; - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - qFatal("Invalid pixel format requested"); - - // qFatal will abort so we won't get here, but this suppresses compiler warnings - return 0; -} - -int PixelFormat::ChannelCount(const PixelFormat::Format &format) -{ - if (PixelFormat::FormatHasAlphaChannel(format)) { - return kRGBAChannels; - } else { - return kRGBChannels; - } -} - -FramePtr PixelFormat::ConvertPixelFormat(FramePtr frame, const PixelFormat::Format &dest_format) -{ - if (frame->format() == dest_format) { - return frame; - } - - // Create a destination frame with the same parameters - FramePtr converted = Frame::Create(); - converted->set_video_params(VideoParams(frame->video_params().width(), - frame->video_params().height(), - dest_format)); - converted->set_timestamp(frame->timestamp()); - converted->allocate(); - - // Do the conversion through OIIO - create a buffer for the source image - OIIO::ImageBuf src(OIIO::ImageSpec(frame->width(), - frame->height(), - ChannelCount(frame->format()), - GetOIIOTypeDesc(frame->format()))); - - // Set the pixels (this is necessary as opposed to an OIIO buffer wrapper since Frame has - // linesizes) - OIIODecoder::FrameToBuffer(frame, &src); - - // Create a destination OIIO buffer with our destination format - OIIO::ImageBuf dst(OIIO::ImageSpec(converted->width(), - converted->height(), - ChannelCount(converted->format()), - GetOIIOTypeDesc(converted->format()))); - - if (dst.copy_pixels(src)) { - - // Convert our buffer back to a frame - OIIODecoder::BufferToFrame(&dst, converted); - - return converted; - } else { - return nullptr; - } -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/render/pixelformat.h b/app/render/pixelformat.h deleted file mode 100644 index cb7c53fae..000000000 --- a/app/render/pixelformat.h +++ /dev/null @@ -1,149 +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 . - -***/ - -#ifndef BITDEPTHS_H -#define BITDEPTHS_H - -#include -#include -#include -#include - -#include "render/rendermodes.h" - -OLIVE_NAMESPACE_ENTER - -class Frame; -using FramePtr = std::shared_ptr; - -class PixelFormat : public QObject -{ - Q_OBJECT -public: - /** - * @brief Olive's internal supported pixel formats. - */ - enum Format { - PIX_FMT_INVALID = -1, - - PIX_FMT_RGBA8, - PIX_FMT_RGBA16U, - PIX_FMT_RGBA16F, - PIX_FMT_RGBA32F, - - PIX_FMT_RGB8, - PIX_FMT_RGB16U, - PIX_FMT_RGB16F, - PIX_FMT_RGB32F, - - PIX_FMT_COUNT - }; - - static void CreateInstance(); - static void DestroyInstance(); - static PixelFormat* instance(); - - /** - * @brief Returns the configured pixel format for a given mode - */ - Format GetConfiguredFormatForMode(RenderMode::Mode mode); - void SetConfiguredFormatForMode(RenderMode::Mode mode, PixelFormat::Format format); - - static Format OIIOFormatToOliveFormat(OIIO::TypeDesc desc, bool has_alpha); - - static Format GetFormatWithAlphaChannel(Format f); - static Format GetFormatWithoutAlphaChannel(Format f); - - /** - * @brief Returns the minimum buffer size (in bytes) necessary for a given format, width, and height. - * - * @param format - * - * The format of the data the buffer should contain. Must be a member of the olive::PixelFormat enum. - * - * @param width - * - * The width (in pixels) of the buffer. - * - * @param height - * - * The height (in pixels) of the buffer. - */ - static int GetBufferSize(const Format &format, const int& width, const int& height); - - /** - * @brief Returns the number of bytes per pixel for a certain format - * - * Different formats use different sizes of data for pixels. Use this function to determine how many bytes a pixel - * requires for a certain format. The number of bytes will always be a multiple of 4 since all formats use RGBA and - * are at least 1 bpc. - */ - static int BytesPerPixel(const Format &format); - - /** - * @brief Returns the number of bytes per channel for a certain format - */ - static int BytesPerChannel(const Format& format); - - /** - * @brief Return the number of channels in this format - */ - static int ChannelCount(const Format& format); - - /** - * @brief Convert a frame to a pixel format - * - * If the frame's pixel format == the destination format, this just returns `frame`. - */ - static FramePtr ConvertPixelFormat(FramePtr frame, const Format &dest_format); - - /** - * @brief Simple convenience function returning whether a pixel format has an alpha channel or not - */ - static bool FormatHasAlphaChannel(const Format& format); - - /** - * @brief Simple convenience function returning whether a pixel format is float-based or integer-based - */ - static bool FormatIsFloat(const Format& format); - - /** - * @brief Get corresponding OpenImageIO TypeDesc for a given pixel format - */ - static OIIO::TypeDesc::BASETYPE GetOIIOTypeDesc(const Format& format); - - /** - * @brief Get format name - */ - static QString GetName(const Format& format); - -signals: - void FormatChanged(); - -private: - PixelFormat() = default; - - static PixelFormat* instance_; - -}; - -OLIVE_NAMESPACE_EXIT - -#endif // BITDEPTHS_H diff --git a/app/render/playbackcache.cpp b/app/render/playbackcache.cpp index 1c6103e48..a56c106be 100644 --- a/app/render/playbackcache.cpp +++ b/app/render/playbackcache.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,13 +27,16 @@ #include "project/project.h" #include "render/diskmanager.h" -OLIVE_NAMESPACE_ENTER +namespace olive { void PlaybackCache::Invalidate(const TimeRange &r) { - Q_ASSERT(r.in() != r.out()); + if (r.in() == r.out()) { + qWarning() << "Tried to invalidate zero-length range"; + return; + } - invalidated_.InsertTimeRange(r); + invalidated_.insert(r); RemoveRangeFromJobs(r); qint64 job_time = QDateTime::currentMSecsSinceEpoch(); @@ -69,11 +72,11 @@ void PlaybackCache::SetLength(const rational &r) jobs_.clear(); } else if (r > length_) { // If new length is greater, simply extend the invalidated range for now - invalidated_.InsertTimeRange(range_diff); + invalidated_.insert(range_diff); jobs_.append({range_diff, QDateTime::currentMSecsSinceEpoch()}); } else { // If new length is smaller, removed hashes - invalidated_.RemoveTimeRange(range_diff); + invalidated_.remove(range_diff); RemoveRangeFromJobs(range_diff); } @@ -123,7 +126,7 @@ void PlaybackCache::Shift(const rational &from, const rational &to) void PlaybackCache::Validate(const TimeRange &r) { - invalidated_.RemoveTimeRange(r); + invalidated_.remove(r); emit Validated(r); } @@ -192,4 +195,4 @@ QString PlaybackCache::GetCacheDirectory() const } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/render/playbackcache.h b/app/render/playbackcache.h index 73a4ee385..40d333526 100644 --- a/app/render/playbackcache.h +++ b/app/render/playbackcache.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/timerange.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Project; @@ -71,13 +71,13 @@ public slots: void Shift(const rational& from, const rational& to); signals: - void Invalidated(const OLIVE_NAMESPACE::TimeRange& r); + void Invalidated(const olive::TimeRange& r); - void Validated(const OLIVE_NAMESPACE::TimeRange& r); + void Validated(const olive::TimeRange& r); - void Shifted(const OLIVE_NAMESPACE::rational& from, const OLIVE_NAMESPACE::rational& to); + void Shifted(const olive::rational& from, const olive::rational& to); - void LengthChanged(const OLIVE_NAMESPACE::rational& r); + void LengthChanged(const olive::rational& r); protected: void Validate(const TimeRange& r); @@ -106,6 +106,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // PLAYBACKCACHE_H diff --git a/app/render/previewautocacher.cpp b/app/render/previewautocacher.cpp new file mode 100644 index 000000000..8037b6a6f --- /dev/null +++ b/app/render/previewautocacher.cpp @@ -0,0 +1,782 @@ +#include "previewautocacher.h" + +#include +#include + +#include "project/item/sequence/sequence.h" +#include "project/project.h" +#include "render/rendermanager.h" +#include "render/renderprocessor.h" + +namespace olive { + +PreviewAutoCacher::PreviewAutoCacher() : + viewer_node_(nullptr), + paused_(false), + has_changed_(false), + use_custom_range_(false), + single_frame_render_(nullptr), + last_update_time_(0), + ignore_next_mouse_button_(false), + video_params_changed_(false), + audio_params_changed_(false), + color_manager_(nullptr) +{ + // Set default autocache range + SetPlayhead(rational()); + + delayed_requeue_timer_.setInterval(Config::Current()[QStringLiteral("AutoCacheDelay")].toInt()); + delayed_requeue_timer_.setSingleShot(true); + connect(&delayed_requeue_timer_, &QTimer::timeout, this, &PreviewAutoCacher::RequeueFrames); +} + +RenderTicketPtr PreviewAutoCacher::GetSingleFrame(const rational &t) +{ + if (single_frame_render_) { + single_frame_render_->Cancel(); + } + + single_frame_render_ = std::make_shared(); + + single_frame_render_->setProperty("time", QVariant::fromValue(t)); + + // Copy because TryRender() might set this to null and we still want to return a handle to this + RenderTicketPtr copy = single_frame_render_; + + TryRender(); + + return copy; +} + +void PreviewAutoCacher::SetPaused(bool paused) +{ + paused_ = paused; + + if (paused_) { + // Pause the autocache + ClearVideoQueue(); + } else { + // Unpause the cache + RequeueFrames(); + } +} + +void PreviewAutoCacher::NodeGraphChanged(NodeInput *source) +{ + // We need to determine: + // - If we don't have this input, assume that it's coming soon and ignore it + // - If we do, is this input a child of another input we're already copying? + // - Or are any of the queued inputs children of this one? + + // First we need to find our copy of the input being queued + Node* our_copy_node = copy_map_.value(source->parentNode()); + + // If we don't have this node yet, assume it's coming in a later copy in which case it'll be + // copied then + if (!our_copy_node) { + // Assert that there are updates coming + Q_ASSERT(!graph_update_queue_.isEmpty()); + return; + } + + // If we're here, we must have this node. Determine if we're already copying a "parent" of this + for (int i=0; iIsArray() && static_cast(source)->sub_params().contains(queued_input)) + || queued_input->parentNode()->OutputsTo(source, true, true)) { + // In which case, we don't need to queue it and can queue our own + graph_update_queue_.removeAt(i); + disconnect(queued_input, &NodeInput::destroyed, this, &PreviewAutoCacher::QueuedInputRemoved); + i--; + } + + // Check if the source is a member of this array, in which case it'll be copied eventually anyway + if (queued_input->IsArray() + && static_cast(queued_input)->sub_params().contains(source)) { + return; + } + + // Check if this dependency graph is already queued + if (source->parentNode()->OutputsTo(queued_input, true, true)) { + // In which case, no further copy is necessary + return; + } + } + + graph_update_queue_.append(source); + connect(source, &NodeInput::destroyed, this, &PreviewAutoCacher::QueuedInputRemoved); +} + +void PreviewAutoCacher::GenerateHashes(ViewerOutput *viewer, FrameHashCache* cache, const QVector ×, qint64 job_time) +{ + std::vector existing_hashes; + + foreach (const rational& time, times) { + // See if hash already exists in disk cache + QByteArray hash = RenderManager::Hash(viewer->texture_input()->get_connected_node(), viewer->video_params(), time); + + // Check memory list since disk checking is slow + bool hash_exists = (std::find(existing_hashes.begin(), existing_hashes.end(), hash) != existing_hashes.end()); + + if (!hash_exists) { + hash_exists = QFileInfo::exists(cache->CachePathName(hash)); + + if (hash_exists) { + existing_hashes.push_back(hash); + } + } + + // Set hash in FrameHashCache's thread rather than in ours to prevent race conditions + QMetaObject::invokeMethod(cache, "SetHash", Qt::QueuedConnection, + OLIVE_NS_ARG(rational, time), + Q_ARG(QByteArray, hash), + Q_ARG(qint64, job_time), + Q_ARG(bool, hash_exists)); + } +} + +void PreviewAutoCacher::VideoInvalidated(const TimeRange &range) +{ + ClearQueue(false); + + // Hash these frames since that should be relatively quick. + if (ignore_next_mouse_button_ || !(qApp->mouseButtons() & Qt::LeftButton)) { + ignore_next_mouse_button_ = false; + + invalidated_video_.insert(range); + + TryRender(); + } +} + +void PreviewAutoCacher::AudioInvalidated(const TimeRange &range) +{ + ClearQueue(false); + + // Start jobs to re-render the audio at this range, split into 2 second chunks + invalidated_audio_.insert(range); + + TryRender(); +} + +void PreviewAutoCacher::HashesProcessed() +{ + QFutureWatcher* watcher = static_cast*>(sender()); + + if (hash_tasks_.contains(watcher)) { + hash_tasks_.removeOne(watcher); + + // Restart delayed requeue timer + delayed_requeue_timer_.stop(); + delayed_requeue_timer_.start(); + } + + // The cacher might be waiting for this job to finish + if (!graph_update_queue_.isEmpty()) { + TryRender(); + } + + delete watcher; +} + +void PreviewAutoCacher::AudioRendered() +{ + RenderTicketWatcher* watcher = static_cast(sender()); + + if (audio_tasks_.contains(watcher)) { + if (!watcher->WasCancelled()) { + viewer_node_->audio_playback_cache()->WritePCM(audio_tasks_.value(watcher), + watcher->Get().value(), + watcher->GetTicket()->GetJobTime()); + + // Retrieve visual waveforms + QVector waveform_list = watcher->GetTicket()->property("waveforms").value< QVector >(); + foreach (const RenderProcessor::RenderedWaveform& waveform_info, waveform_list) { + // Find original track + TrackOutput* track = nullptr; + + for (auto it=copy_map_.cbegin(); it!=copy_map_.cend(); it++) { + if (it.value() == waveform_info.track) { + track = static_cast(it.key()); + break; + } + } + + if (track) { + QList valid_ranges = viewer_node_->audio_playback_cache()->GetValidRanges(waveform_info.range, + watcher->GetTicket()->GetJobTime()); + if (!valid_ranges.isEmpty()) { + // Generate visual waveform in this background thread + track->waveform().set_channel_count(viewer_node_->audio_params().channel_count()); + + foreach (const TimeRange& r, valid_ranges) { + track->waveform().OverwriteSums(waveform_info.waveform, r.in(), r.in() - waveform_info.range.in(), r.length()); + } + + emit track->PreviewChanged(); + } + } + } + } + + audio_tasks_.remove(watcher); + } + + // The cacher might be waiting for this job to finish + if (!graph_update_queue_.isEmpty()) { + TryRender(); + } + + delete watcher; +} + +void PreviewAutoCacher::VideoRendered() +{ + RenderTicketWatcher* watcher = static_cast(sender()); + + if (video_tasks_.contains(watcher)) { + if (watcher->WasCancelled()) { + // We didn't get this hash + currently_caching_hashes_.removeOne(watcher->property("hash").toByteArray()); + } else { + const QByteArray& hash = video_tasks_.value(watcher); + + // Download frame in another thread + RenderTicketWatcher* w = new RenderTicketWatcher(); + video_download_tasks_.insert(w, hash); + connect(w, &RenderTicketWatcher::Finished, this, &PreviewAutoCacher::VideoDownloaded); + w->SetTicket(RenderManager::instance()->SaveFrameToCache(viewer_node_->video_frame_cache(), + watcher->Get().value(), + hash, + true)); + } + + video_tasks_.remove(watcher); + } + + // The cacher might be waiting for this job to finish + if (!graph_update_queue_.isEmpty()) { + TryRender(); + } + + delete watcher; +} + +void PreviewAutoCacher::VideoDownloaded() +{ + RenderTicketWatcher* watcher = static_cast(sender()); + + if (video_download_tasks_.contains(watcher)) { + if (!watcher->WasCancelled()) { + if (watcher->Get().toBool()) { + const QByteArray& hash = video_download_tasks_.value(watcher); + + currently_caching_hashes_.removeOne(hash); + + viewer_node_->video_frame_cache()->ValidateFramesWithHash(hash); + } else { + qCritical() << "Failed to download video frame"; + } + } + + video_download_tasks_.remove(watcher); + } + + delete watcher; +} + +void PreviewAutoCacher::QueuedInputRemoved() +{ + NodeInput* i = static_cast(sender()); + disconnect(i, &NodeInput::destroyed, this, &PreviewAutoCacher::QueuedInputRemoved); + graph_update_queue_.removeOne(i); +} + +void PreviewAutoCacher::VideoParamsChanged() +{ + // In case the user is pressing the mouse at this exact moment + IgnoreNextMouseButton(); + + ClearVideoQueue(); + video_params_changed_ = true; + TryRender(); +} + +void PreviewAutoCacher::AudioParamsChanged() +{ + ClearAudioQueue(); + audio_params_changed_ = true; + TryRender(); +} + +void PreviewAutoCacher::SingleFrameFinished() +{ + RenderTicketWatcher* watcher = static_cast(sender()); + RenderTicketPtr passthrough = watcher->property("passthrough").value(); + passthrough->Finish(watcher->GetTicket()->Get(), watcher->GetTicket()->WasCancelled()); + delete watcher; +} + +//#define PRINT_UPDATE_QUEUE_INFO +void PreviewAutoCacher::ProcessUpdateQueue() +{ +#ifdef PRINT_UPDATE_QUEUE_INFO + qint64 t = QDateTime::currentMSecsSinceEpoch(); + qDebug() << "Processing update queue of" << graph_update_queue_.size() << "elements:"; +#endif + + while (!graph_update_queue_.isEmpty()) { + NodeInput* i = graph_update_queue_.takeFirst(); +#ifdef PRINT_UPDATE_QUEUE_INFO + qDebug() << " " << i->parentNode()->id() << i->id(); +#endif + disconnect(i, &NodeInput::destroyed, this, &PreviewAutoCacher::QueuedInputRemoved); + + CopyNodeInputValue(i); + } + +#ifdef PRINT_UPDATE_QUEUE_INFO + qDebug() << "Update queue took:" << (QDateTime::currentMSecsSinceEpoch() - t); +#endif + + last_update_time_ = QDateTime::currentMSecsSinceEpoch(); +} + +bool PreviewAutoCacher::HasActiveJobs() const +{ + return !hash_tasks_.isEmpty() + || !audio_tasks_.isEmpty() + || !video_tasks_.isEmpty(); +} + +void PreviewAutoCacher::SetPlayhead(const rational &playhead) +{ + cache_range_ = TimeRange(playhead - Config::Current()["DiskCacheBehind"].value(), + playhead + Config::Current()["DiskCacheAhead"].value()); + + has_changed_ = true; + use_custom_range_ = false; + + RequeueFrames(); +} + +void PreviewAutoCacher::ClearQueue(bool wait) +{ + ClearHashQueue(wait); + ClearVideoQueue(wait); + ClearAudioQueue(wait); +} + +void PreviewAutoCacher::ClearHashQueue(bool wait) +{ + auto copy = hash_tasks_; + + for (auto it=copy.cbegin(); it!=copy.cend(); it++) { + (*it)->cancel(); + } + if (wait) { + copy = hash_tasks_; + for (auto it=copy.cbegin(); it!=copy.cend(); it++) { + (*it)->waitForFinished(); + } + } +} + +void PreviewAutoCacher::ClearVideoQueue(bool wait) +{ + // Copy because tasks that cancel immediately will be automatically removed from the list + auto copy = video_tasks_; + + for (auto it=copy.cbegin(); it!=copy.cend(); it++) { + it.key()->Cancel(); + } + if (wait) { + copy = video_tasks_; + for (auto it=copy.cbegin(); it!=copy.cend(); it++) { + it.key()->WaitForFinished(); + } + } + + has_changed_ = true; + use_custom_range_ = false; +} + +void PreviewAutoCacher::ClearAudioQueue(bool wait) +{ + // Create a copy because otherwise + auto copy = audio_tasks_; + + for (auto it=copy.cbegin(); it!=copy.cend(); it++) { + it.key()->Cancel(); + } + if (wait) { + copy = audio_tasks_; + for (auto it=copy.cbegin(); it!=copy.cend(); it++) { + it.key()->WaitForFinished(); + } + } +} + +void PreviewAutoCacher::ClearVideoDownloadQueue(bool wait) +{ + // Create a copy because otherwise + auto copy = video_download_tasks_; + + for (auto it=copy.cbegin(); it!=copy.cend(); it++) { + it.key()->Cancel(); + } + if (wait) { + copy = video_download_tasks_; + for (auto it=copy.cbegin(); it!=copy.cend(); it++) { + it.key()->WaitForFinished(); + } + } +} + +void PreviewAutoCacher::CopyNodeInputValue(NodeInput *input) +{ + // Find our copy of this parameter + Node* our_copy_node = copy_map_.value(input->parentNode()); + Q_ASSERT(our_copy_node); + NodeInput* our_copy = our_copy_node->GetInputWithID(input->id()); + + // Copy the standard/keyframe values between these two inputs + NodeInput::CopyValues(input, + our_copy, + false, + false); + + // Handle connections + if (input->is_connected() || our_copy->is_connected()) { + // If one of the inputs is connected, it's likely this change came from connecting or + // disconnecting whatever was connected to it + + // We start by removing all old dependencies from the map + QVector old_deps = our_copy->GetExclusiveDependencies(); + foreach (Node* i, old_deps) { + copy_map_.take(copy_map_.key(i))->deleteLater(); + } + + // And clear any other edges + while (!our_copy->edges().isEmpty()) { + NodeParam::DisconnectEdge(our_copy->edges().first()); + } + + // Then we copy all node dependencies and connections (if there are any) + CopyNodeMakeConnection(input, our_copy); + } + + // Call on sub-elements too + if (input->IsArray()) { + foreach (NodeInput* i, static_cast(input)->sub_params()) { + CopyNodeInputValue(i); + } + } +} + +Node* PreviewAutoCacher::CopyNodeConnections(Node* src_node) +{ + // Check if this node is already in the map + Node* dst_node = copy_map_.value(src_node); + + // If not, create it now + if (!dst_node) { + dst_node = src_node->copy(); + + if (dst_node->IsTrack()) { + // Hack that ensures the track type is set since we don't bother copying the whole timeline + static_cast(dst_node)->set_track_type(static_cast(src_node)->track_type()); + } + + copy_map_.insert(src_node, dst_node); + } + + // Make sure its values are copied + Node::CopyInputs(src_node, dst_node, false); + + // Copy all connections + QVector src_node_inputs = src_node->GetInputsIncludingArrays(); + QVector dst_node_inputs = dst_node->GetInputsIncludingArrays(); + + for (int i=0;iis_connected()) { + Node* dst_node = CopyNodeConnections(src_input->get_connected_node()); + + NodeOutput* corresponding_output = dst_node->GetOutputWithID(src_input->get_connected_output()->id()); + + NodeParam::ConnectEdge(corresponding_output, + dst_input); + } +} + +void PreviewAutoCacher::TryRender() +{ + if (!graph_update_queue_.isEmpty()) { + if (HasActiveJobs()) { + // Still waiting for jobs to finish + return; + } + + // No jobs are active, we can process the update queue + ProcessUpdateQueue(); + + if (video_params_changed_) { + copied_viewer_node_->set_video_params(viewer_node_->video_params()); + video_params_changed_ = false; + } + + if (audio_params_changed_) { + copied_viewer_node_->set_audio_params(viewer_node_->audio_params()); + audio_params_changed_ = false; + } + } + + // If we're here, we must be able to render + if (!invalidated_video_.isEmpty()) { + QVector frames = viewer_node_->video_frame_cache()->GetFrameListFromTimeRange(invalidated_video_); + + QFutureWatcher* watcher = new QFutureWatcher(); + hash_tasks_.append(watcher); + connect(watcher, &QFutureWatcher::finished, this, &PreviewAutoCacher::HashesProcessed); + watcher->setFuture(QtConcurrent::run(&PreviewAutoCacher::GenerateHashes, + copied_viewer_node_, + viewer_node_->video_frame_cache(), + frames, + last_update_time_)); + + invalidated_video_.clear(); + } + + if (!invalidated_audio_.isEmpty()) { + foreach (const TimeRange& range, invalidated_audio_) { + std::list chunks = range.Split(2); + + foreach (const TimeRange& r, chunks) { + RenderTicketWatcher* watcher = new RenderTicketWatcher(); + connect(watcher, &RenderTicketWatcher::Finished, this, &PreviewAutoCacher::AudioRendered); + audio_tasks_.insert(watcher, r); + watcher->SetTicket(RenderManager::instance()->RenderAudio(copied_viewer_node_, r, true)); + } + } + + invalidated_audio_.clear(); + } + + if (single_frame_render_) { + RenderTicketWatcher* watcher = new RenderTicketWatcher(); + + watcher->setProperty("passthrough", QVariant::fromValue(single_frame_render_)); + + connect(watcher, &RenderTicketWatcher::Finished, this, &PreviewAutoCacher::SingleFrameFinished); + + single_frame_render_->Start(); + + watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_, + color_manager_, + single_frame_render_->property("time").value(), + RenderMode::kOffline, + viewer_node_->video_frame_cache(), + true)); + + single_frame_render_ = nullptr; + } +} + +void PreviewAutoCacher::RequeueFrames() +{ + delayed_requeue_timer_.stop(); + + if (viewer_node_ + && viewer_node_->video_frame_cache()->HasInvalidatedRanges() + && hash_tasks_.isEmpty() + && has_changed_ + && (!paused_ || use_custom_range_)) { + TimeRange using_range; + + if (use_custom_range_) { + using_range = custom_autocache_range_; + use_custom_range_ = false; + } else { + using_range = cache_range_; + } + + QVector invalidated_ranges = viewer_node_->video_frame_cache()->GetInvalidatedFrames(using_range); + + ClearVideoQueue(); + + foreach (const rational& t, invalidated_ranges) { + const QByteArray& hash = viewer_node_->video_frame_cache()->GetHash(t); + + if (t >= using_range.in() + && t < using_range.out() + && !currently_caching_hashes_.contains(hash)) { + // Don't render any hash more than once + currently_caching_hashes_.append(hash); + + RenderTicketWatcher* watcher = new RenderTicketWatcher(); + watcher->setProperty("hash", hash); + connect(watcher, &RenderTicketWatcher::Finished, this, &PreviewAutoCacher::VideoRendered); + video_tasks_.insert(watcher, hash); + watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_, + color_manager_, + t, RenderMode::kOffline, + viewer_node_->video_frame_cache(), + false)); + } + } + + has_changed_ = false; + } +} + +void PreviewAutoCacher::IgnoreNextMouseButton() +{ + ignore_next_mouse_button_ = true; +} + +void PreviewAutoCacher::ForceCacheRange(const TimeRange &range) +{ + has_changed_ = true; + use_custom_range_ = true; + custom_autocache_range_ = range; + + RequeueFrames(); +} + +void PreviewAutoCacher::SetViewerNode(ViewerOutput *viewer_node) +{ + if (viewer_node_ == viewer_node) { + return; + } + + if (viewer_node_) { + // Cancel any remaining tickets and wait for them to finish + ClearQueue(true); + + // Clear autocache lists + { + // We need to wait for these since they work directly on the FrameHashCache. Most of the time + // this is fine, but not if the FrameHashCache gets deleted after this function. + ClearHashQueue(true); + + // This can be cleared normally (frames will be discarded and need to be rendered again) + ClearVideoQueue(false); + + // This can be cleared normally (PCM data will be discarded and need to be rendered again) + ClearAudioQueue(false); + + // We'll need to wait for these since they work directly on the FrameHashCache. Frames will + // be in the cache for later use. + ClearVideoDownloadQueue(true); + + // No longer caching any hashes + currently_caching_hashes_.clear(); + } + + // Delete all of our copied nodes + foreach (Node* c, copy_map_) { + delete c; + } + copy_map_.clear(); + copied_viewer_node_ = nullptr; + graph_update_queue_.clear(); + + video_params_changed_ = false; + audio_params_changed_ = false; + + // Disconnect signal (will be a no-op if the signal was never connected) + disconnect(viewer_node_, + &ViewerOutput::GraphChangedFrom, + this, + &PreviewAutoCacher::NodeGraphChanged); + + disconnect(viewer_node_, + &ViewerOutput::VideoParamsChanged, + this, + &PreviewAutoCacher::VideoParamsChanged); + + disconnect(viewer_node_, + &ViewerOutput::AudioParamsChanged, + this, + &PreviewAutoCacher::AudioParamsChanged); + + disconnect(viewer_node_->video_frame_cache(), + &PlaybackCache::Invalidated, + this, + &PreviewAutoCacher::VideoInvalidated); + + disconnect(viewer_node_->audio_playback_cache(), + &PlaybackCache::Invalidated, + this, + &PreviewAutoCacher::AudioInvalidated); + } + + viewer_node_ = viewer_node; + + if (viewer_node_) { + // Copy graph + copied_viewer_node_ = static_cast(viewer_node_->copy()); + copy_map_.insert(viewer_node_, copied_viewer_node_); + + // Copy parameters + copied_viewer_node_->set_video_params(viewer_node_->video_params()); + copied_viewer_node_->set_audio_params(viewer_node_->audio_params()); + + // We begin an operation and never end it which prevents the copy from unnecessarily + // invalidating its own cache + copied_viewer_node_->BeginOperation(); + + NodeGraphChanged(viewer_node_->texture_input()); + NodeGraphChanged(viewer_node_->samples_input()); + ProcessUpdateQueue(); + + invalidated_video_ = viewer_node_->video_frame_cache()->GetInvalidatedRanges(); + invalidated_audio_ = viewer_node_->audio_playback_cache()->GetInvalidatedRanges(); + + connect(viewer_node_, + &ViewerOutput::GraphChangedFrom, + this, + &PreviewAutoCacher::NodeGraphChanged); + + connect(viewer_node_, + &ViewerOutput::VideoParamsChanged, + this, + &PreviewAutoCacher::VideoParamsChanged); + + connect(viewer_node_, + &ViewerOutput::AudioParamsChanged, + this, + &PreviewAutoCacher::AudioParamsChanged); + + connect(viewer_node_->video_frame_cache(), + &PlaybackCache::Invalidated, + this, + &PreviewAutoCacher::VideoInvalidated); + + connect(viewer_node_->audio_playback_cache(), + &PlaybackCache::Invalidated, + this, + &PreviewAutoCacher::AudioInvalidated); + + TryRender(); + } +} + +} diff --git a/app/render/previewautocacher.h b/app/render/previewautocacher.h new file mode 100644 index 000000000..99c7aec70 --- /dev/null +++ b/app/render/previewautocacher.h @@ -0,0 +1,211 @@ +#ifndef AUTOCACHER_H +#define AUTOCACHER_H + +#include + +#include "config/config.h" +#include "node/node.h" +#include "node/output/viewer/viewer.h" +#include "render/colormanager.h" +#include "threading/threadticketwatcher.h" + +namespace olive { + +/** + * @brief Manager for dynamically caching a sequence in the background + * + * Intended to be used with a Viewer to dynamically cache parts of a sequence based on the playhead. + */ +class PreviewAutoCacher : public QObject +{ + Q_OBJECT +public: + PreviewAutoCacher(); + + RenderTicketPtr GetSingleFrame(const rational& t); + + /** + * @brief Set the viewer node to auto-cache + */ + void SetViewerNode(ViewerOutput *viewer_node); + + /** + * @brief If the mouse is held during the next cache invalidation, cache anyway + * + * By default, PreviewAutoCacher ignores invalidations that occur while the mouse is held down, + * assuming that if the mouse is held, the user is dragging something. If you know the mouse will + * be held during a certain action and want PreviewAutoCacher to cache anyway, call this before + * the cache invalidates. + */ + void IgnoreNextMouseButton(); + + /** + * @brief Returns whether the auto-cache is currently paused or not + */ + bool IsPaused() const + { + return paused_; + } + + /** + * @brief Sets whether the auto-cache is currently paused or not + * @param paused + * + * If TRUE, the cache queue is cleared (any frames currently being rendered will be processed as + * normal however). If FALSE, any uncached frames in the range will automatically be queued. + */ + void SetPaused(bool paused); + + /** + * @brief Force a certain range to be cached + * + * Usually, PreviewAutoCacher caches a user-defined range around the playhead, however there are + * times they may want certain non-playhead-related time ranges to be cached (i.e. entire sequence + * or in/out range), so that can be set here. + */ + void ForceCacheRange(const TimeRange& range); + + /** + * @brief Updates the range of frames to auto-cache + */ + void SetPlayhead(const rational& playhead); + + /** + * @brief Clears queue of running jobs + * + * Any jobs that haven't run yet are cancelled and will never run. Any jobs that are currently + * running are cancelled, but may not be finished by the time this function returns. If the + * jobs must be finished by the time this function returns, set `wait` to TRUE. + */ + void ClearQueue(bool wait = false); + + void ClearHashQueue(bool wait = false); + void ClearVideoQueue(bool wait = false); + void ClearAudioQueue(bool wait = false); + void ClearVideoDownloadQueue(bool wait = false); + + void SetColorManager(ColorManager* manager) + { + color_manager_ = manager; + } + +public slots: + /** + * @brief Main handler for when the NodeGraph changes + */ + void NodeGraphChanged(NodeInput *source); + +private: + static void GenerateHashes(ViewerOutput* viewer, FrameHashCache *cache, const QVector& times, qint64 job_time); + + void CopyNodeInputValue(NodeInput* input); + Node *CopyNodeConnections(Node *src_node); + void CopyNodeMakeConnection(NodeInput *src_input, NodeInput *dst_input); + + void TryRender(); + + /** + * @brief Process all changes to internal NodeGraph copy + * + * PreviewAutoCacher staggers updates to its internal NodeGraph copy, only applying them when the + * RenderManager is not reading from it. This function is called when such an opportunity arises. + */ + void ProcessUpdateQueue(); + + bool HasActiveJobs() const; + + QList graph_update_queue_; + QHash copy_map_; + ViewerOutput* copied_viewer_node_; + + ViewerOutput* viewer_node_; + + bool paused_; + + TimeRange cache_range_; + + bool has_changed_; + + bool use_custom_range_; + TimeRange custom_autocache_range_; + + TimeRangeList invalidated_video_; + TimeRangeList invalidated_audio_; + + RenderTicketPtr single_frame_render_; + + QList*> hash_tasks_; + QMap audio_tasks_; + QMap video_tasks_; + QMap video_download_tasks_; + + QVector currently_caching_hashes_; + + qint64 last_update_time_; + + bool ignore_next_mouse_button_; + + bool video_params_changed_; + + bool audio_params_changed_; + + ColorManager* color_manager_; + + QTimer delayed_requeue_timer_; + +private slots: + /** + * @brief Handler for when the NodeGraph reports a video change over a certain time range + */ + void VideoInvalidated(const olive::TimeRange &range); + + /** + * @brief Handler for when the NodeGraph reports a audio change over a certain time range + */ + void AudioInvalidated(const olive::TimeRange &range); + + /** + * @brief Handler for when we have applied all the hashes to the FrameHashCache + */ + void HashesProcessed(); + + /** + * @brief Handler for when the RenderManager has returned rendered audio + */ + void AudioRendered(); + + /** + * @brief Handler for when the RenderManager has returned rendered video frames + */ + void VideoRendered(); + + /** + * @brief Handler for when we've saved a video frame to the cache + */ + void VideoDownloaded(); + + /** + * @brief Handler for when a NodeInput has been deleted so we clear it from the queue + * + * FIXME: This is hacky. It also might not be necessary anymore with recent changes to the + * node system, but I haven't tested yet. Either way, PreviewAutoCacher should probably + * be able to pick up on these sorts of things without such a slot. + */ + void QueuedInputRemoved(); + + void VideoParamsChanged(); + + void AudioParamsChanged(); + + void SingleFrameFinished(); + + /** + * @brief Generic function called whenever the frames to render need to be (re)queued + */ + void RequeueFrames(); + +}; + +} + +#endif // AUTOCACHER_H diff --git a/app/node/input/media/audio/audio.h b/app/render/rendercache.h similarity index 59% rename from app/node/input/media/audio/audio.h rename to app/render/rendercache.h index 5cebdcc3c..f27120e61 100644 --- a/app/node/input/media/audio/audio.h +++ b/app/render/rendercache.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -18,29 +18,31 @@ ***/ -#ifndef AUDIOINPUT_H -#define AUDIOINPUT_H +#ifndef RENDERCACHE_H +#define RENDERCACHE_H -#include "../media.h" +#include "codec/decoder.h" +#include "project/item/footage/stream.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -class AudioInput : public MediaInput +template +class RenderCache : public QHash { public: - AudioInput() = default; + QMutex *mutex() + { + return &mutex_; + } - virtual Node* copy() const override; - - virtual Stream::Type type() const override; - - virtual QString Name() const override; - virtual QString ShortName() const override; - virtual QString id() const override; - virtual QString Description() const override; +private: + QMutex mutex_; }; -OLIVE_NAMESPACE_EXIT +using DecoderCache = RenderCache; +using ShaderCache = RenderCache; -#endif // AUDIOINPUT_H +} + +#endif // RENDERCACHE_H diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp new file mode 100644 index 000000000..f33dd3a7d --- /dev/null +++ b/app/render/renderer.cpp @@ -0,0 +1,273 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 "renderer.h" + +#include + +#include "common/ocioutils.h" + +namespace olive { + +Renderer::Renderer(QObject *parent) : + QObject(parent) +{ + +} + +TexturePtr Renderer::CreateTexture(const VideoParams ¶ms, Texture::Type type, const void *data, int linesize) +{ + QVariant v; + + if (type == Texture::k3D) { + v = CreateNativeTexture3D(params.effective_width(), params.effective_height(), + params.effective_depth(), params.format(), params.channel_count(), data, linesize); + } else { + v = CreateNativeTexture2D(params.effective_width(), params.effective_height(), params.format(), + params.channel_count(), data, linesize); + } + + if (v.isNull()) { + return nullptr; + } + + return std::make_shared(this, v, params, type); +} + +TexturePtr Renderer::CreateTexture(const VideoParams ¶ms, const void *data, int linesize) +{ + return CreateTexture(params, Texture::k2D, data, linesize); +} + +void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, bool source_is_premultiplied, Texture *destination, bool clear_destination, const QMatrix4x4 &matrix) +{ + BlitColorManagedInternal(color_processor, source, source_is_premultiplied, destination, destination->params(), clear_destination, matrix); +} + +void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, bool source_is_premultiplied, VideoParams params, bool clear_destination, const QMatrix4x4& matrix) +{ + BlitColorManagedInternal(color_processor, source, source_is_premultiplied, nullptr, params, clear_destination, matrix); +} + +void Renderer::Destroy() +{ + color_cache_.clear(); + + DestroyInternal(); +} + +bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::ColorContext *ctx) +{ + QMutexLocker locker(&color_cache_mutex_); + + ColorContext& color_ctx = *ctx; + + if (color_cache_.contains(color_processor->id())) { + color_ctx = color_cache_.value(color_processor->id()); + return true; + } else { + // Create shader description + const char* ocio_func_name = "OCIODisplay"; + auto shader_desc = OCIO::GpuShaderDesc::CreateShaderDesc(); + shader_desc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_3); + shader_desc->setFunctionName(ocio_func_name); + shader_desc->setResourcePrefix("ocio_"); + + // Generate shader + color_processor->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc); + + QString shader_frag; + shader_frag.append(QStringLiteral("// Main texture input\n" + "uniform sampler2D ove_maintex;\n" + "uniform int ove_maintex_alpha;\n" + "\n" + "// Macros defining `ove_maintex_alpha` state\n" + "// Matches `AlphaAssociated` C++ enum\n" + "#define ALPHA_NONE 0\n" + "#define ALPHA_UNASSOC 1\n" + "#define ALPHA_ASSOC 2\n" + "\n" + "// Macros so OCIO's shaders work on this GLSL version\n" + "#define texture2D texture\n" + "#define texture3D texture\n" + "\n" + "// Main texture coordinate\n" + "in vec2 ove_texcoord;\n" + "\n" + "// Texture output\n" + "out vec4 fragColor;\n")); + shader_frag.append(shader_desc->getShaderText()); + shader_frag.append(QStringLiteral("\n" + "// Alpha association functions\n" + "vec4 assoc(vec4 c) {\n" + " return vec4(c.rgb * c.a, c.a);\n" + "}\n" + "\n" + "vec4 reassoc(vec4 c) {\n" + " return (c.a == 0.0) ? c : assoc(c);\n" + "}\n" + "\n" + "vec4 deassoc(vec4 c) {\n" + " return (c.a == 0.0) ? c : vec4(c.rgb / c.a, c.a);\n" + "}\n" + "\n" + "void main() {\n" + " vec4 col = texture(ove_maintex, ove_texcoord);\n" + "\n" + " // If alpha is associated, de-associate now\n" + " if (ove_maintex_alpha == ALPHA_ASSOC) {\n" + " col = deassoc(col);\n" + " }\n" + "\n" + " // Perform color conversion\n" + " col = %1(col);\n" + "\n" + " // Associate or re-associate here\n" + " if (ove_maintex_alpha == ALPHA_ASSOC) {\n" + " col = reassoc(col);\n" + " } else if (ove_maintex_alpha == ALPHA_UNASSOC) {\n" + " col = assoc(col);\n" + " }\n" + "\n" + " fragColor = col;\n" + "}\n").arg(ocio_func_name)); + + // Try to compile shader + color_ctx.compiled_shader = CreateNativeShader(ShaderCode(shader_frag, + FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.vert")))); + + if (color_ctx.compiled_shader.isNull()) { + return false; + } + + color_ctx.lut3d_textures.resize(shader_desc->getNum3DTextures()); + for (unsigned int i=0; igetNum3DTextures(); i++) { + const char* tex_name = nullptr; + const char* sampler_name = nullptr; + unsigned int edge_len = 0; + OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR; + + shader_desc->get3DTexture(i, tex_name, sampler_name, edge_len, interpolation); + + if (!tex_name || !*tex_name + || !sampler_name || !*sampler_name + || !edge_len) { + qCritical() << "3D LUT texture data is corrupted"; + return false; + } + + const float* values = nullptr; + shader_desc->get3DTextureValues(i, values); + if (!values) { + qCritical() << "3D LUT texture values are missing"; + return false; + } + + // Allocate 3D LUT + color_ctx.lut3d_textures[i].texture = CreateTexture(VideoParams(edge_len, edge_len, edge_len, VideoParams::kFormatFloat32, VideoParams::kRGBChannelCount), + Texture::k3D, values); + color_ctx.lut3d_textures[i].name = sampler_name; + color_ctx.lut3d_textures[i].interpolation = (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; + } + + color_ctx.lut1d_textures.resize(shader_desc->getNumTextures()); + for (unsigned int i=0; igetNumTextures(); i++) { + const char* tex_name = nullptr; + const char* sampler_name = nullptr; + unsigned int width = 0, height = 0; + OCIO::GpuShaderDesc::TextureType channel = OCIO::GpuShaderDesc::TEXTURE_RGB_CHANNEL; + OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR; + + shader_desc->getTexture(i, tex_name, sampler_name, width, height, channel, interpolation); + + if (!tex_name || !*tex_name + || !sampler_name || !*sampler_name + || !width) { + qCritical() << "1D LUT texture data is corrupted"; + return false; + } + + const float* values = nullptr; + shader_desc->getTextureValues(i, values); + if (!values) { + qCritical() << "1D LUT texture values are missing"; + return false; + } + + // Allocate 1D LUT + color_ctx.lut1d_textures[i].texture = CreateTexture(VideoParams(width, height, VideoParams::kFormatFloat32, (channel == OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ? 1 : VideoParams::kRGBChannelCount), + Texture::k2D, + values); + color_ctx.lut1d_textures[i].name = sampler_name; + color_ctx.lut1d_textures[i].interpolation = (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; + } + + color_cache_.insert(color_processor->id(), color_ctx); + + return true; + } +} + +void Renderer::BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source, + bool source_is_premultiplied, Texture *destination, + VideoParams params, bool clear_destination, const QMatrix4x4& matrix) +{ + ColorContext color_ctx; + if (!GetColorContext(color_processor, &color_ctx)) { + return; + } + + ShaderJob job; + + job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(source), NodeParam::kTexture)); + job.InsertValue(QStringLiteral("ove_mvpmat"), ShaderValue(matrix, NodeParam::kMatrix)); + + AlphaAssociated associated; + if (source->channel_count() == VideoParams::kRGBAChannelCount) { + if (source_is_premultiplied) { + // De-assoc/re-assoc required for color management + associated = kAlphaAssociated; + } else { + // Just assoc at the end + associated = kAlphaUnassociated; + } + } else { + // No assoc/deassoc required + associated = kAlphaNone; + } + job.InsertValue(QStringLiteral("ove_maintex_alpha"), ShaderValue(associated, NodeParam::kInt)); + + foreach (const ColorContext::LUT& l, color_ctx.lut3d_textures) { + job.InsertValue(l.name, ShaderValue(QVariant::fromValue(l.texture), NodeParam::kTexture)); + job.SetInterpolation(l.name, l.interpolation); + } + foreach (const ColorContext::LUT& l, color_ctx.lut1d_textures) { + job.InsertValue(l.name, ShaderValue(QVariant::fromValue(l.texture), NodeParam::kTexture)); + job.SetInterpolation(l.name, l.interpolation); + } + + if (destination) { + BlitToTexture(color_ctx.compiled_shader, job, destination, clear_destination); + } else { + Blit(color_ctx.compiled_shader, job, params, clear_destination); + } +} + +} diff --git a/app/render/renderer.h b/app/render/renderer.h new file mode 100644 index 000000000..b75a1e0bc --- /dev/null +++ b/app/render/renderer.h @@ -0,0 +1,134 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 RENDERCONTEXT_H +#define RENDERCONTEXT_H + +#include +#include + +#include "common/define.h" +#include "common/timerange.h" +#include "node/node.h" +#include "render/colorprocessor.h" +#include "render/videoparams.h" +#include "texture.h" + +namespace olive { + +class ShaderJob; + +class Renderer : public QObject +{ + Q_OBJECT +public: + Renderer(QObject* parent = nullptr); + + virtual bool Init() = 0; + + TexturePtr CreateTexture(const VideoParams& params, Texture::Type type, const void* data = nullptr, int linesize = 0); + TexturePtr CreateTexture(const VideoParams& params, const void *data = nullptr, int linesize = 0); + + void BlitToTexture(QVariant shader, + olive::ShaderJob job, + olive::Texture* destination, + bool clear_destination = true) + { + Blit(shader, job, destination, destination->params(), clear_destination); + } + + void Blit(QVariant shader, + olive::ShaderJob job, + olive::VideoParams params, + bool clear_destination = true) + { + Blit(shader, job, nullptr, params, clear_destination); + } + + void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, bool source_is_premultiplied, Texture* destination, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4()); + void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, bool source_is_premultiplied, VideoParams params, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4()); + + void Destroy(); + + virtual void PostDestroy() = 0; + +public slots: + virtual void PostInit() = 0; + + virtual void DestroyInternal() = 0; + + virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) = 0; + + virtual QVariant CreateNativeTexture2D(int width, int height, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) = 0; + virtual QVariant CreateNativeTexture3D(int width, int height, int depth, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) = 0; + + virtual void DestroyNativeTexture(QVariant texture) = 0; + + virtual QVariant CreateNativeShader(olive::ShaderCode code) = 0; + + virtual void DestroyNativeShader(QVariant shader) = 0; + + virtual void UploadToTexture(olive::Texture* texture, const void* data, int linesize) = 0; + + virtual void DownloadFromTexture(olive::Texture* texture, void* data, int linesize) = 0; + +protected slots: + virtual void Blit(QVariant shader, + olive::ShaderJob job, + olive::Texture* destination, + olive::VideoParams destination_params, + bool clear_destination) = 0; + +private: + struct ColorContext { + struct LUT { + TexturePtr texture; + Texture::Interpolation interpolation; + QString name; + }; + + QVariant compiled_shader; + QVector lut3d_textures; + QVector lut1d_textures; + + }; + + enum AlphaAssociated { + kAlphaNone, + kAlphaUnassociated, + kAlphaAssociated + }; + + bool GetColorContext(ColorProcessorPtr color_processor, ColorContext* ctx); + + void BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source, + bool source_is_premultiplied, + Texture* destination, VideoParams params, bool clear_destination, + const QMatrix4x4 &matrix); + + QHash color_cache_; + + QMutex color_cache_mutex_; + +}; + +} + +#endif // RENDERCONTEXT_H diff --git a/app/render/rendererthreadwrapper.cpp b/app/render/rendererthreadwrapper.cpp new file mode 100644 index 000000000..2b86c1539 --- /dev/null +++ b/app/render/rendererthreadwrapper.cpp @@ -0,0 +1,163 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 "rendererthreadwrapper.h" + +namespace olive { + +RendererThreadWrapper::RendererThreadWrapper(Renderer *inner, QObject *parent) : + Renderer(parent), + inner_(inner), + thread_(nullptr) +{ +} + +bool RendererThreadWrapper::Init() +{ + // Init context in main thread + if (!inner_->Init()) { + return false; + } + + // Create thread + thread_ = new QThread(this); + thread_->start(QThread::IdlePriority); + + // Move context to thread + inner_->moveToThread(thread_); + + // Queue post-init in new thread + QMetaObject::invokeMethod(inner_, "PostInit", Qt::BlockingQueuedConnection); + + return true; +} + +void RendererThreadWrapper::PostInit() +{ + // Do nothing +} + +void RendererThreadWrapper::DestroyInternal() +{ + if (thread_) { + QMetaObject::invokeMethod(inner_, "DestroyInternal", Qt::BlockingQueuedConnection); + + thread_->quit(); + thread_->wait(); + delete thread_; + thread_ = nullptr; + + // Destroy in main thread + inner_->PostDestroy(); + } +} + +void RendererThreadWrapper::ClearDestination(double r, double g, double b, double a) +{ + QMetaObject::invokeMethod(inner_, "ClearDestination", Qt::BlockingQueuedConnection, + Q_ARG(double, r), + Q_ARG(double, g), + Q_ARG(double, b), + Q_ARG(double, a)); +} + +QVariant RendererThreadWrapper::CreateNativeTexture2D(int width, int height, VideoParams::Format format, int channel_count, const void *data, int linesize) +{ + QVariant v; + + QMetaObject::invokeMethod(inner_, "CreateNativeTexture2D", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QVariant, v), + Q_ARG(int, width), + Q_ARG(int, height), + OLIVE_NS_ARG(VideoParams::Format, format), + Q_ARG(int, channel_count), + Q_ARG(const void*, data), + Q_ARG(int, linesize)); + + return v; +} + +QVariant RendererThreadWrapper::CreateNativeTexture3D(int width, int height, int depth, VideoParams::Format format, int channel_count, const void *data, int linesize) +{ + QVariant v; + + QMetaObject::invokeMethod(inner_, "CreateNativeTexture3D", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QVariant, v), + Q_ARG(int, width), + Q_ARG(int, height), + Q_ARG(int, depth), + OLIVE_NS_ARG(VideoParams::Format, format), + Q_ARG(int, channel_count), + Q_ARG(const void*, data), + Q_ARG(int, linesize)); + + return v; +} + +void RendererThreadWrapper::DestroyNativeTexture(QVariant texture) +{ + QMetaObject::invokeMethod(inner_, "DestroyNativeTexture", Qt::BlockingQueuedConnection, + Q_ARG(QVariant, texture)); +} + +QVariant RendererThreadWrapper::CreateNativeShader(ShaderCode code) +{ + QVariant v; + + QMetaObject::invokeMethod(inner_, "CreateNativeShader", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QVariant, v), + OLIVE_NS_ARG(ShaderCode, code)); + + return v; +} + +void RendererThreadWrapper::DestroyNativeShader(QVariant shader) +{ + QMetaObject::invokeMethod(inner_, "DestroyNativeShader", Qt::BlockingQueuedConnection, + Q_ARG(QVariant, shader)); +} + +void RendererThreadWrapper::UploadToTexture(Texture *texture, const void *data, int linesize) +{ + QMetaObject::invokeMethod(inner_, "UploadToTexture", Qt::BlockingQueuedConnection, + OLIVE_NS_ARG(Texture*, texture), + Q_ARG(const void*, data), + Q_ARG(int, linesize)); +} + +void RendererThreadWrapper::DownloadFromTexture(Texture *texture, void *data, int linesize) +{ + QMetaObject::invokeMethod(inner_, "DownloadFromTexture", Qt::BlockingQueuedConnection, + OLIVE_NS_ARG(Texture*, texture), + Q_ARG(void*, data), + Q_ARG(int, linesize)); +} + +void RendererThreadWrapper::Blit(QVariant shader, ShaderJob job, Texture *destination, VideoParams destination_params, bool clear_destination) +{ + QMetaObject::invokeMethod(inner_, "Blit", Qt::BlockingQueuedConnection, + Q_ARG(QVariant, shader), + OLIVE_NS_ARG(ShaderJob, job), + OLIVE_NS_ARG(Texture*, destination), + OLIVE_NS_ARG(VideoParams, destination_params), + Q_ARG(bool, clear_destination)); +} + +} diff --git a/app/render/rendererthreadwrapper.h b/app/render/rendererthreadwrapper.h new file mode 100644 index 000000000..875a86d74 --- /dev/null +++ b/app/render/rendererthreadwrapper.h @@ -0,0 +1,82 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 RENDERCONTEXTTHREADWRAPPER_H +#define RENDERCONTEXTTHREADWRAPPER_H + +#include + +#include "renderer.h" + +namespace olive { + +class RendererThreadWrapper : public Renderer +{ +public: + RendererThreadWrapper(Renderer* inner, QObject* parent = nullptr); + + virtual ~RendererThreadWrapper() override + { + Destroy(); + PostDestroy(); + delete inner_; + } + + virtual bool Init() override; + + virtual void PostDestroy() override {} + +public slots: + virtual void PostInit() override; + + virtual void DestroyInternal() override; + + virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override; + + virtual QVariant CreateNativeTexture2D(int width, int height, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override; + virtual QVariant CreateNativeTexture3D(int width, int height, int depth, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override; + + virtual void DestroyNativeTexture(QVariant texture) override; + + virtual QVariant CreateNativeShader(olive::ShaderCode code) override; + + virtual void DestroyNativeShader(QVariant shader) override; + + virtual void UploadToTexture(olive::Texture* texture, const void* data, int linesize) override; + + virtual void DownloadFromTexture(olive::Texture* texture, void* data, int linesize) override; + +protected slots: + virtual void Blit(QVariant shader, + olive::ShaderJob job, + olive::Texture* destination, + olive::VideoParams destination_params, + bool clear_destination) override; + +private: + Renderer* inner_; + + QThread* thread_; + +}; + +} + +#endif // RENDERCONTEXTTHREADWRAPPER_H diff --git a/app/render/rendermanager.cpp b/app/render/rendermanager.cpp new file mode 100644 index 000000000..eceb9f89a --- /dev/null +++ b/app/render/rendermanager.cpp @@ -0,0 +1,215 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 "rendermanager.h" + +#include +#include +#include +#include + +#include "config/config.h" +#include "core.h" +#include "render/opengl/openglrenderer.h" +#include "render/rendererthreadwrapper.h" +#include "renderprocessor.h" +#include "task/conform/conform.h" +#include "task/taskmanager.h" +#include "window/mainwindow/mainwindow.h" + +namespace olive { + +RenderManager* RenderManager::instance_ = nullptr; + +RenderManager::RenderManager(QObject *parent) : + ThreadPool(QThread::IdlePriority, 0, parent), + backend_(kOpenGL) +{ + Renderer* graphics_renderer = nullptr; + + if (backend_ == kOpenGL) { + graphics_renderer = new OpenGLRenderer(); + } + + if (graphics_renderer) { + context_ = new RendererThreadWrapper(graphics_renderer, this); + context_->Init(); + context_->PostInit(); + + still_cache_ = new StillImageCache(); + decoder_cache_ = new DecoderCache(); + shader_cache_ = new ShaderCache(); + default_shader_ = context_->CreateNativeShader(ShaderCode(QString(), QString())); + } else { + qCritical() << "Tried to initialize unknown graphics backend"; + context_ = nullptr; + still_cache_ = nullptr; + decoder_cache_ = nullptr; + } +} + +RenderManager::~RenderManager() +{ + if (context_) { + context_->DestroyNativeShader(default_shader_); + + delete shader_cache_; + delete decoder_cache_; + delete still_cache_; + + context_->Destroy(); + context_->PostDestroy(); + delete context_; + } +} + +QByteArray RenderManager::Hash(const Node *n, const VideoParams ¶ms, const rational &time) +{ + QCryptographicHash hasher(QCryptographicHash::Sha1); + + // Embed video parameters into this hash + int width = params.effective_width(); + int height = params.effective_height(); + VideoParams::Format format = params.format(); + + hasher.addData(reinterpret_cast(&width), sizeof(int)); + hasher.addData(reinterpret_cast(&height), sizeof(int)); + hasher.addData(reinterpret_cast(&format), sizeof(VideoParams::Format)); + + if (n) { + n->Hash(hasher, time); + } + + return hasher.result(); +} + +RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, ColorManager* color_manager, + const rational& time, RenderMode::Mode mode, + FrameHashCache* cache, bool prioritize) +{ + return RenderFrame(viewer, + color_manager, + time, + mode, + viewer->video_params(), + viewer->audio_params(), + QSize(0, 0), + QMatrix4x4(), + VideoParams::kFormatInvalid, + nullptr, + cache, + prioritize); +} + +RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, ColorManager* color_manager, + const rational& time, RenderMode::Mode mode, + const VideoParams &video_params, const AudioParams &audio_params, + const QSize& force_size, + const QMatrix4x4& force_matrix, VideoParams::Format force_format, + ColorProcessorPtr force_color_output, + FrameHashCache* cache, bool prioritize) +{ + // Create ticket + RenderTicketPtr ticket = std::make_shared(); + + ticket->setProperty("viewer", Node::PtrToValue(viewer)); + ticket->setProperty("time", QVariant::fromValue(time)); + ticket->setProperty("size", force_size); + ticket->setProperty("matrix", force_matrix); + ticket->setProperty("format", force_format); + ticket->setProperty("mode", mode); + ticket->setProperty("type", kTypeVideo); + ticket->setProperty("colormanager", Node::PtrToValue(color_manager)); + ticket->setProperty("coloroutput", QVariant::fromValue(force_color_output)); + ticket->setProperty("vparam", QVariant::fromValue(video_params)); + ticket->setProperty("aparam", QVariant::fromValue(audio_params)); + + if (cache) { + ticket->setProperty("cache", cache->GetCacheDirectory()); + } + + if (ticket->thread() != this->thread()) { + ticket->moveToThread(this->thread()); + } + + // Queue appending the ticket and running the next job on our thread to make this function thread-safe + QMetaObject::invokeMethod(this, "AddTicket", Qt::AutoConnection, + OLIVE_NS_ARG(RenderTicketPtr, ticket), + Q_ARG(bool, prioritize)); + + return ticket; +} + +RenderTicketPtr RenderManager::RenderAudio(ViewerOutput* viewer, const TimeRange& r, bool generate_waveforms, bool prioritize) +{ + return RenderAudio(viewer, r, viewer->audio_params(), generate_waveforms, prioritize); +} + +RenderTicketPtr RenderManager::RenderAudio(ViewerOutput* viewer, const TimeRange &r, const AudioParams ¶ms, bool generate_waveforms, bool prioritize) +{ + // Create ticket + RenderTicketPtr ticket = std::make_shared(); + + ticket->setProperty("viewer", Node::PtrToValue(viewer)); + ticket->setProperty("time", QVariant::fromValue(r)); + ticket->setProperty("type", kTypeAudio); + ticket->setProperty("enablewaveforms", generate_waveforms); + ticket->setProperty("aparam", QVariant::fromValue(params)); + + if (ticket->thread() != this->thread()) { + ticket->moveToThread(this->thread()); + } + + // Queue appending the ticket and running the next job on our thread to make this function thread-safe + QMetaObject::invokeMethod(this, "AddTicket", Qt::AutoConnection, + OLIVE_NS_ARG(RenderTicketPtr, ticket), + Q_ARG(bool, prioritize)); + + return ticket; +} + +RenderTicketPtr RenderManager::SaveFrameToCache(FrameHashCache *cache, FramePtr frame, const QByteArray &hash, bool prioritize) +{ + // Create ticket + RenderTicketPtr ticket = std::make_shared(); + + ticket->setProperty("cache", Node::PtrToValue(cache)); + ticket->setProperty("frame", QVariant::fromValue(frame)); + ticket->setProperty("hash", hash); + ticket->setProperty("type", kTypeVideoDownload); + + if (ticket->thread() != this->thread()) { + ticket->moveToThread(this->thread()); + } + + // Queue appending the ticket and running the next job on our thread to make this function thread-safe + QMetaObject::invokeMethod(this, "AddTicket", Qt::AutoConnection, + OLIVE_NS_ARG(RenderTicketPtr, ticket), + Q_ARG(bool, prioritize)); + + return ticket; +} + +void RenderManager::RunTicket(RenderTicketPtr ticket) const +{ + RenderProcessor::Process(ticket, context_, still_cache_, decoder_cache_, shader_cache_, default_shader_); +} + +} diff --git a/app/render/rendermanager.h b/app/render/rendermanager.h new file mode 100644 index 000000000..8bc580ab8 --- /dev/null +++ b/app/render/rendermanager.h @@ -0,0 +1,149 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 RENDERBACKEND_H +#define RENDERBACKEND_H + +#include + +#include "config/config.h" +#include "colorprocessorcache.h" +#include "dialog/rendercancel/rendercancel.h" +#include "node/graph.h" +#include "node/output/viewer/viewer.h" +#include "node/traverser.h" +#include "render/renderer.h" +#include "rendercache.h" +#include "stillimagecache.h" +#include "threading/threadpool.h" + +namespace olive { + +class RenderManager : public ThreadPool +{ + Q_OBJECT +public: + enum Backend { + /// Graphics acceleration provided by OpenGL + kOpenGL, + + /// No graphics rendering - used to test core threading logic + kDummy + }; + + static void CreateInstance() + { + instance_ = new RenderManager(); + } + + static void DestroyInstance() + { + delete instance_; + instance_ = nullptr; + } + + static RenderManager* instance() + { + return instance_; + } + + /** + * @brief Generate a unique identifier for a certain node at a certain time + */ + static QByteArray Hash(const Node *n, const VideoParams ¶ms, const rational &time); + + /** + * @brief Asynchronously generate a frame at a given time + * + * The ticket from this function will return a FramePtr - the rendered frame in reference color + * space. + * + * Setting `prioritize` to TRUE puts this ticket at the top of the queue. Leaving it as FALSE + * appends it to the bottom. + * + * This function is thread-safe. + */ + RenderTicketPtr RenderFrame(ViewerOutput* viewer, ColorManager* color_manager, + const rational& time, RenderMode::Mode mode, + FrameHashCache* cache = nullptr, bool prioritize = false); + RenderTicketPtr RenderFrame(ViewerOutput* viewer, ColorManager* color_manager, + const rational& time, RenderMode::Mode mode, + const VideoParams& video_params, const AudioParams& audio_params, + const QSize& force_size, + const QMatrix4x4& force_matrix, VideoParams::Format force_format, + ColorProcessorPtr force_color_output, + FrameHashCache* cache = nullptr, bool prioritize = false); + + /** + * @brief Asynchronously generate a chunk of audio + * + * The ticket from this function will return a SampleBufferPtr - the rendered audio. + * + * Setting `prioritize` to TRUE puts this ticket at the top of the queue. Leaving it as FALSE + * appends it to the bottom. + * + * This function is thread-safe. + */ + RenderTicketPtr RenderAudio(ViewerOutput* viewer, const TimeRange& r, const AudioParams& params, bool generate_waveforms, bool prioritize = false); + RenderTicketPtr RenderAudio(ViewerOutput* viewer, const TimeRange& r, bool generate_waveforms, bool prioritize = false); + + RenderTicketPtr SaveFrameToCache(FrameHashCache* cache, FramePtr frame, const QByteArray& hash, bool prioritize = false); + + virtual void RunTicket(RenderTicketPtr ticket) const override; + + enum TicketType { + kTypeVideo, + kTypeAudio, + kTypeVideoDownload + }; + + Backend backend() const + { + return backend_; + } + +signals: + +private: + RenderManager(QObject* parent = nullptr); + + virtual ~RenderManager() override; + + static RenderManager* instance_; + + Renderer* context_; + + Backend backend_; + + StillImageCache* still_cache_; + + DecoderCache* decoder_cache_; + + ShaderCache* shader_cache_; + + QVariant default_shader_; + +}; + +} + +Q_DECLARE_METATYPE(olive::RenderManager::TicketType) + +#endif // RENDERBACKEND_H diff --git a/app/render/rendermodes.h b/app/render/rendermodes.h index 373414da8..02f2dfda2 100644 --- a/app/render/rendermodes.h +++ b/app/render/rendermodes.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class RenderMode { public: @@ -45,6 +45,6 @@ public: }; }; -OLIVE_NAMESPACE_EXIT +} #endif // RENDERMODE_H diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp new file mode 100644 index 000000000..27bd924c9 --- /dev/null +++ b/app/render/renderprocessor.cpp @@ -0,0 +1,538 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 "renderprocessor.h" + +#include +#include +#include +#include + +#include "project/project.h" +#include "rendermanager.h" + +namespace olive { + +RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache, ShaderCache *shader_cache, QVariant default_shader) : + ticket_(ticket), + render_ctx_(render_ctx), + still_image_cache_(still_image_cache), + decoder_cache_(decoder_cache), + shader_cache_(shader_cache), + default_shader_(default_shader) +{ +} + +void RenderProcessor::Run() +{ + // Depending on the render ticket type, start a job + RenderManager::TicketType type = ticket_->property("type").value(); + + ticket_->Start(); + + if (ticket_->WasCancelled()) { + return; + } + + switch (type) { + case RenderManager::kTypeVideo: + { + ViewerOutput* viewer = Node::ValueToPtr(ticket_->property("viewer")); + const VideoParams& video_params = ticket_->property("vparam").value(); + rational time = ticket_->property("time").value(); + + NodeValueTable table = ProcessInput(viewer->texture_input(), + TimeRange(time, time + video_params.time_base())); + + TexturePtr texture = table.Get(NodeParam::kTexture).value(); + + // Set up output frame parameters + VideoParams frame_params = ticket_->property("vparam").value(); + + QSize frame_size = ticket_->property("size").value(); + if (!frame_size.isNull()) { + frame_params.set_width(frame_size.width()); + frame_params.set_height(frame_size.height()); + } + + VideoParams::Format frame_format = static_cast(ticket_->property("format").toInt()); + if (frame_format != VideoParams::kFormatInvalid) { + frame_params.set_format(frame_format); + } + + if (RenderManager::instance()->backend() == RenderManager::kOpenGL + && QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) { + // HACK: From what I can tell, ANGLE only supports texture reading to RGBA + frame_params.set_channel_count(VideoParams::kRGBAChannelCount); + } else if (texture) { + frame_params.set_channel_count(texture->channel_count()); + } + + FramePtr frame = Frame::Create(); + frame->set_timestamp(time); + frame->set_video_params(frame_params); + frame->allocate(); + + if (!texture) { + // Blank frame out + memset(frame->data(), 0, frame->allocated_size()); + } else { + // Dump texture contents to frame + ColorProcessorPtr output_color_transform = ticket_->property("coloroutput").value(); + const VideoParams& tex_params = texture->params(); + + if (tex_params.effective_width() != frame_params.effective_width() + || tex_params.effective_height() != frame_params.effective_height() + || tex_params.format() != frame_params.format() + || output_color_transform) { + TexturePtr blit_tex = render_ctx_->CreateTexture(frame_params); + + QMatrix4x4 matrix = ticket_->property("matrix").value(); + + if (output_color_transform) { + // Yes color transform, blit color managed + render_ctx_->BlitColorManaged(output_color_transform, texture, true, blit_tex.get(), true, matrix); + } else { + // No color transform, just blit + ShaderJob job; + job.InsertValue(QStringLiteral("ove_maintex"), {QVariant::fromValue(texture), NodeParam::kTexture}); + job.InsertValue(QStringLiteral("ove_mvpmat"), {matrix, NodeParam::kMatrix}); + + render_ctx_->BlitToTexture(default_shader_, job, blit_tex.get()); + } + + // Replace texture that we're going to download in the next step + texture = blit_tex; + } + + render_ctx_->DownloadFromTexture(texture.get(), frame->data(), frame->linesize_pixels()); + } + + ticket_->Finish(QVariant::fromValue(frame), IsCancelled()); + break; + } + case RenderManager::kTypeAudio: + { + ViewerOutput* viewer = Node::ValueToPtr(ticket_->property("viewer")); + TimeRange time = ticket_->property("time").value(); + + NodeValueTable table = ProcessInput(viewer->samples_input(), time); + + ticket_->Finish(table.Get(NodeParam::kSamples), IsCancelled()); + break; + } + case RenderManager::kTypeVideoDownload: + { + FrameHashCache* cache = Node::ValueToPtr(ticket_->property("cache")); + FramePtr frame = ticket_->property("frame").value(); + QByteArray hash = ticket_->property("hash").toByteArray(); + + ticket_->Finish(cache->SaveCacheFrame(hash, frame), false); + break; + } + default: + // Fail + ticket_->Cancel(); + } +} + +DecoderPtr RenderProcessor::ResolveDecoderFromInput(StreamPtr stream) +{ + if (!stream) { + qWarning() << "Attempted to resolve the decoder of a null stream"; + return nullptr; + } + + QMutexLocker locker(decoder_cache_->mutex()); + + DecoderPtr decoder = decoder_cache_->value(stream.get()); + + if (!decoder) { + // No decoder + decoder = Decoder::CreateFromID(stream->footage()->decoder()); + + if (decoder->Open(stream)) { + decoder_cache_->insert(stream.get(), decoder); + } else { + qWarning() << "Failed to open decoder for" << stream->footage()->filename() + << "::" << stream->index(); + return nullptr; + } + } + + return decoder; +} + +void RenderProcessor::Process(RenderTicketPtr ticket, Renderer *render_ctx, StillImageCache *still_image_cache, DecoderCache *decoder_cache, ShaderCache *shader_cache, QVariant default_shader) +{ + RenderProcessor p(ticket, render_ctx, still_image_cache, decoder_cache, shader_cache, default_shader); + p.Run(); +} + +NodeValueTable RenderProcessor::GenerateBlockTable(const TrackOutput *track, const TimeRange &range) +{ + if (track->track_type() == Timeline::kTrackTypeAudio) { + + const AudioParams& audio_params = ticket_->property("aparam").value(); + + QList active_blocks = track->BlocksAtTimeRange(range); + + // All these blocks will need to output to a buffer so we create one here + SampleBufferPtr block_range_buffer = SampleBuffer::CreateAllocated(audio_params, + audio_params.time_to_samples(range.length())); + block_range_buffer->fill(0); + + NodeValueTable merged_table; + + // Loop through active blocks retrieving their audio + foreach (Block* b, active_blocks) { + TimeRange range_for_block(qMax(b->in(), range.in()), + qMin(b->out(), range.out())); + + int destination_offset = audio_params.time_to_samples(range_for_block.in() - range.in()); + int max_dest_sz = audio_params.time_to_samples(range_for_block.length()); + + // Destination buffer + NodeValueTable table = GenerateTable(b, range_for_block); + SampleBufferPtr samples_from_this_block = table.Take(NodeParam::kSamples).value(); + + if (!samples_from_this_block) { + // If we retrieved no samples from this block, do nothing + continue; + } + + // FIXME: Doesn't handle reversing + if (b->speed_input()->is_keyframing() || b->speed_input()->is_connected()) { + // FIXME: We'll need to calculate the speed hoo boy + } else { + double speed_value = b->speed_input()->get_standard_value().toDouble(); + + if (qIsNull(speed_value)) { + // Just silence, don't think there's any other practical application of 0 speed audio + samples_from_this_block->fill(0); + } else if (!qFuzzyCompare(speed_value, 1.0)) { + // Multiply time + samples_from_this_block->speed(speed_value); + } + } + + int copy_length = qMin(max_dest_sz, samples_from_this_block->sample_count()); + + // Copy samples into destination buffer + block_range_buffer->set(samples_from_this_block->const_data(), destination_offset, copy_length); + + NodeValueTable::Merge({merged_table, table}); + } + + if (ticket_->property("enablewaveforms").toBool()) { + // Generate a visual waveform and send it back to the main thread + AudioVisualWaveform visual_waveform; + visual_waveform.set_channel_count(audio_params.channel_count()); + visual_waveform.OverwriteSamples(block_range_buffer, audio_params.sample_rate()); + + RenderedWaveform waveform_info = {track, visual_waveform, range}; + QVector waveform_list = ticket_->property("waveforms").value< QVector >(); + waveform_list.append(waveform_info); + ticket_->setProperty("waveforms", QVariant::fromValue(waveform_list)); + } + + merged_table.Push(NodeParam::kSamples, QVariant::fromValue(block_range_buffer), track); + + return merged_table; + + } else { + return NodeTraverser::GenerateBlockTable(track, range); + } +} + +QVariant RenderProcessor::ProcessVideoFootage(StreamPtr stream, const rational &input_time) +{ + TexturePtr value = nullptr; + + // Check the still frame cache. On large frames such as high resolution still images, uploading + // and color managing them for every frame is a waste of time, so we implement a small cache here + // to optimize such a situation + VideoStreamPtr video_stream = std::static_pointer_cast(stream); + const VideoParams& video_params = ticket_->property("vparam").value(); + + ColorManager* color_manager = Node::ValueToPtr(ticket_->property("colormanager")); + + // See if we can make this divider larger (i.e. if the fooage is smaller) + int footage_divider = video_params.divider(); + while (footage_divider > 1 + && VideoParams::GetScaledDimension(video_stream->width(), footage_divider-1) < video_params.effective_width() + && VideoParams::GetScaledDimension(video_stream->height(), footage_divider-1) < video_params.effective_height()) { + footage_divider--; + } + + StillImageCache::EntryPtr want_entry = std::make_shared( + nullptr, + stream, + ColorProcessor::GenerateID(color_manager, video_stream->colorspace(), color_manager->GetReferenceColorSpace()), + video_stream->premultiplied_alpha(), + footage_divider, + (video_stream->video_type() == VideoStream::kVideoTypeStill) ? 0 : input_time, + true); + + bool found_existing = false; + + still_image_cache_->mutex()->lock(); + + foreach (StillImageCache::EntryPtr e, still_image_cache_->entries()) { + if (StillImageCache::CompareEntryMetadata(want_entry, e)) { + // Found an exact match of the texture we want in the cache. See if it's working or if it's + // ready. + want_entry = e; + found_existing = true; + + while (want_entry->working) { + still_image_cache_->wait_cond()->wait(still_image_cache_->mutex()); + } + + value = want_entry->texture; + break; + } + } + + if (value) { + // Found the texture, we can release the cache now + still_image_cache_->mutex()->unlock(); + } else { + // Wasn't in still image cache, so we'll have to retrieve it from the decoder + + // Let other processors know we're getting this texture (want_entry's `working` field is + // already set to true in the initializer above) + if (!found_existing) { + still_image_cache_->PushEntry(want_entry); + } + + still_image_cache_->mutex()->unlock(); + + DecoderPtr decoder = ResolveDecoderFromInput(stream); + + if (decoder) { + FramePtr frame = decoder->RetrieveVideo(input_time, + footage_divider); + + if (frame) { + // Return a texture from the derived class + TexturePtr unmanaged_texture = render_ctx_->CreateTexture(frame->video_params(), + frame->data(), + frame->linesize_pixels()); + + // We convert to our rendering pixel format, since that will always be float-based which + // is necessary for correct color conversion + VideoParams managed_params = frame->video_params(); + managed_params.set_format(video_params.format()); + value = render_ctx_->CreateTexture(managed_params); + + ColorProcessorPtr processor = ColorProcessor::Create(color_manager, + video_stream->colorspace(), + color_manager->GetReferenceColorSpace()); + + render_ctx_->BlitColorManaged(processor, unmanaged_texture, + video_stream->premultiplied_alpha(), + value.get()); + + still_image_cache_->mutex()->lock(); + + // Put this into the image cache instead + want_entry->texture = value; + want_entry->working = false; + + still_image_cache_->wait_cond()->wakeAll(); + + still_image_cache_->mutex()->unlock(); + } + } + } + + return QVariant::fromValue(value); +} + +QVariant RenderProcessor::ProcessAudioFootage(StreamPtr stream, const TimeRange &input_time) +{ + QVariant value; + + DecoderPtr decoder = ResolveDecoderFromInput(stream); + + if (decoder) { + const AudioParams& audio_params = ticket_->property("aparam").value(); + + SampleBufferPtr frame = decoder->RetrieveAudio(input_time, audio_params, &IsCancelled()); + + if (frame) { + value = QVariant::fromValue(frame); + } + } + + return value; +} + +QVariant RenderProcessor::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) +{ + Q_UNUSED(range) + + QString full_shader_id = QStringLiteral("%1:%2").arg(node->id(), job.GetShaderID()); + + QMutexLocker locker(shader_cache_->mutex()); + + QVariant shader = shader_cache_->value(full_shader_id); + + if (shader.isNull()) { + // Since we have shader code, compile it now + shader = render_ctx_->CreateNativeShader(node->GetShaderCode(job.GetShaderID())); + + if (shader.isNull()) { + // Couldn't find or build the shader required + return QVariant(); + } + } + + VideoParams tex_params = ticket_->property("vparam").value(); + + bool input_textures_have_alpha = false; + for (auto it=job.GetValues().cbegin(); it!=job.GetValues().cend(); it++) { + if (it.value().type == NodeParam::kTexture) { + TexturePtr tex = it.value().data.value(); + if (tex && tex->channel_count() == VideoParams::kRGBAChannelCount) { + input_textures_have_alpha = true; + break; + } + } + } + + if (input_textures_have_alpha || job.GetAlphaChannelRequired()) { + tex_params.set_channel_count(VideoParams::kRGBAChannelCount); + } else { + tex_params.set_channel_count(VideoParams::kRGBChannelCount); + } + + TexturePtr destination = render_ctx_->CreateTexture(tex_params); + + // Run shader + render_ctx_->BlitToTexture(shader, job, destination.get()); + + return QVariant::fromValue(destination); +} + +QVariant RenderProcessor::ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) +{ + if (!job.samples() || !job.samples()->is_allocated()) { + return QVariant(); + } + + SampleBufferPtr output_buffer = SampleBuffer::CreateAllocated(job.samples()->audio_params(), job.samples()->sample_count()); + NodeValueDatabase value_db; + + const AudioParams& audio_params = ticket_->property("aparam").value(); + + for (int i=0;isample_count();i++) { + // Calculate the exact rational time at this sample + double sample_to_second = static_cast(i) / static_cast(audio_params.sample_rate()); + + rational this_sample_time = rational::fromDouble(range.in().toDouble() + sample_to_second); + + // Update all non-sample and non-footage inputs + NodeValueMap::const_iterator j; + for (j=job.GetValues().constBegin(); j!=job.GetValues().constEnd(); j++) { + NodeValueTable value; + NodeInput* corresponding_input = node->GetInputWithID(j.key()); + + if (corresponding_input) { + value = ProcessInput(corresponding_input, TimeRange(this_sample_time, this_sample_time)); + } else { + value.Push(j.value(), node); + } + + value_db.Insert(j.key(), value); + } + + AddGlobalsToDatabase(value_db, TimeRange(this_sample_time, this_sample_time)); + + node->ProcessSamples(value_db, + job.samples(), + output_buffer, + i); + } + + return QVariant::fromValue(output_buffer); +} + +QVariant RenderProcessor::ProcessFrameGeneration(const Node *node, const GenerateJob &job) +{ + FramePtr frame = Frame::Create(); + + VideoParams frame_params = ticket_->property("vparam").value(); + if (job.GetAlphaChannelRequired()) { + frame_params.set_channel_count(VideoParams::kRGBAChannelCount); + } else { + frame_params.set_channel_count(VideoParams::kRGBChannelCount); + } + + frame->set_video_params(frame_params); + frame->allocate(); + + node->GenerateFrame(frame, job); + + TexturePtr texture = render_ctx_->CreateTexture(frame->video_params(), + frame->data(), + frame->linesize_pixels()); + + return QVariant::fromValue(texture); +} + +QVariant RenderProcessor::GetCachedFrame(const Node *node, const rational &time) +{ + if (!ticket_->property("cache").toString().isEmpty() + && node->id() == QStringLiteral("org.olivevideoeditor.Olive.videoinput")) { + const VideoParams& video_params = ticket_->property("vparam").value(); + + QByteArray hash = RenderManager::Hash(node, video_params, time); + + FramePtr f = FrameHashCache::LoadCacheFrame(ticket_->property("cache").toString(), hash); + + if (f) { + // The cached frame won't load with the correct divider by default, so we enforce it here + VideoParams p = f->video_params(); + + p.set_width(f->width() * video_params.divider()); + p.set_height(f->height() * video_params.divider()); + p.set_divider(video_params.divider()); + + f->set_video_params(p); + + TexturePtr texture = render_ctx_->CreateTexture(f->video_params(), f->data(), f->linesize_pixels()); + return QVariant::fromValue(texture); + } + } + + return QVariant(); +} + +QVector2D RenderProcessor::GenerateResolution() const +{ + // Set resolution to the destination to the "logical" resolution of the destination + const VideoParams& video_params = ticket_->property("vparam").value(); + return QVector2D(video_params.width() * video_params.pixel_aspect_ratio().toDouble(), + video_params.height()); +} + +} diff --git a/app/render/renderprocessor.h b/app/render/renderprocessor.h new file mode 100644 index 000000000..c9df7d109 --- /dev/null +++ b/app/render/renderprocessor.h @@ -0,0 +1,85 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 RENDERPROCESSOR_H +#define RENDERPROCESSOR_H + +#include "node/traverser.h" +#include "render/renderer.h" +#include "rendercache.h" +#include "stillimagecache.h" +#include "threading/threadticket.h" + +namespace olive { + +class RenderProcessor : public NodeTraverser +{ +public: + static void Process(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache, ShaderCache* shader_cache, QVariant default_shader); + + struct RenderedWaveform { + const TrackOutput* track; + AudioVisualWaveform waveform; + TimeRange range; + }; + +protected: + virtual NodeValueTable GenerateBlockTable(const TrackOutput *track, const TimeRange &range) override; + + virtual QVariant ProcessVideoFootage(StreamPtr stream, const rational &input_time) override; + + virtual QVariant ProcessAudioFootage(StreamPtr stream, const TimeRange &input_time) override; + + virtual QVariant ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job) override; + + virtual QVariant ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) override; + + virtual QVariant ProcessFrameGeneration(const Node *node, const GenerateJob& job) override; + + virtual QVariant GetCachedFrame(const Node *node, const rational &time) override; + + virtual QVector2D GenerateResolution() const override; + +private: + RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache, ShaderCache* shader_cache, QVariant default_shader); + + void Run(); + + DecoderPtr ResolveDecoderFromInput(StreamPtr stream); + + RenderTicketPtr ticket_; + + Renderer* render_ctx_; + + StillImageCache* still_image_cache_; + + DecoderCache* decoder_cache_; + + ShaderCache* shader_cache_; + + QVariant default_shader_; + +}; + +} + +Q_DECLARE_METATYPE(olive::RenderProcessor::RenderedWaveform) + +#endif // RENDERPROCESSOR_H diff --git a/app/render/shadercode.h b/app/render/shadercode.h new file mode 100644 index 000000000..1042c5c02 --- /dev/null +++ b/app/render/shadercode.h @@ -0,0 +1,62 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 SHADERCODE_H +#define SHADERCODE_H + +#include "common/filefunctions.h" + +namespace olive { + +class ShaderCode { +public: + ShaderCode(const QString& frag_code = QString(), const QString& vert_code = QString()) : + frag_code_(frag_code), + vert_code_(vert_code) + { + if (frag_code_.isEmpty()) { + frag_code_ = FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.frag")); + } + + if (vert_code_.isEmpty()) { + vert_code_ = FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.vert")); + } + } + + const QString& frag_code() const + { + return frag_code_; + } + + const QString& vert_code() const + { + return vert_code_; + } + +private: + QString frag_code_; + + QString vert_code_; + +}; + +} + +#endif // SHADERCODE_H diff --git a/app/render/shaderinfo.h b/app/render/shaderinfo.h deleted file mode 100644 index 1fa685e2b..000000000 --- a/app/render/shaderinfo.h +++ /dev/null @@ -1,193 +0,0 @@ -#ifndef SHADERINFO_H -#define SHADERINFO_H - -#include "codec/samplebuffer.h" -#include "node/input.h" -#include "node/inputarray.h" -#include "node/value.h" - -OLIVE_NAMESPACE_ENTER - -using NodeValueMap = QHash; - -class AcceleratedJob { -public: - AcceleratedJob() = default; - - NodeValue GetValue(NodeInput* input) const - { - return value_map_.value(input->id()); - } - - NodeValue GetValue(const QString& input) const - { - return value_map_.value(input); - } - - void InsertValue(NodeInput* input, NodeValueDatabase& value) - { - if (input->IsArray()) { - NodeInputArray* array = static_cast(input); - QVector values(array->GetSize()); - - for (int j=0;jGetSize();j++) { - NodeInput* subparam = array->At(j); - - values[j] = value[subparam].TakeWithMeta(subparam->data_type()); - } - - InsertValue(input->id(), NodeValue(NodeParam::kVec2, QVariant::fromValue(values), input->parentNode())); - } else { - InsertValue(input->id(), value[input].TakeWithMeta(input->data_type())); - } - } - - void InsertValue(const QString& input, const NodeValue& value) - { - value_map_.insert(input, value); - } - - void InsertValue(NodeInput* input, const NodeValue& value) - { - value_map_.insert(input->id(), value); - } - - const NodeValueMap &GetValues() const - { - return value_map_; - } - -private: - NodeValueMap value_map_; - -}; - -class SampleJob : public AcceleratedJob { -public: - SampleJob() - { - samples_ = nullptr; - } - - SampleJob(const NodeValue& value) - { - samples_ = value.data().value(); - } - - SampleJob(NodeInput* from, NodeValueDatabase& db) - { - samples_ = db[from].Take(NodeParam::kSamples).value(); - } - - SampleBufferPtr samples() const - { - return samples_; - } - - bool HasSamples() const - { - return samples_ && samples_->is_allocated(); - } - -private: - SampleBufferPtr samples_; - -}; - -class GenerateJob : public AcceleratedJob { -public: - GenerateJob() - { - alpha_channel_required_ = false; - } - - bool GetAlphaChannelRequired() const - { - return alpha_channel_required_; - } - - void SetAlphaChannelRequired(bool e) - { - alpha_channel_required_ = e; - } - -private: - bool alpha_channel_required_; - -}; - -class ShaderJob : public GenerateJob { -public: - ShaderJob() - { - iterations_ = 1; - iterative_input_ = nullptr; - } - - const QString& GetShaderID() const - { - return id_; - } - - void SetShaderID(const QString& id) - { - id_ = id; - } - - void SetIterations(int iterations, NodeInput* iterative_input) - { - iterations_ = iterations; - iterative_input_ = iterative_input; - } - - int GetIterationCount() const - { - return iterations_; - } - - NodeInput* GetIterativeInput() const - { - return iterative_input_; - } - -private: - QString id_; - - int iterations_; - - NodeInput* iterative_input_; - -}; - -class ShaderCode { -public: - ShaderCode(const QString& frag_code, const QString& vert_code) : - frag_code_(frag_code), - vert_code_(vert_code) - { - } - - const QString& frag_code() const - { - return frag_code_; - } - - const QString& vert_code() const - { - return vert_code_; - } - -private: - QString frag_code_; - - QString vert_code_; - -}; - -OLIVE_NAMESPACE_EXIT - -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::ShaderJob) -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::SampleJob) -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::GenerateJob) - -#endif // SHADERINFO_H diff --git a/app/render/shadervalue.h b/app/render/shadervalue.h new file mode 100644 index 000000000..0b042173b --- /dev/null +++ b/app/render/shadervalue.h @@ -0,0 +1,55 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 SHADERVALUE_H +#define SHADERVALUE_H + +#include "node/param.h" + +namespace olive { + +struct ShaderValue +{ + ShaderValue() + { + type = NodeParam::kNone; + array = false; + } + + ShaderValue(QVariant data_in, NodeParam::DataType type_in, bool array_in = false) + { + data = data_in; + type = type_in; + array = array_in; + } + + NodeParam::DataType type; + QVariant data; + bool array; + + QString tag; + +}; + +using NodeValueMap = QHash; + +} + +#endif // SHADERVALUE_H diff --git a/app/render/stillimagecache.h b/app/render/stillimagecache.h new file mode 100644 index 000000000..728247200 --- /dev/null +++ b/app/render/stillimagecache.h @@ -0,0 +1,83 @@ +#ifndef STILLIMAGECACHE_H +#define STILLIMAGECACHE_H + +#include +#include + +#include "common/rational.h" +#include "project/item/footage/stream.h" +#include "render/texture.h" + +namespace olive { + +class StillImageCache +{ +public: + struct Entry { + Entry(TexturePtr t, StreamPtr s, const QString& cs, bool a, int d, const rational& i, bool w) + { + texture = t; + stream = s; + colorspace = cs; + alpha_is_associated = a; + divider = d; + time = i; + working = w; + } + + TexturePtr texture; + StreamPtr stream; + QString colorspace; + bool alpha_is_associated; + int divider; + rational time; + bool working; + }; + + using EntryPtr = std::shared_ptr; + + QMutex* mutex() + { + return &mutex_; + } + + QWaitCondition* wait_cond() + { + return &wait_cond_; + } + + const QVector& entries() const + { + return entries_; + } + + static bool CompareEntryMetadata(EntryPtr a, EntryPtr b) + { + return (a->stream == b->stream + && a->colorspace == b->colorspace + && a->alpha_is_associated == b->alpha_is_associated + && a->divider == b->divider + && a->time == b->time); + } + + void PushEntry(EntryPtr e) + { + entries_.prepend(e); + + if (entries_.size() > 8) { + entries_.removeLast(); + } + } + +private: + QMutex mutex_; + + QWaitCondition wait_cond_; + + QVector entries_; + +}; + +} + +#endif // STILLIMAGECACHE_H diff --git a/app/render/backend/opengl/openglbackend.h b/app/render/texture.cpp similarity index 62% rename from app/render/backend/opengl/openglbackend.h rename to app/render/texture.cpp index 7d88611f3..c6ed11e6f 100644 --- a/app/render/backend/opengl/openglbackend.h +++ b/app/render/texture.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -18,26 +18,22 @@ ***/ -#ifndef OPENGLBACKEND_H -#define OPENGLBACKEND_H +#include "texture.h" -#include "openglproxy.h" -#include "render/backend/renderbackend.h" +#include "renderer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -class OpenGLBackend : public RenderBackend +const Texture::Interpolation Texture::kDefaultInterpolation = Texture::kMipmappedLinear; + +Texture::~Texture() { -public: - OpenGLBackend(QObject* parent = nullptr); + renderer_->DestroyNativeTexture(id_); +} - virtual ~OpenGLBackend() override; +void Texture::Upload(void *data, int linesize) +{ + renderer_->UploadToTexture(this, data, linesize); +} -protected: - virtual RenderWorker* CreateNewWorker() override; - -}; - -OLIVE_NAMESPACE_EXIT - -#endif // OPENGLBACKEND_H +} diff --git a/app/render/texture.h b/app/render/texture.h new file mode 100644 index 000000000..e0d9500f3 --- /dev/null +++ b/app/render/texture.h @@ -0,0 +1,122 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 RENDERTEXTURE_H +#define RENDERTEXTURE_H + +#include + +#include "render/videoparams.h" + +namespace olive { + +class Renderer; + +class Texture +{ +public: + enum Type { + k2D, + k3D + }; + + enum Interpolation { + kNearest, + kLinear, + kMipmappedLinear + }; + + static const Interpolation kDefaultInterpolation; + + Texture(Renderer* renderer, const QVariant& native, const VideoParams& param, Type type) : + renderer_(renderer), + params_(param), + id_(native), + type_(type) + { + } + + ~Texture(); + + QVariant id() const + { + return id_; + } + + const VideoParams& params() const + { + return params_; + } + + void Upload(void* data, int linesize); + + int width() const + { + return params_.effective_width(); + } + + int height() const + { + return params_.effective_height(); + } + + VideoParams::Format format() const + { + return params_.format(); + } + + int channel_count() const + { + return params_.channel_count(); + } + + int divider() const + { + return params_.divider(); + } + + const rational& pixel_aspect_ratio() const + { + return params_.pixel_aspect_ratio(); + } + + Type type() const + { + return type_; + } + +private: + Renderer* renderer_; + + VideoParams params_; + + QVariant id_; + + Type type_; + +}; + +using TexturePtr = std::shared_ptr; + +} + +Q_DECLARE_METATYPE(olive::TexturePtr) + +#endif // RENDERTEXTURE_H diff --git a/app/render/videoparams.cpp b/app/render/videoparams.cpp index 00167c63a..02f736344 100644 --- a/app/render/videoparams.cpp +++ b/app/render/videoparams.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,9 @@ #include "core.h" -OLIVE_NAMESPACE_ENTER +namespace olive { + +const int VideoParams::kInternalChannelCount = kRGBAChannelCount; const rational VideoParams::kPixelAspectSquare(1); const rational VideoParams::kPixelAspectNTSCStandard(8, 9); @@ -62,15 +64,19 @@ const QVector VideoParams::kStandardPixelAspects = { VideoParams::VideoParams() : width_(0), height_(0), - format_(PixelFormat::PIX_FMT_INVALID), + depth_(0), + format_(kFormatInvalid), + channel_count_(0), interlacing_(Interlacing::kInterlaceNone) { } -VideoParams::VideoParams(const int &width, const int &height, const PixelFormat::Format &format, const rational& pixel_aspect_ratio, const Interlacing &interlacing, const int& divider) : +VideoParams::VideoParams(int width, int height, Format format, int nb_channels, const rational& pixel_aspect_ratio, Interlacing interlacing, int divider) : width_(width), height_(height), + depth_(0), format_(format), + channel_count_(nb_channels), pixel_aspect_ratio_(pixel_aspect_ratio), interlacing_(interlacing), divider_(divider) @@ -79,11 +85,27 @@ VideoParams::VideoParams(const int &width, const int &height, const PixelFormat: validate_pixel_aspect_ratio(); } -VideoParams::VideoParams(const int &width, const int &height, const rational &time_base, const PixelFormat::Format &format, const rational& pixel_aspect_ratio, const Interlacing &interlacing, const int ÷r) : +VideoParams::VideoParams(int width, int height, int depth, Format format, int nb_channels, const rational &pixel_aspect_ratio, VideoParams::Interlacing interlacing, int divider) : width_(width), height_(height), + depth_(depth), + format_(format), + channel_count_(nb_channels), + pixel_aspect_ratio_(pixel_aspect_ratio), + interlacing_(interlacing), + divider_(divider) +{ + calculate_effective_size(); + validate_pixel_aspect_ratio(); +} + +VideoParams::VideoParams(int width, int height, const rational &time_base, Format format, int nb_channels, const rational& pixel_aspect_ratio, Interlacing interlacing, int divider) : + width_(width), + height_(height), + depth_(0), time_base_(time_base), format_(format), + channel_count_(nb_channels), pixel_aspect_ratio_(pixel_aspect_ratio), interlacing_(interlacing), divider_(divider) @@ -143,10 +165,69 @@ bool VideoParams::operator!=(const VideoParams &rhs) const return !(*this == rhs); } +int VideoParams::GetBytesPerChannel(VideoParams::Format format) +{ + switch (format) { + case kFormatInvalid: + case kFormatCount: + break; + case kFormatUnsigned8: + return 1; + case kFormatUnsigned16: + case kFormatFloat16: + return 2; + case kFormatFloat32: + return 4; + } + + return 0; +} + +int VideoParams::GetBytesPerPixel(VideoParams::Format format, int channels) +{ + return GetBytesPerChannel(format) * channels; +} + +bool VideoParams::FormatIsFloat(VideoParams::Format format) +{ + switch (format) { + case kFormatFloat16: + case kFormatFloat32: + return true; + case kFormatUnsigned8: + case kFormatUnsigned16: + case kFormatInvalid: + case kFormatCount: + break; + } + + return false; +} + +QString VideoParams::GetFormatName(VideoParams::Format format) +{ + switch (format) { + case kFormatUnsigned8: + return QCoreApplication::translate("VideoParams", "8-bit"); + case kFormatUnsigned16: + return QCoreApplication::translate("VideoParams", "16-bit Integer"); + case kFormatFloat16: + return QCoreApplication::translate("VideoParams", "Half-Float (16-bit)"); + case kFormatFloat32: + return QCoreApplication::translate("VideoParams", "Full-Float (32-bit)"); + case kFormatInvalid: + case kFormatCount: + break; + } + + return QCoreApplication::translate("VideoParams", "Unknown (0x%1)").arg(format, 0, 16); +} + void VideoParams::calculate_effective_size() { effective_width_ = GetScaledDimension(width(), divider_); effective_height_ = GetScaledDimension(height(), divider_); + effective_depth_ = GetScaledDimension(depth(), divider_); } void VideoParams::validate_pixel_aspect_ratio() @@ -161,8 +242,8 @@ bool VideoParams::is_valid() const return (width() > 0 && height() > 0 && !pixel_aspect_ratio_.isNull() - && format_ != PixelFormat::PIX_FMT_INVALID - && format_ != PixelFormat::PIX_FMT_COUNT); + && format_ > kFormatInvalid && format_ < kFormatCount + && channel_count_ > 0); } QString VideoParams::FrameRateToString(const rational &frame_rate) @@ -196,7 +277,7 @@ QString VideoParams::FormatPixelAspectRatioString(const QString &format, const r int VideoParams::GetScaledDimension(int dim, int divider) { - return qCeil(dim / divider * 0.5) * 2; + return dim / divider; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/render/videoparams.h b/app/render/videoparams.h index fa24e2027..d38626491 100644 --- a/app/render/videoparams.h +++ b/app/render/videoparams.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,13 +22,35 @@ #define VIDEOPARAMS_H #include "common/rational.h" -#include "pixelformat.h" #include "rendermodes.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class VideoParams { public: + enum Format { + /// Invalid or no format + kFormatInvalid = -1, + + /// 8-bit unsigned integer + kFormatUnsigned8, + + /// 16-bit unsigned integer + kFormatUnsigned16, + + /// 16-bit half float + kFormatFloat16, + + /// 32-bit full float + kFormatFloat32, + + /// 64-bit double float - disabled since very, very few libs support 64-bit buffers + //kFormatFloat64, + + /// Total format count + kFormatCount + }; + enum Interlacing { kInterlaceNone, kInterlacedTopFirst, @@ -36,58 +58,128 @@ public: }; VideoParams(); - VideoParams(const int& width, const int& height, const PixelFormat::Format& format, + VideoParams(int width, int height, Format format, int nb_channels, const rational& pixel_aspect_ratio = 1, - const Interlacing& interlacing = kInterlaceNone, const int& divider = 1); - VideoParams(const int& width, const int& height, const rational& time_base, - const PixelFormat::Format& format, const rational& pixel_aspect_ratio = 1, - const Interlacing& interlacing = kInterlaceNone, const int& divider = 1); + Interlacing interlacing = kInterlaceNone, int divider = 1); + VideoParams(int width, int height, int depth, + Format format, int nb_channels, + const rational& pixel_aspect_ratio = 1, + Interlacing interlacing = kInterlaceNone, int divider = 1); + VideoParams(int width, int height, const rational& time_base, + Format format, int nb_channels, + const rational& pixel_aspect_ratio = 1, + Interlacing interlacing = kInterlaceNone, int divider = 1); - const int& width() const + int width() const { return width_; } - const int& height() const + void set_width(int width) + { + width_ = width; + calculate_effective_size(); + } + + int height() const { return height_; } + void set_height(int height) + { + height_ = height; + calculate_effective_size(); + } + + int depth() const + { + return depth_; + } + + void set_depth(int depth) + { + depth_ = depth; + calculate_effective_size(); + } + const rational& time_base() const { return time_base_; } - const int& divider() const + void set_time_base(const rational& r) + { + time_base_ = r; + } + + int divider() const { return divider_; } - const int& effective_width() const + void set_divider(int d) + { + divider_ = d; + calculate_effective_size(); + } + + int effective_width() const { return effective_width_; } - const int& effective_height() const + int effective_height() const { return effective_height_; } - const PixelFormat::Format& format() const + int effective_depth() const + { + return effective_depth_; + } + + Format format() const { return format_; } + void set_format(Format f) + { + format_ = f; + } + + int channel_count() const + { + return channel_count_; + } + + void set_channel_count(int c) + { + channel_count_ = c; + } + const rational& pixel_aspect_ratio() const { return pixel_aspect_ratio_; } + void set_pixel_aspect_ratio(const rational& r) + { + pixel_aspect_ratio_ = r; + validate_pixel_aspect_ratio(); + } + Interlacing interlacing() const { return interlacing_; } + void set_interlacing(Interlacing i) + { + interlacing_ = i; + } + static int generate_auto_divider(qint64 width, qint64 height); bool is_valid() const; @@ -95,6 +187,33 @@ public: bool operator==(const VideoParams& rhs) const; bool operator!=(const VideoParams& rhs) const; + static int GetBytesPerChannel(Format format); + int GetBytesPerChannel() const + { + return GetBytesPerChannel(format_); + } + + static int GetBytesPerPixel(Format format, int channels); + int GetBytesPerPixel() const + { + return GetBytesPerPixel(format_, channel_count_); + } + + static int GetBufferSize(int width, int height, Format format, int channels) + { + return width * height * GetBytesPerPixel(format, channels); + } + int GetBufferSize() const + { + return GetBufferSize(width_, height_, format_, channel_count_); + } + + static bool FormatIsFloat(Format format); + + static QString GetFormatName(Format format); + + static const int kInternalChannelCount; + static const rational kPixelAspectSquare; static const rational kPixelAspectNTSCStandard; static const rational kPixelAspectNTSCWidescreen; @@ -106,6 +225,10 @@ public: static const QVector kStandardPixelAspects; static const QVector kSupportedDividers; + static const int kHSVChannelCount = 3; + static const int kRGBChannelCount = 3; + static const int kRGBAChannelCount = 4; + /** * @brief Convert rational frame rate (i.e. flipped timebase) to a user-friendly string */ @@ -123,9 +246,12 @@ private: int width_; int height_; + int depth_; rational time_base_; - PixelFormat::Format format_; + Format format_; + + int channel_count_; rational pixel_aspect_ratio_; @@ -134,11 +260,12 @@ private: int divider_; int effective_width_; int effective_height_; + int effective_depth_; }; -OLIVE_NAMESPACE_EXIT +} -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::VideoParams) -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::VideoParams::Interlacing) +Q_DECLARE_METATYPE(olive::VideoParams) +Q_DECLARE_METATYPE(olive::VideoParams::Interlacing) #endif // VIDEOPARAMS_H diff --git a/app/shaders/CMakeLists.txt b/app/shaders/CMakeLists.txt index a9ad28c12..78845347e 100644 --- a/app/shaders/CMakeLists.txt +++ b/app/shaders/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/shaders/alphaover.frag b/app/shaders/alphaover.frag index 5af27f1bb..3411ad3d3 100644 --- a/app/shaders/alphaover.frag +++ b/app/shaders/alphaover.frag @@ -1,5 +1,3 @@ -#version 150 - uniform sampler2D base_in; uniform sampler2D blend_in; uniform bool base_in_enabled; diff --git a/app/shaders/blur.frag b/app/shaders/blur.frag index 4dc2e0566..dcb0bf253 100644 --- a/app/shaders/blur.frag +++ b/app/shaders/blur.frag @@ -1,13 +1,11 @@ -#version 150 - uniform sampler2D tex_in; uniform int method_in; uniform float radius_in; uniform bool horiz_in; uniform bool vert_in; uniform bool repeat_edge_pixels_in; +uniform vec2 resolution_in; -uniform vec2 ove_resolution; uniform int ove_iteration; in vec2 ove_texcoord; @@ -109,9 +107,9 @@ void main(void) { vec2 pixel_coord = ove_texcoord; if (mode == MODE_HORIZONTAL) { - pixel_coord.x += i / ove_resolution.x; + pixel_coord.x += i / resolution_in.x; } else if (mode == MODE_VERTICAL) { - pixel_coord.y += i / ove_resolution.y; + pixel_coord.y += i / resolution_in.y; } if (repeat_edge_pixels_in diff --git a/app/shaders/colorgradient.frag b/app/shaders/colorgradient.frag deleted file mode 100644 index 1d4a2d3b5..000000000 --- a/app/shaders/colorgradient.frag +++ /dev/null @@ -1,28 +0,0 @@ -#version 150 - -// Inputs -uniform int orientation; -uniform vec3 color_a; -uniform vec3 color_b; - -// Standard inputs -uniform vec2 ove_resolution; - -in vec2 ove_texcoord; - -out vec4 fragColor; - -void main(void) { - float t; - - // This very roughly conforms to Qt::Orientation - if (orientation == 1) { - // Horizontal orientation - t = ove_texcoord.x; - } else { - // Vertical orientation - t = 1.0 - ove_texcoord.y; - } - - fragColor = vec4(mix(color_a, color_b, t), 1.0); -} diff --git a/app/shaders/colorwheel.frag b/app/shaders/colorwheel.frag deleted file mode 100644 index 2a891a243..000000000 --- a/app/shaders/colorwheel.frag +++ /dev/null @@ -1,94 +0,0 @@ -#version 150 - -// Custom inputs -uniform float hsv_value; - -// Standard inputs -uniform vec2 ove_resolution; - -in vec2 ove_texcoord; - -out vec4 fragColor; - -// Color wheel uses PI -#define M_PI 3.1415926535897932384626433832795 - -vec3 hsv_to_rgb(float H, float S, float V) { - float C = S * V; - float X = C * (1.0 - abs(mod(H / 60.0, 2.0) - 1.0)); - float m = V - C; - float Rs, Gs, Bs; - - if(H >= 0.0 && H < 60.0) { - Rs = C; - Gs = X; - Bs = 0.0; - } - else if(H >= 60.0 && H < 120.0) { - Rs = X; - Gs = C; - Bs = 0.0; - } - else if(H >= 120.0 && H < 180.0) { - Rs = 0.0; - Gs = C; - Bs = X; - } - else if(H >= 180.0 && H < 240.0) { - Rs = 0.0; - Gs = X; - Bs = C; - } - else if(H >= 240.0 && H < 300.0) { - Rs = X; - Gs = 0.0; - Bs = C; - } - else { - Rs = C; - Gs = 0.0; - Bs = X; - } - - return vec3(Rs + m, Gs + m, Bs + m); -} - -void main(void) { - vec2 center = vec2(0.5, 0.5); - float radius = 0.5; - - vec2 flipped_texcoord = vec2(ove_texcoord.x, (1.0 - ove_texcoord.y)); - - // Calculate scale - if (ove_resolution.x != ove_resolution.y) { - // Scale around center - flipped_texcoord -= vec2(0.5, 0.5); - - if (ove_resolution.x > ove_resolution.y) { - flipped_texcoord.x *= ove_resolution.x / ove_resolution.y; - } else { - flipped_texcoord.y *= ove_resolution.y / ove_resolution.x; - } - - flipped_texcoord += vec2(0.5, 0.5); - } - - float dist = distance(flipped_texcoord, center); - - if (dist <= radius) { - float opposite = flipped_texcoord.y - center.y; - float adjacent = flipped_texcoord.x - center.x; - - float hue = atan(opposite, adjacent) * 180.0 / M_PI + 180.0; - float sat = dist / radius; - - // Extremely simple antialiasing, we taper off the edges between (radius) and (radius - 1) - float pixel_radius = min(ove_resolution.x, ove_resolution.y) * 0.5; - float pixel_dist = (pixel_radius / radius) * dist; - float alpha = min((pixel_radius - pixel_dist), 1.0); - - fragColor = vec4(hsv_to_rgb(hue, sat, hsv_value), alpha); - } else { - fragColor = vec4(0.0); - } -} diff --git a/app/shaders/crop.frag b/app/shaders/crop.frag new file mode 100644 index 000000000..22248e0ef --- /dev/null +++ b/app/shaders/crop.frag @@ -0,0 +1,55 @@ +// Input variables +uniform sampler2D tex_in; +uniform float left_in; +uniform float top_in; +uniform float right_in; +uniform float bottom_in; +uniform float feather_in; +uniform vec2 resolution_in; + +// Input texture coordinate +in vec2 ove_texcoord; + +// Output color +out vec4 fragColor; + +void main() { + float multiplier = 1.0; + + vec2 feather_normalized = vec2(feather_in / resolution_in.x, feather_in / resolution_in.y); + vec2 feather_normalized_half = feather_normalized * 0.5; + + // Calculate left cropping + float left_adjustment; + float right_adjustment; + float top_adjustment; + float bottom_adjustment; + + if (feather_in == 0.0) { + if (ove_texcoord.x < left_in + || ove_texcoord.x > (1.0-right_in) + || ove_texcoord.y < (top_in) + || ove_texcoord.y > (1.0-bottom_in)) { + multiplier = 0.0; + } + } else { + float left_adjustment = clamp((ove_texcoord.x - (left_in - feather_normalized.x*(1.0-left_in))) / feather_normalized.x, 0.0, 1.0); + multiplier *= left_adjustment; + + float right_adjustment = 1.0-clamp((ove_texcoord.x - ((1.0-right_in) - feather_normalized.x*(right_in))) / feather_normalized.x, 0.0, 1.0); + multiplier *= right_adjustment; + + float top_adjustment = clamp((ove_texcoord.y - (top_in - feather_normalized.y*(1.0-top_in))) / feather_normalized.y, 0.0, 1.0); + multiplier *= top_adjustment; + + float bottom_adjustment = 1.0-clamp((ove_texcoord.y - ((1.0-bottom_in) - feather_normalized.y*(bottom_in))) / feather_normalized.y, 0.0, 1.0); + multiplier *= bottom_adjustment; + } + + if (multiplier > 0.0) { + vec4 color = texture(tex_in, ove_texcoord) * multiplier; + fragColor = color; + } else { + fragColor = vec4(0.0); + } +} diff --git a/app/shaders/crossdissolve.frag b/app/shaders/crossdissolve.frag index e9461244c..66152486b 100644 --- a/app/shaders/crossdissolve.frag +++ b/app/shaders/crossdissolve.frag @@ -1,5 +1,3 @@ -#version 150 - #define LINEAR_CURVE 0 #define EXPONENTIAL_CURVE 1 #define LOGARITHMIC_CURVE 2 diff --git a/app/shaders/default.frag b/app/shaders/default.frag new file mode 100644 index 000000000..2a6a46b9e --- /dev/null +++ b/app/shaders/default.frag @@ -0,0 +1,13 @@ +// Input texture +uniform sampler2D ove_maintex; + +// Input texture coordinate +in vec2 ove_texcoord; + +// Output color +out vec4 fragColor; + +void main() { + vec4 color = texture(ove_maintex, ove_texcoord); + fragColor = color; +} diff --git a/app/shaders/default.vert b/app/shaders/default.vert new file mode 100644 index 000000000..eda14fb70 --- /dev/null +++ b/app/shaders/default.vert @@ -0,0 +1,11 @@ +uniform mat4 ove_mvpmat; + +in vec4 a_position; +in vec2 a_texcoord; + +out vec2 ove_texcoord; + +void main() { + gl_Position = ove_mvpmat * a_position; + ove_texcoord = a_texcoord; +} \ No newline at end of file diff --git a/app/shaders/deinterlace.frag b/app/shaders/deinterlace.frag new file mode 100644 index 000000000..45104a145 --- /dev/null +++ b/app/shaders/deinterlace.frag @@ -0,0 +1,20 @@ +uniform sampler2D ove_maintex; + +uniform vec2 resolution_in; + +in vec2 ove_texcoord; + +out vec4 fragColor; + +void main() { + vec2 using_texcoord = ove_texcoord; + + // A very basic deinterlace that halves the vertical + // resolution and linearly interpolates the two fields + // by reading the texture coord between them. + float half_vert = round(resolution_in.y / 2.0); + using_texcoord.y = (round(using_texcoord.y * half_vert) + 0.25) / half_vert; + + vec4 color = texture(ove_maintex, using_texcoord); + fragColor = color; +} diff --git a/app/shaders/diptoblack.frag b/app/shaders/diptoblack.frag index b6e89dad3..1238a7b85 100644 --- a/app/shaders/diptoblack.frag +++ b/app/shaders/diptoblack.frag @@ -1,5 +1,3 @@ -#version 150 - uniform sampler2D out_block_in; uniform sampler2D in_block_in; uniform bool out_block_in_enabled; diff --git a/app/shaders/matrix.vert b/app/shaders/matrix.vert deleted file mode 100644 index dcfc4741f..000000000 --- a/app/shaders/matrix.vert +++ /dev/null @@ -1,37 +0,0 @@ -#version 150 - -uniform mat4 %1; - -uniform vec2 %2_resolution; -uniform vec2 ove_resolution; - -in vec4 a_position; -in vec2 a_texcoord; - -out vec2 ove_texcoord; - -mat4 scale_mat4(vec3 scale) { - return mat4( - scale.x, 0.0, 0.0, 0.0, - 0.0, scale.y, 0.0, 0.0, - 0.0, 0.0, scale.z, 0.0, - 0.0, 0.0, 0.0, 1.0 - ); -} - -void main() { - // Create identity matrix - mat4 transform = mat4(1.0); - - // Scale to square - transform *= scale_mat4(vec3(1.0 / ove_resolution, 1.0)); - - // Multiply by received matrix - transform *= %1; - - // Scale back out to footage size - transform *= scale_mat4(vec3(%2_resolution, 1.0)); - - gl_Position = transform * a_position; - ove_texcoord = a_texcoord; -} diff --git a/app/shaders/mosaic.frag b/app/shaders/mosaic.frag new file mode 100644 index 000000000..6169d9d62 --- /dev/null +++ b/app/shaders/mosaic.frag @@ -0,0 +1,31 @@ +// Input texture +uniform sampler2D tex_in; + +uniform float horiz_in; +uniform float vert_in; + +// Input texture coordinate +in vec2 ove_texcoord; + +// Output color +out vec4 fragColor; + +void main() { + float x; + float y; + + if (horiz_in > 0.0) { + x = floor(ove_texcoord.x * horiz_in) / horiz_in; + } else { + x = ove_texcoord.x; + } + + if (vert_in > 0.0) { + y = floor(ove_texcoord.y * vert_in) / vert_in; + } else { + y = ove_texcoord.y; + } + + vec4 color = texture(tex_in, vec2(x, y)); + fragColor = color; +} diff --git a/app/shaders/polygon.frag b/app/shaders/polygon.frag index ae45ddf73..b5fa0fed1 100644 --- a/app/shaders/polygon.frag +++ b/app/shaders/polygon.frag @@ -1,10 +1,8 @@ -#version 150 - uniform vec2[256] points_in; uniform int points_in_count; uniform vec4 color_in; -uniform vec2 ove_resolution; +uniform vec2 resolution_in; in vec2 ove_texcoord; @@ -36,7 +34,7 @@ bool pnpoly(vec2 p) { } void main(void) { - if (points_in_count > 0 && pnpoly(ove_texcoord * ove_resolution)) { + if (points_in_count > 0 && pnpoly(ove_texcoord * resolution_in)) { fragColor = color_in; } else { fragColor = vec4(0.0, 0.0, 0.0, 0.0); diff --git a/app/shaders/rgbhistogram.frag b/app/shaders/rgbhistogram.frag index 435949138..25471dc6e 100644 --- a/app/shaders/rgbhistogram.frag +++ b/app/shaders/rgbhistogram.frag @@ -1,9 +1,5 @@ -#version 150 - uniform sampler2D ove_maintex; -uniform vec2 ove_resolution; -uniform vec2 ove_viewport; - +uniform vec2 viewport; uniform float histogram_scale; in vec2 ove_texcoord; @@ -11,7 +7,7 @@ in vec2 ove_texcoord; out vec4 fragColor; void main(void) { - float histogram_width = ceil(histogram_scale * ove_viewport.y); + float histogram_width = ceil(histogram_scale * viewport.y); float quantisation = 1.0 / (histogram_width - 1.0); vec3 cur_col = vec3(0.0); vec3 sum = vec3(0.0); diff --git a/app/shaders/rgbhistogram.vert b/app/shaders/rgbhistogram.vert index 92536144c..44100df79 100644 --- a/app/shaders/rgbhistogram.vert +++ b/app/shaders/rgbhistogram.vert @@ -1,7 +1,4 @@ -#version 150 - uniform float histogram_scale; -uniform vec2 ove_resolution; in vec4 a_position; in vec2 a_texcoord; @@ -26,4 +23,4 @@ void main() { gl_Position = transform * a_position; ove_texcoord = a_texcoord; -} \ No newline at end of file +} diff --git a/app/shaders/rgbhistogram_secondary.frag b/app/shaders/rgbhistogram_secondary.frag index 474db6b74..742584502 100644 --- a/app/shaders/rgbhistogram_secondary.frag +++ b/app/shaders/rgbhistogram_secondary.frag @@ -1,8 +1,5 @@ -#version 150 - uniform sampler2D ove_maintex; -uniform vec2 ove_resolution; -uniform vec2 ove_viewport; +uniform vec2 viewport; uniform float histogram_scale; uniform float histogram_power; @@ -13,11 +10,11 @@ out vec4 fragColor; void main(void) { vec3 col = vec3(0.0); - float histogram_height = ceil(ove_viewport.y * histogram_scale); + float histogram_height = ceil(viewport.y * histogram_scale); vec3 histogram_ratio = vec3(0.0); vec3 sum = vec3(0.0); float ratio = 0.0; - vec3 total_pixels = vec3(ceil(ove_viewport.x * ove_resolution.y * + vec3 total_pixels = vec3(ceil(viewport.x * viewport.y * histogram_scale)); for (int i = 0; i < histogram_height; i++) { diff --git a/app/shaders/rgbwaveform.frag b/app/shaders/rgbwaveform.frag index e568b37cd..a3242ec76 100644 --- a/app/shaders/rgbwaveform.frag +++ b/app/shaders/rgbwaveform.frag @@ -1,8 +1,6 @@ -#version 150 - uniform sampler2D ove_maintex; -uniform vec2 ove_resolution; -uniform vec2 ove_viewport; + +uniform vec2 viewport; uniform vec3 luma_coeffs; uniform float waveform_scale; @@ -12,7 +10,7 @@ in vec2 ove_texcoord; out vec4 fragColor; void main(void) { - float waveform_height = ceil(waveform_scale * ove_viewport.y); + float waveform_height = ceil(waveform_scale * viewport.y); float quantisation = 1.0 / (waveform_height - 1.0); float intensity = 0.10; vec4 col = vec4(0.0); diff --git a/app/shaders/rgbwaveform.vert b/app/shaders/rgbwaveform.vert index 88fde9934..33980f284 100644 --- a/app/shaders/rgbwaveform.vert +++ b/app/shaders/rgbwaveform.vert @@ -1,7 +1,4 @@ -#version 150 - uniform float waveform_scale; -uniform vec2 ove_resolution; in vec4 a_position; in vec2 a_texcoord; @@ -26,4 +23,4 @@ void main() { gl_Position = transform * a_position; ove_texcoord = a_texcoord; -} \ No newline at end of file +} diff --git a/app/shaders/solid.frag b/app/shaders/solid.frag index 39030f10e..2be4254a9 100644 --- a/app/shaders/solid.frag +++ b/app/shaders/solid.frag @@ -1,5 +1,3 @@ -#version 150 - uniform vec4 color_in; out vec4 fragColor; diff --git a/app/shaders/stroke.frag b/app/shaders/stroke.frag index bdd7d2691..147b1db55 100644 --- a/app/shaders/stroke.frag +++ b/app/shaders/stroke.frag @@ -1,14 +1,12 @@ -#version 150 - // Node parameter inputs uniform sampler2D tex_in; uniform vec4 color_in; uniform float radius_in; uniform float opacity_in; uniform bool inner_in; +uniform vec2 resolution_in; // Standard inputs -uniform vec2 ove_resolution; uniform int ove_iteration; in vec2 ove_texcoord; @@ -34,10 +32,10 @@ void main(void) { // Loop over box for (float i=-radius + 0.5; i<=radius; i += 2.0) { - float x_coord = i / ove_resolution.x; + float x_coord = i / resolution_in.x; for (float j=-radius + 0.5; j<=radius; j += 2.0) { - float y_coord = j / ove_resolution.y; + float y_coord = j / resolution_in.y; if (abs(length(vec2(i, j))) < radius) { // Get pixel here diff --git a/app/task/CMakeLists.txt b/app/task/CMakeLists.txt index 3498e2910..775e43c86 100644 --- a/app/task/CMakeLists.txt +++ b/app/task/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/task/conform/CMakeLists.txt b/app/task/conform/CMakeLists.txt index a905c3269..0e8ab6e62 100644 --- a/app/task/conform/CMakeLists.txt +++ b/app/task/conform/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/task/conform/conform.cpp b/app/task/conform/conform.cpp index fa131be8c..b1e546155 100644 --- a/app/task/conform/conform.cpp +++ b/app/task/conform/conform.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "codec/decoder.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ConformTask::ConformTask(AudioStreamPtr stream, const AudioParams& params) : stream_(stream), @@ -33,7 +33,10 @@ ConformTask::ConformTask(AudioStreamPtr stream, const AudioParams& params) : bool ConformTask::Run() { - if (stream_->footage()->decoder().isEmpty()) { + // Conforming is done by the renderer now, but I would like to use something like this just to + // show progress + + /*if (stream_->footage()->decoder().isEmpty()) { SetError(tr("Failed to find decoder to conform audio stream")); return false; } else { @@ -49,7 +52,9 @@ bool ConformTask::Run() } else { return true; } - } + }*/ + + return true; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/task/conform/conform.h b/app/task/conform/conform.h index b65d2d689..4486cda8f 100644 --- a/app/task/conform/conform.h +++ b/app/task/conform/conform.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,10 +25,11 @@ #include "render/audioparams.h" #include "task/task.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ConformTask : public Task { + Q_OBJECT public: ConformTask(AudioStreamPtr stream, const AudioParams& params); @@ -42,6 +43,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // CONFORMTASK_H diff --git a/app/task/export/CMakeLists.txt b/app/task/export/CMakeLists.txt index 104ca8fdf..ba76ff017 100644 --- a/app/task/export/CMakeLists.txt +++ b/app/task/export/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/task/export/export.cpp b/app/task/export/export.cpp index 28215e856..50bcb3554 100644 --- a/app/task/export/export.cpp +++ b/app/task/export/export.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "common/timecodefunctions.h" #include "render/colormanager.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ExportTask::ExportTask(ViewerOutput* viewer_node, ColorManager* color_manager, @@ -33,16 +33,22 @@ ExportTask::ExportTask(ViewerOutput* viewer_node, params_(params) { SetTitle(tr("Exporting \"%1\"").arg(viewer_node->media_name())); - - // Render highest quality - backend()->SetRenderMode(RenderMode::kOnline); } bool ExportTask::Run() { TimeRange range; + // For safety, if we're overwriting, we save to a temporary filename and then only overwrite it + // at the end + QString real_filename = params_.filename(); + if (QFileInfo::exists(params_.filename())) { + // Generate a filename that definitely doesn't exist + params_.SetFilename(FileFunctions::GetSafeTemporaryFilename(real_filename)); + } + encoder_ = Encoder::CreateFromID(params_.encoder(), params_); + if (!encoder_) { SetError(tr("Failed to create encoder")); return false; @@ -62,22 +68,28 @@ bool ExportTask::Run() range = TimeRange(0, viewer()->GetLength()); } - frame_time_ = Timecode::time_to_timestamp(range.in(), viewer()->video_params().time_base()); + frame_time_ = 0; + + QSize video_force_size; + QMatrix4x4 video_force_matrix; if (params_.video_enabled()) { - // Ensure renderer always provides the same resolution - backend()->SetForceDownloadResolution(true); - // If a transformation matrix is applied to this video, create it here - if (params_.video_scaling_method() != ExportParams::kStretch) { - QMatrix4x4 mat = ExportParams::GenerateMatrix(params_.video_scaling_method(), - viewer()->video_params().width(), - viewer()->video_params().height(), - params_.video_params().width(), - params_.video_params().height()); + if (viewer()->video_params().width() != params_.video_params().width() + || params_.video_params().height() != params_.video_params().height()) { + video_force_size = QSize(params_.video_params().width(), params_.video_params().height()); - backend()->SetVideoDownloadMatrix(mat); + if (params_.video_scaling_method() != ExportParams::kStretch) { + video_force_matrix = ExportParams::GenerateMatrix(params_.video_scaling_method(), + viewer()->video_params().width(), + viewer()->video_params().height(), + params_.video_params().width(), + params_.video_params().height()); + } + } else { + // Disables forcing size in the renderer + video_force_size = QSize(0, 0); } // Create color processor @@ -94,15 +106,17 @@ bool ExportTask::Run() TimeRangeList video_range, audio_range; if (params_.video_enabled()) { - video_range.append(range); + video_range = {range}; } if (params_.audio_enabled()) { - audio_range.append(range); + audio_range = {range}; audio_data_.SetLength(range.length()); } - Render(video_range, audio_range, false); + Render(color_manager_, video_range, audio_range, RenderMode::kOnline, nullptr, + video_force_size, video_force_matrix, encoder_->GetDesiredPixelFormat(), + color_processor_); bool success = true; @@ -113,52 +127,37 @@ bool ExportTask::Run() encoder_->Close(); - encoder_->deleteLater(); + delete encoder_; + + // If cancelled, delete the file we made, which is always a file we created since we write to a + // temp file during the actual encoding process + if (IsCancelled()) { + QFile::remove(params_.filename()); + } else if (params_.filename() != real_filename) { + // If we were writing to a temp file, overwrite now + if (!FileFunctions::RenameFileAllowOverwrite(params_.filename(), real_filename)) { + SetError(tr("Failed to overwrite \"%1\". Export has been saved as \"%2\" instead.") + .arg(real_filename, params_.filename())); + success = false; + } + } return success; } -void FrameColorConvert(ColorProcessorPtr processor, FramePtr frame) -{ - // OCIO conversion requires a frame in 32F format - if (frame->format() != PixelFormat::PIX_FMT_RGBA32F - && frame->format() != PixelFormat::PIX_FMT_RGB32F) { - PixelFormat::Format dst; - - if (PixelFormat::FormatHasAlphaChannel(frame->format())) { - dst = PixelFormat::PIX_FMT_RGBA32F; - } else { - dst = PixelFormat::PIX_FMT_RGB32F; - } - - frame = PixelFormat::ConvertPixelFormat(frame, dst); - } - - // Color conversion must be done with unassociated alpha, and the pipeline is always associated - ColorManager::DisassociateAlpha(frame); - - // Convert color space - processor->ConvertFrame(frame); - - // Re-associate alpha - ColorManager::ReassociateAlpha(frame); -} - -QFuture ExportTask::DownloadFrame(FramePtr frame, const QByteArray &hash) -{ - rendered_frame_.insert(hash, frame); - - return QtConcurrent::run(FrameColorConvert, color_processor_, frame); -} - -void ExportTask::FrameDownloaded(const QByteArray &hash, const std::list ×, qint64 job_time) +void ExportTask::FrameDownloaded(FramePtr f, const QByteArray &hash, const QVector ×, qint64 job_time) { Q_UNUSED(job_time) - - FramePtr f = rendered_frame_.value(hash); + Q_UNUSED(hash) foreach (const rational& t, times) { - time_map_.insert(t, f); + rational actual_time = t; + + if (params_.has_custom_range()) { + actual_time -= params_.custom_range().in(); + } + + time_map_.insert(actual_time, f); } forever { @@ -174,7 +173,6 @@ void ExportTask::FrameDownloaded(const QByteArray &hash, const std::listWriteFrame(time_map_.take(real_time), real_time); frame_time_++; - } } @@ -191,4 +189,4 @@ void ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples audio_data_.WritePCM(adjusted_range, samples, QDateTime::currentMSecsSinceEpoch()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/task/export/export.h b/app/task/export/export.h index 58e392ad5..1382d6856 100644 --- a/app/task/export/export.h +++ b/app/task/export/export.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "task/render/render.h" #include "task/task.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ExportTask : public RenderTask { @@ -38,15 +38,16 @@ public: protected: virtual bool Run() override; - virtual QFuture DownloadFrame(FramePtr frame, const QByteArray &hash) override; - - virtual void FrameDownloaded(const QByteArray& hash, const std::list& times, qint64 job_time) override; + virtual void FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector& times, qint64 job_time) override; virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples, qint64 job_time) override; -private: - QHash rendered_frame_; + virtual bool TwoStepFrameRendering() const override + { + return false; + } +private: QHash time_map_; ColorManager* color_manager_; @@ -63,6 +64,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // EXPORTTASK_H diff --git a/app/task/export/exportparams.cpp b/app/task/export/exportparams.cpp index 299c1fca3..7b3b6a659 100644 --- a/app/task/export/exportparams.cpp +++ b/app/task/export/exportparams.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "exportparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ExportParams::ExportParams() : video_scaling_method_(kStretch), @@ -122,4 +122,4 @@ void ExportParams::Save(QXmlStreamWriter *writer) const writer->writeEndElement(); // export } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/task/export/exportparams.h b/app/task/export/exportparams.h index ed6106d67..0fb17a4f2 100644 --- a/app/task/export/exportparams.h +++ b/app/task/export/exportparams.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "node/output/viewer/viewer.h" #include "render/colortransform.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ExportParams : public EncodingParams { public: @@ -70,6 +70,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // EXPORTPARAMS_H diff --git a/app/task/precache/CMakeLists.txt b/app/task/precache/CMakeLists.txt index 872149bae..d9077fbbc 100644 --- a/app/task/precache/CMakeLists.txt +++ b/app/task/precache/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/task/precache/precachetask.cpp b/app/task/precache/precachetask.cpp index e707a6949..b26568063 100644 --- a/app/task/precache/precachetask.cpp +++ b/app/task/precache/precachetask.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,9 @@ #include "precachetask.h" -OLIVE_NAMESPACE_ENTER +#include "project/project.h" + +namespace olive { PreCacheTask::PreCacheTask(VideoStreamPtr footage, Sequence* sequence) : RenderTask(new ViewerOutput(), sequence->video_params(), sequence->audio_params()), @@ -29,23 +31,18 @@ PreCacheTask::PreCacheTask(VideoStreamPtr footage, Sequence* sequence) : viewer()->set_video_params(sequence->video_params()); viewer()->set_audio_params(sequence->audio_params()); - // Render fastest quality - backend()->SetRenderMode(RenderMode::kOffline); - - video_node_ = new VideoInput(); + video_node_ = new MediaInput(); video_node_->SetStream(footage); NodeParam::ConnectEdge(video_node_->output(), viewer()->texture_input()); SetTitle(tr("Pre-caching %1:%2").arg(footage->footage()->filename(), QString::number(footage->index()))); - - backend()->NodeGraphChanged(viewer()->texture_input()); - backend()->ProcessUpdateQueue(); } PreCacheTask::~PreCacheTask() { + // We created this viewer node ourselves, so now we should delete it delete viewer(); delete video_node_; } @@ -66,23 +63,21 @@ bool PreCacheTask::Run() } */ - Render(video_range, TimeRangeList(), true); - - download_threads_.waitForDone(); + Render(footage_->footage()->project()->color_manager(), + video_range, + TimeRangeList(), + RenderMode::kOnline, + viewer()->video_frame_cache()); return true; } -QFuture PreCacheTask::DownloadFrame(FramePtr frame, const QByteArray &hash) -{ - return QtConcurrent::run(&download_threads_, viewer()->video_frame_cache(), &FrameHashCache::SaveCacheFrame, hash, frame); -} - -void PreCacheTask::FrameDownloaded(const QByteArray &hash, const std::list ×, qint64 job_time) +void PreCacheTask::FrameDownloaded(FramePtr frame, const QByteArray &hash, const QVector ×, qint64 job_time) { // Do nothing. Pre-cache essentially just creates more frames in the cache, it doesn't need to do // anything else. + Q_UNUSED(frame) Q_UNUSED(hash) Q_UNUSED(times) Q_UNUSED(job_time) @@ -97,4 +92,4 @@ void PreCacheTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr sampl Q_UNUSED(job_time) } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/task/precache/precachetask.h b/app/task/precache/precachetask.h index 090fedd44..5f3bf0b74 100644 --- a/app/task/precache/precachetask.h +++ b/app/task/precache/precachetask.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,15 +21,16 @@ #ifndef PRECACHETASK_H #define PRECACHETASK_H -#include "node/input/media/video/video.h" +#include "node/input/media/media.h" #include "project/item/footage/footage.h" #include "project/item/sequence/sequence.h" #include "task/render/render.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PreCacheTask : public RenderTask { + Q_OBJECT public: PreCacheTask(VideoStreamPtr footage, Sequence* sequence); @@ -38,21 +39,17 @@ public: protected: virtual bool Run() override; - virtual QFuture DownloadFrame(FramePtr frame, const QByteArray &hash) override; - - virtual void FrameDownloaded(const QByteArray& hash, const std::list& times, qint64 job_time) override; + virtual void FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector& times, qint64 job_time) override; virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples, qint64 job_time) override; private: VideoStreamPtr footage_; - VideoInput* video_node_; - - QThreadPool download_threads_; + MediaInput* video_node_; }; -OLIVE_NAMESPACE_EXIT +} #endif // PRECACHETASK_H diff --git a/app/task/project/CMakeLists.txt b/app/task/project/CMakeLists.txt index 9c7d5384b..d287a74a9 100644 --- a/app/task/project/CMakeLists.txt +++ b/app/task/project/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/task/project/import/CMakeLists.txt b/app/task/project/import/CMakeLists.txt index 4a25a6b03..2cafaf272 100644 --- a/app/task/project/import/CMakeLists.txt +++ b/app/task/project/import/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/task/project/import/import.cpp b/app/task/project/import/import.cpp index 5a94e2d38..be423648f 100644 --- a/app/task/project/import/import.cpp +++ b/app/task/project/import/import.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "core.h" #include "project/item/footage/footage.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectImportTask::ProjectImportTask(ProjectViewModel *model, Folder *folder, const QStringList &filenames) : command_(nullptr), @@ -40,7 +40,7 @@ ProjectImportTask::ProjectImportTask(ProjectViewModel *model, Folder *folder, co file_count_ = Core::CountFilesInFileList(filenames_); - SetTitle(tr("Importing %1 files").arg(file_count_)); + SetTitle(tr("Importing %1 file(s)").arg(file_count_)); } const int &ProjectImportTask::GetFileCount() const @@ -110,8 +110,8 @@ void ProjectImportTask::Import(Folder *folder, QFileInfoList import, int &counte } else { - FootagePtr item = Decoder::ProbeMedia(model_->project(), file_info.absoluteFilePath(), - &IsCancelled()); + FootagePtr item = Decoder::Probe(model_->project(), file_info.absoluteFilePath(), + &IsCancelled()); if (item) { // See if this footage is an image sequence @@ -284,4 +284,4 @@ int64_t ProjectImportTask::GetImageSequenceLimit(const QString& start_fn, int64_ return start; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/task/project/import/import.h b/app/task/project/import/import.h index de65a3b5d..9dd44b65e 100644 --- a/app/task/project/import/import.h +++ b/app/task/project/import/import.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "project/projectviewmodel.h" #include "task/task.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ProjectImportTask : public Task { @@ -83,6 +83,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTIMPORTMANAGER_H diff --git a/app/task/project/import/importerrordialog.cpp b/app/task/project/import/importerrordialog.cpp index c6b5e4d8c..232967cff 100644 --- a/app/task/project/import/importerrordialog.cpp +++ b/app/task/project/import/importerrordialog.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectImportErrorDialog::ProjectImportErrorDialog(const QStringList& filenames, QWidget* parent) : QDialog(parent) @@ -50,4 +50,4 @@ ProjectImportErrorDialog::ProjectImportErrorDialog(const QStringList& filenames, layout->addWidget(buttons); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/task/project/import/importerrordialog.h b/app/task/project/import/importerrordialog.h index 8ee6bf740..21cc1a720 100644 --- a/app/task/project/import/importerrordialog.h +++ b/app/task/project/import/importerrordialog.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ProjectImportErrorDialog : public QDialog { @@ -35,6 +35,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTIMPORTERRORDIALOG_H diff --git a/app/task/project/load/CMakeLists.txt b/app/task/project/load/CMakeLists.txt index d08807a8c..0d8b16ab7 100644 --- a/app/task/project/load/CMakeLists.txt +++ b/app/task/project/load/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/task/project/load/load.cpp b/app/task/project/load/load.cpp index ebdc9fb5b..c83cb1c1a 100644 --- a/app/task/project/load/load.cpp +++ b/app/task/project/load/load.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/xmlutils.h" #include "core.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectLoadTask::ProjectLoadTask(const QString &filename) : ProjectLoadBaseTask(filename) @@ -37,6 +37,7 @@ ProjectLoadTask::ProjectLoadTask(const QString &filename) : bool ProjectLoadTask::Run() { QFile project_file(GetFilename()); + uint project_version = Core::kProjectVersion; if (project_file.open(QFile::ReadOnly | QFile::Text)) { QXmlStreamReader reader(&project_file); @@ -45,7 +46,7 @@ bool ProjectLoadTask::Run() if (reader.name() == QStringLiteral("olive")) { while(XMLReadNextStartElement(&reader)) { if (reader.name() == QStringLiteral("version")) { - uint project_version = reader.readElementText().toUInt(); + project_version = reader.readElementText().toUInt(); if (project_version > Core::kProjectVersion) { // Project is newer than we support @@ -59,11 +60,11 @@ bool ProjectLoadTask::Run() } else if (reader.name() == QStringLiteral("url")) { project_saved_url_ = reader.readElementText(); } else if (reader.name() == QStringLiteral("project")) { - project_ = std::make_shared(); + project_ = new Project(); project_->set_filename(GetFilename()); - project_->Load(&reader, &layout_info_, &IsCancelled()); + project_->Load(&reader, &layout_info_, project_version, &IsCancelled()); // Ensure project is in main thread project_->moveToThread(qApp->thread()); @@ -99,4 +100,4 @@ bool ProjectLoadTask::Run() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/task/project/load/load.h b/app/task/project/load/load.h index 565d3dc73..5b521324a 100644 --- a/app/task/project/load/load.h +++ b/app/task/project/load/load.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "loadbasetask.h" #include "window/mainwindow/mainwindowlayoutinfo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ProjectLoadTask : public ProjectLoadBaseTask { @@ -37,6 +37,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTLOADMANAGER_H diff --git a/app/task/project/load/loadbasetask.cpp b/app/task/project/load/loadbasetask.cpp index 1e499ca9a..a6fce7189 100644 --- a/app/task/project/load/loadbasetask.cpp +++ b/app/task/project/load/loadbasetask.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "loadbasetask.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectLoadBaseTask::ProjectLoadBaseTask(const QString &filename) : project_(nullptr), @@ -29,4 +29,4 @@ ProjectLoadBaseTask::ProjectLoadBaseTask(const QString &filename) : SetTitle(tr("Loading '%1'").arg(filename)); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/task/project/load/loadbasetask.h b/app/task/project/load/loadbasetask.h index 7825c2305..0f2c6b0a4 100644 --- a/app/task/project/load/loadbasetask.h +++ b/app/task/project/load/loadbasetask.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "project/project.h" #include "task/task.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ProjectLoadBaseTask : public Task { @@ -32,7 +32,7 @@ class ProjectLoadBaseTask : public Task public: ProjectLoadBaseTask(const QString& filename); - ProjectPtr GetLoadedProject() const + Project* GetLoadedProject() const { return project_; } @@ -58,7 +58,7 @@ public: } protected: - ProjectPtr project_; + Project* project_; MainWindowLayoutInfo layout_info_; @@ -69,6 +69,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // LOADBASETASK_H diff --git a/app/task/project/loadotio/CMakeLists.txt b/app/task/project/loadotio/CMakeLists.txt index 6243a5bcb..0fcbfd16d 100644 --- a/app/task/project/loadotio/CMakeLists.txt +++ b/app/task/project/loadotio/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/task/project/loadotio/loadotio.cpp b/app/task/project/loadotio/loadotio.cpp index 763139560..a09df5147 100644 --- a/app/task/project/loadotio/loadotio.cpp +++ b/app/task/project/loadotio/loadotio.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,12 +29,11 @@ #include "node/block/clip/clip.h" #include "node/block/gap/gap.h" -#include "node/input/media/audio/audio.h" -#include "node/input/media/video/video.h" +#include "node/input/media/media.h" #include "project/item/folder/folder.h" #include "project/item/sequence/sequence.h" -OLIVE_NAMESPACE_ENTER +namespace olive { LoadOTIOTask::LoadOTIOTask(const QString& s) : ProjectLoadBaseTask(s) @@ -52,7 +51,7 @@ bool LoadOTIOTask::Run() return false; } - project_ = std::make_shared(); + project_ = new Project(); project_->set_filename(GetFilename()); std::vector timelines; @@ -164,18 +163,16 @@ bool LoadOTIOTask::Run() if (imported_footage.contains(footage_url)) { probed_item = imported_footage.value(footage_url); } else { - probed_item = Decoder::ProbeMedia(project_.get(), footage_url, &IsCancelled()); + probed_item = Decoder::Probe(project_, footage_url, &IsCancelled()); imported_footage.insert(footage_url, probed_item); project_->root()->add_child(probed_item); } if (probed_item && probed_item->type() == Item::kFootage) { - MediaInput* media; + MediaInput* media = new MediaInput(); if (track->track_type() == Timeline::kTrackTypeVideo) { - media = new VideoInput(); media->SetStream(probed_item->get_first_stream_of_type(Stream::kVideo)); } else { - media = new AudioInput(); media->SetStream(probed_item->get_first_stream_of_type(Stream::kAudio)); } sequence->AddNode(media); @@ -207,4 +204,4 @@ bool LoadOTIOTask::Run() return true; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/task/project/loadotio/loadotio.h b/app/task/project/loadotio/loadotio.h index da156f68c..abe959d3f 100644 --- a/app/task/project/loadotio/loadotio.h +++ b/app/task/project/loadotio/loadotio.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "project/project.h" #include "task/project/load/loadbasetask.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class LoadOTIOTask : public ProjectLoadBaseTask { @@ -38,6 +38,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // OTIODECODER_H diff --git a/app/task/project/save/CMakeLists.txt b/app/task/project/save/CMakeLists.txt index 11cc7273d..930a58bb9 100644 --- a/app/task/project/save/CMakeLists.txt +++ b/app/task/project/save/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/task/project/save/save.cpp b/app/task/project/save/save.cpp index 4ee1b1fc0..541a75718 100644 --- a/app/task/project/save/save.cpp +++ b/app/task/project/save/save.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,9 +27,9 @@ #include "common/filefunctions.h" #include "core.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -ProjectSaveTask::ProjectSaveTask(ProjectPtr project) : +ProjectSaveTask::ProjectSaveTask(Project *project) : project_(project) { SetTitle(tr("Saving '%1'").arg(project->filename())); @@ -38,7 +38,7 @@ ProjectSaveTask::ProjectSaveTask(ProjectPtr project) : bool ProjectSaveTask::Run() { // File to temporarily save to (ensures we can't half-write the user's main file and crash) - QString temp_save = QDir(FileFunctions::GetTempFilePath()).filePath(QStringLiteral("tempsv")); + QString temp_save = FileFunctions::GetSafeTemporaryFilename(project_->filename()); QFile project_file(temp_save); @@ -74,18 +74,17 @@ bool ProjectSaveTask::Run() } // Save was successful, we can now rewrite the original file - QFile original(project_->filename()); - if ((!original.exists() || original.remove()) - && QFile::copy(temp_save, project_->filename())) { + if (FileFunctions::RenameFileAllowOverwrite(temp_save, project_->filename())) { return true; } else { - SetError(tr("Failed to write to \"%1\".").arg(project_->filename())); + SetError(tr("Failed to overwrite \"%1\". Project has been saved as \"%2\" instead.") + .arg(project_->filename(), temp_save)); return false; } } else { - SetError(tr("Failed to open file \"%1\" for writing.").arg(project_->filename())); + SetError(tr("Failed to open temporary file \"%1\" for writing.").arg(temp_save)); return false; } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/task/project/save/save.h b/app/task/project/save/save.h index 6d7f7dc14..85306318a 100644 --- a/app/task/project/save/save.h +++ b/app/task/project/save/save.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,15 +24,15 @@ #include "project/project.h" #include "task/task.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ProjectSaveTask : public Task { Q_OBJECT public: - ProjectSaveTask(ProjectPtr project); + ProjectSaveTask(Project* project); - ProjectPtr GetProject() const + Project* GetProject() const { return project_; } @@ -41,10 +41,10 @@ protected: virtual bool Run() override; private: - ProjectPtr project_; + Project* project_; }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTSAVEMANAGER_H diff --git a/app/task/project/saveotio/CMakeLists.txt b/app/task/project/saveotio/CMakeLists.txt index 4610ecd5f..480c621ab 100644 --- a/app/task/project/saveotio/CMakeLists.txt +++ b/app/task/project/saveotio/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/task/project/saveotio/saveotio.cpp b/app/task/project/saveotio/saveotio.cpp index 586bc8570..b477b4ec5 100644 --- a/app/task/project/saveotio/saveotio.cpp +++ b/app/task/project/saveotio/saveotio.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,9 +30,9 @@ #include "node/block/transition/transition.h" #include "node/input/media/media.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -SaveOTIOTask::SaveOTIOTask(ProjectPtr project) : +SaveOTIOTask::SaveOTIOTask(Project *project) : project_(project) { SetTitle(tr("Exporting project to OpenTimelineIO")); @@ -50,7 +50,7 @@ bool SaveOTIOTask::Run() std::vector serialized; foreach (ItemPtr item, sequences) { - SequencePtr seq = std::static_pointer_cast(sequences.first()); + SequencePtr seq = std::static_pointer_cast(item); auto otio_timeline = SerializeTimeline(seq); @@ -136,7 +136,7 @@ OTIO::Track *SaveOTIOTask::SerializeTrack(TrackOutput *track) otio_clip->set_source_range(OTIO::TimeRange(block->in().toRationalTime(), block->length().toRationalTime())); - QList media_nodes = block->FindInputNodes(); + QVector media_nodes = block->FindInputNodes(); if (!media_nodes.isEmpty()) { auto media_ref = new OTIO::ExternalReference(media_nodes.first()->stream()->footage()->filename().toStdString()); otio_clip->set_media_reference(media_ref); @@ -209,4 +209,4 @@ bool SaveOTIOTask::SerializeTrackList(TrackList *list, OTIO::Timeline* otio_time return true; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/task/project/saveotio/saveotio.h b/app/task/project/saveotio/saveotio.h index a360dab5d..0bce6932c 100644 --- a/app/task/project/saveotio/saveotio.h +++ b/app/task/project/saveotio/saveotio.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,13 +28,13 @@ #include "project/project.h" #include "task/task.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SaveOTIOTask : public Task { Q_OBJECT public: - SaveOTIOTask(ProjectPtr project); + SaveOTIOTask(Project* project); protected: virtual bool Run() override; @@ -46,10 +46,10 @@ private: bool SerializeTrackList(TrackList* list, OTIO::Timeline *otio_timeline); - ProjectPtr project_; + Project* project_; }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTSAVEASOTIOTASK_H diff --git a/app/task/render/CMakeLists.txt b/app/task/render/CMakeLists.txt index 71cd61d65..d2a2cf2ff 100644 --- a/app/task/render/CMakeLists.txt +++ b/app/task/render/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/task/render/render.cpp b/app/task/render/render.cpp index bd813ac19..0529c66ea 100644 --- a/app/task/render/render.cpp +++ b/app/task/render/render.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,223 +21,221 @@ #include "render.h" #include "common/timecodefunctions.h" +#include "render/rendermanager.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -RenderTask::RenderTask(ViewerOutput* viewer, const VideoParams &vparams, const AudioParams &aparams) +RenderTask::RenderTask(ViewerOutput* viewer, const VideoParams &vparams, const AudioParams &aparams) : + viewer_(viewer), + video_params_(vparams), + audio_params_(aparams), + running_tickets_(0) { - backend_ = new OpenGLBackend(); - backend_->SetViewerNode(viewer); - backend_->SetVideoParams(vparams); - backend_->SetAudioParams(aparams); } RenderTask::~RenderTask() { - delete backend_; } -struct TimeHashFuturePair { - rational time; - RenderTicketPtr hash_future; -}; - -struct HashTimePair { - rational time; - QByteArray hash; -}; - -struct HashFrameFuturePair { - QByteArray hash; - RenderTicketPtr frame_future; -}; - -struct RangeSampleFuturePair { - TimeRange range; - RenderTicketPtr sample_future; -}; - -struct HashDownloadFuturePair { - QByteArray hash; - QFuture download_future; - qint64 job_time; -}; - -void RenderTask::Render(const TimeRangeList& video_range, +bool RenderTask::Render(ColorManager* manager, + const TimeRangeList& video_range, const TimeRangeList &audio_range, - bool use_disk_cache) + RenderMode::Mode mode, + FrameHashCache* cache, const QSize &force_size, + const QMatrix4x4 &force_matrix, VideoParams::Format force_format, + ColorProcessorPtr force_color_output) { + // Run watchers in another thread so they can accept signals even while this thread is blocked + QThread watcher_thread; + watcher_thread.start(); + double progress_counter = 0; double total_length = 0; double video_frame_sz = video_params().time_base().toDouble(); - std::list audio_queue; - std::list audio_lookup_table; - if (!audio_range.isEmpty()) { - foreach (const TimeRange& r, audio_range) { - total_length += r.length().toDouble(); + // Store real time before any rendering takes place + qint64 job_time = QDateTime::currentMSecsSinceEpoch(); - std::list ranges = RenderBackend::SplitRangeIntoChunks(r); - audio_queue.insert(audio_queue.end(), ranges.begin(), ranges.end()); - } + // Queue audio jobs + foreach (const TimeRange& r, audio_range) { + // Don't count audio progress, since it's generally a lot faster than video and is weighted at + // 50%, which makes the progress bar look weird to the uninitiated + //total_length += r.length().toDouble(); + + IncrementRunningTickets(); + + RenderTicketWatcher* watcher = new RenderTicketWatcher(); + watcher->setProperty("range", QVariant::fromValue(r)); + PrepareWatcher(watcher, &watcher_thread); + watcher->SetTicket(RenderManager::instance()->RenderAudio(viewer_, r, audio_params_, false)); } - std::list render_lookup_table; - QVector times; - QVector hashes; - std::list frame_queue; - qint64 hash_job_time = 0; + // Look up hashes + QMap > time_map; if (!video_range.isEmpty()) { - times = viewer()->video_frame_cache()->GetFrameListFromTimeRange(video_range); + // Get list of discrete frames from range + QVector times = viewer()->video_frame_cache()->GetFrameListFromTimeRange(video_range); + QVector hashes(times.size()); - total_length += video_frame_sz * times.size(); - - RenderTicketPtr hash_future = backend_->Hash(times); - hashes = hash_future->Get().value >(); - hash_job_time = hash_future->GetJobTime(); - - if (!hash_future->WasCancelled()) { - for (int i=0;iHash(viewer(), video_params_, times.at(i)); + } + + // Filter out duplicates + for (int i=0; isetProperty("hash", hash); + PrepareWatcher(watcher, &watcher_thread); + + IncrementRunningTickets(); + + watcher->SetTicket(RenderManager::instance()->RenderFrame(viewer_, manager, times.at(i), + mode, video_params_, audio_params_, + force_size, force_matrix, + force_format, force_color_output, + cache)); + } + } + + // Add to "total progress" + total_length += video_frame_sz * time_map.size(); + } + + finished_watcher_mutex_.lock(); + + while (!IsCancelled()) { + while (!finished_watchers_.empty() && !IsCancelled()) { + RenderTicketWatcher* watcher = finished_watchers_.front(); + finished_watchers_.pop_front(); + + finished_watcher_mutex_.unlock(); + + // Analyze watcher here + RenderManager::TicketType ticket_type = watcher->GetTicket()->property("type").value(); + + if (ticket_type == RenderManager::kTypeAudio) { + + TimeRange range = watcher->property("range").value(); + + AudioDownloaded(range, + watcher->Get().value(), + job_time); + + // Don't count audio progress, since it's generally a lot faster than video and is weighted at + // 50%, which makes the progress bar look weird to the uninitiated + //progress_counter += range.length().toDouble(); + //emit ProgressChanged(progress_counter / total_length); + + } else if (ticket_type == RenderManager::kTypeVideo && TwoStepFrameRendering()) { + + DownloadFrame(&watcher_thread, + watcher->Get().value(), + watcher->property("hash").toByteArray()); + + progress_counter += video_frame_sz * 0.5; + emit ProgressChanged(progress_counter / total_length); + + } else { + + // Assume single-step video or video download ticket + QByteArray rendered_hash = watcher->property("hash").toByteArray(); + FrameDownloaded(watcher->Get().value(), rendered_hash, time_map.value(rendered_hash), job_time); + + double progress_to_add = video_frame_sz; + if (TwoStepFrameRendering()) { + progress_to_add *= 0.5; + } + progress_counter += progress_to_add; + + emit ProgressChanged(progress_counter / total_length); + + } + + delete watcher; + running_watchers_.removeOne(watcher); + + finished_watcher_mutex_.lock(); + } + + if (IsCancelled()) { + break; + } + + // Run out of finished watchers. If we still have running tickets, wait for the next one to finish. + if (running_tickets_ > 0) { + finished_watcher_wait_cond_.wait(&finished_watcher_mutex_); + } else { + // No more running tickets or finished tickets, wem ust be + break; } } - // Start downloading frames that have finished - std::list download_futures; + finished_watcher_mutex_.unlock(); - // Iterators - std::list::iterator i; - std::list::iterator j; - std::list::iterator k; - - std::list running_hashes; - std::list existing_hashes; - - while (!IsCancelled() - && (!render_lookup_table.empty() - || !frame_queue.empty() - || !audio_queue.empty() - || !download_futures.empty() - || !audio_lookup_table.empty())) { - - while (!IsCancelled() && !frame_queue.empty()) { - - // Pop another frame off the frame queue - const HashTimePair& p = frame_queue.front(); - - // Check if we're already rendering this hash - bool rendering_hash = (std::find(running_hashes.begin(), running_hashes.end(), p.hash) != running_hashes.end()); - - // Skip this hash if we're already rendering it - if (!rendering_hash) { - // Check if this frame already exists (has already been rendered previously or during this job) - bool hash_exists = false; - - if (use_disk_cache) { - // Check if this hash is in our "existing hashes" list - hash_exists = (std::find(existing_hashes.begin(), existing_hashes.end(), p.hash) != existing_hashes.end()); - - // If not, check if it's in the filesystem - if (!hash_exists) { - hash_exists = QFileInfo::exists(viewer()->video_frame_cache()->CachePathName(p.hash)); - - // If so, add it to the list so we don't have to check the filesystem again later - if (hash_exists) { - existing_hashes.push_back(p.hash); - } - } - - if (hash_exists) { - // Already exists, no need to render it again - FrameDownloaded(p.hash, {p.time}, hash_job_time); - progress_counter += video_frame_sz; - emit ProgressChanged(progress_counter / total_length); - } - } - - // If no existing disk cache was found, queue it now - if (!hash_exists) { - render_lookup_table.push_back({p.hash, backend_->RenderFrame(p.time)}); - running_hashes.push_back(p.hash); - } - } - - // Remove first element - frame_queue.pop_front(); - } - - while (!IsCancelled() && !audio_queue.empty()) { - audio_lookup_table.push_back({audio_queue.front(), backend_->RenderAudio(audio_queue.front())}); - audio_queue.pop_front(); - } - - i = render_lookup_table.begin(); - - while (!IsCancelled() && i != render_lookup_table.end()) { - if (i->frame_future->IsFinished()) { - if (!i->frame_future->WasCancelled()) { - FramePtr f = i->frame_future->Get().value(); - - // Start multithreaded download here - download_futures.push_back({i->hash, DownloadFrame(f, i->hash), i->frame_future->GetJobTime()}); - } - - i = render_lookup_table.erase(i); - } else { - i++; - } - } - - j = download_futures.begin(); - - while (!IsCancelled() && j != download_futures.end()) { - if (j->download_future.isFinished()) { - // Place it in the cache - std::list times_with_hash; - - for (int hash_index=0;hash_indexhash) { - times_with_hash.push_back(times.at(hash_index)); - } - } - - FrameDownloaded(j->hash, times_with_hash, j->job_time); - - existing_hashes.push_back(j->hash); - - // Signal process - progress_counter += times_with_hash.size() * video_frame_sz; - emit ProgressChanged(progress_counter / total_length); - - j = download_futures.erase(j); - - } else { - j++; - } - } - - k = audio_lookup_table.begin(); - - while (!IsCancelled() && k != audio_lookup_table.end()) { - if (k->sample_future->IsFinished()) { - AudioDownloaded(k->range, - k->sample_future->Get().value(), - k->sample_future->GetJobTime()); - - progress_counter += k->range.length().toDouble(); - emit ProgressChanged(progress_counter / total_length); - - k = audio_lookup_table.erase(k); - } else { - k++; - } + if (IsCancelled()) { + // Cancel every watcher we created + foreach (RenderTicketWatcher* watcher, running_watchers_) { + disconnect(watcher, &RenderTicketWatcher::Finished, this, &RenderTask::TicketDone); + watcher->Cancel(); } } - // `Close` will block until all jobs are done making a safe deletion - backend_->Close(); + watcher_thread.quit(); + watcher_thread.wait(); + + return true; } -OLIVE_NAMESPACE_EXIT +void RenderTask::DownloadFrame(QThread *thread, FramePtr frame, const QByteArray &hash) +{ + RenderTicketWatcher* watcher = new RenderTicketWatcher(); + watcher->setProperty("hash", hash); + PrepareWatcher(watcher, thread); + + IncrementRunningTickets(); + + watcher->SetTicket(RenderManager::instance()->SaveFrameToCache(viewer_->video_frame_cache(), + frame, + hash)); +} + +void RenderTask::PrepareWatcher(RenderTicketWatcher *watcher, QThread *thread) +{ + watcher->moveToThread(thread); + connect(watcher, &RenderTicketWatcher::Finished, this, &RenderTask::TicketDone, Qt::DirectConnection); + running_watchers_.append(watcher); +} + +void RenderTask::IncrementRunningTickets() +{ + finished_watcher_mutex_.lock(); + running_tickets_++; + finished_watcher_mutex_.unlock(); +} + +void RenderTask::TicketDone(RenderTicketWatcher* watcher) +{ + finished_watcher_mutex_.lock(); + finished_watchers_.push_back(watcher); + finished_watcher_wait_cond_.wakeAll(); + running_tickets_--; + finished_watcher_mutex_.unlock(); +} + +} diff --git a/app/task/render/render.h b/app/task/render/render.h index 8571c0894..9b209565d 100644 --- a/app/task/render/render.h +++ b/app/task/render/render.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,54 +24,84 @@ #include #include "node/output/viewer/viewer.h" -#include "render/backend/opengl/openglbackend.h" +#include "render/colormanager.h" #include "task/task.h" +#include "threading/threadticket.h" +#include "threading/threadticketwatcher.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class RenderTask : public Task { + Q_OBJECT public: RenderTask(ViewerOutput* viewer, const VideoParams &vparams, const AudioParams &aparams); virtual ~RenderTask() override; protected: - void Render(const TimeRangeList &video_range, - const TimeRangeList &audio_range, - bool use_disk_cache); + bool Render(ColorManager *manager, const TimeRangeList &video_range, + const TimeRangeList &audio_range, RenderMode::Mode mode, + FrameHashCache *cache, const QSize& force_size = QSize(0, 0), + const QMatrix4x4& force_matrix = QMatrix4x4(), + VideoParams::Format force_format = VideoParams::kFormatInvalid, + ColorProcessorPtr force_color_output = nullptr); - virtual QFuture DownloadFrame(FramePtr frame, const QByteArray &hash) = 0; + virtual void DownloadFrame(QThread* thread, FramePtr frame, const QByteArray &hash); - virtual void FrameDownloaded(const QByteArray& hash, const std::list& times, qint64 job_time) = 0; + virtual void FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector& times, qint64 job_time) = 0; virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples, qint64 job_time) = 0; ViewerOutput* viewer() const { - return backend_->GetViewerNode(); + return viewer_; } - VideoParams video_params() const + const VideoParams& video_params() const { - return backend_->GetVideoParams(); + return video_params_; } - AudioParams audio_params() const + const AudioParams& audio_params() const { - return backend_->GetAudioParams(); + return audio_params_; } - RenderBackend* backend() + virtual void CancelEvent() override { - return backend_; + finished_watcher_mutex_.lock(); + finished_watcher_wait_cond_.wakeAll(); + finished_watcher_mutex_.unlock(); + } + + virtual bool TwoStepFrameRendering() const + { + return true; } private: - RenderBackend* backend_; + void PrepareWatcher(RenderTicketWatcher* watcher, QThread *thread); + + void IncrementRunningTickets(); + + ViewerOutput* viewer_; + + VideoParams video_params_; + + AudioParams audio_params_; + + QVector running_watchers_; + std::list finished_watchers_; + int running_tickets_; + QMutex finished_watcher_mutex_; + QWaitCondition finished_watcher_wait_cond_; + +private slots: + void TicketDone(RenderTicketWatcher *watcher); }; -OLIVE_NAMESPACE_EXIT +} #endif // RENDERTASK_H diff --git a/app/task/task.h b/app/task/task.h index fc4118fc5..84f056315 100644 --- a/app/task/task.h +++ b/app/task/task.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/cancelableobject.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A base class for background tasks running in Olive. @@ -162,6 +162,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TASK_H diff --git a/app/task/taskmanager.cpp b/app/task/taskmanager.cpp index ffcb82a0d..a4b31efb9 100644 --- a/app/task/taskmanager.cpp +++ b/app/task/taskmanager.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { TaskManager* TaskManager::instance_ = nullptr; @@ -133,4 +133,4 @@ void TaskManager::TaskFinished() emit TaskListChanged(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/task/taskmanager.h b/app/task/taskmanager.h index f0cdc3501..ef3f9e127 100644 --- a/app/task/taskmanager.h +++ b/app/task/taskmanager.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "task/task.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief An object that manages background Task objects, handling their start and end @@ -136,6 +136,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // TASKMANAGER_H diff --git a/app/threading/CMakeLists.txt b/app/threading/CMakeLists.txt new file mode 100644 index 000000000..98627f258 --- /dev/null +++ b/app/threading/CMakeLists.txt @@ -0,0 +1,26 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2020 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 . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + threading/threadticket.cpp + threading/threadticket.h + threading/threadticketwatcher.cpp + threading/threadticketwatcher.h + threading/threadpool.cpp + threading/threadpool.h + PARENT_SCOPE +) diff --git a/app/threading/threadpool.cpp b/app/threading/threadpool.cpp new file mode 100644 index 000000000..3f5cec6aa --- /dev/null +++ b/app/threading/threadpool.cpp @@ -0,0 +1,145 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 "threadpool.h" + +namespace olive { + +ThreadPool::ThreadPool(QThread::Priority priority, int threads, QObject *parent) : + QObject(parent) +{ + all_threads_.resize(threads ? threads : QThread::idealThreadCount()); + + // Create threads + for (int i=0; istart(priority); + } +} + +ThreadPool::~ThreadPool() +{ + foreach (ThreadPoolThread* thread, all_threads_) { + thread->Cancel(); + thread->wait(); + delete thread; + } +} + +void ThreadPool::AddTicket(RenderTicketPtr ticket, bool prioritize) +{ + if (prioritize) { + ticket_queue_.push_front(ticket); + } else { + ticket_queue_.push_back(ticket); + } + + RunNext(); +} + +void ThreadPool::RunNext() +{ + while (!ticket_queue_.empty() && !available_threads_.empty()) { + // Run function + RenderTicketPtr ticket = ticket_queue_.front(); + ticket_queue_.pop_front(); + + if (!ticket->WasCancelled()) { + ThreadPoolThread* thread = available_threads_.front(); + available_threads_.pop_front(); + + // Move ticket to other thread so event processing can occur there + ticket->moveToThread(thread); + + // Run the ticket in the thread, which actually just calls our virtual function RunTicket + thread->RunTicket(ticket); + } + } +} + +void ThreadPool::ThreadDone() +{ + ThreadPoolThread* thread = static_cast(sender()); + + available_threads_.push_back(thread); + + RunNext(); +} + +ThreadPoolThread::ThreadPoolThread(ThreadPool *parent) +{ + pool_ = parent; + + // Ensures mutex is definitely locked by the time the thread is running + mutex_.lock(); +} + +ThreadPoolThread::~ThreadPoolThread() +{ + mutex_.unlock(); +} + +void ThreadPoolThread::RunTicket(RenderTicketPtr ticket) +{ + mutex_.lock(); + ticket_ = ticket; + wait_cond_.wakeAll(); + mutex_.unlock(); +} + +void ThreadPoolThread::run() +{ + while (true) { + wait_cond_.wait(&mutex_); + + if (ticket_) { + pool_->RunTicket(ticket_); + + // Move back to calling thread (hacky?) + ticket_->moveToThread(this->thread()); + + ticket_ = nullptr; + } + + if (IsCancelled()) { + break; + } else { + emit Done(); + } + } +} + +void ThreadPoolThread::CancelEvent() +{ + wait_cond_.wakeAll(); +} + +} diff --git a/app/threading/threadpool.h b/app/threading/threadpool.h new file mode 100644 index 000000000..8d93667d4 --- /dev/null +++ b/app/threading/threadpool.h @@ -0,0 +1,93 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 THREADPOOL_H +#define THREADPOOL_H + +#include + +#include "common/cancelableobject.h" +#include "threading/threadticket.h" + +namespace olive { + +class ThreadPoolThread; + +class ThreadPool : public QObject +{ + Q_OBJECT +public: + ThreadPool(QThread::Priority priority = QThread::InheritPriority, int threads = 0, QObject* parent = nullptr); + + virtual ~ThreadPool() override; + + RenderTicketPtr Queue(); + + virtual void RunTicket(RenderTicketPtr ticket) const = 0; + +public slots: + void AddTicket(olive::RenderTicketPtr ticket, bool prioritize = false); + +private: + void RunNext(); + + QVector all_threads_; + + std::list available_threads_; + + std::list ticket_queue_; + +private slots: + void ThreadDone(); + +}; + +class ThreadPoolThread : public QThread, public CancelableObject +{ + Q_OBJECT +public: + ThreadPoolThread(ThreadPool* parent); + + virtual ~ThreadPoolThread() override; + + void RunTicket(RenderTicketPtr ticket); + +protected: + virtual void run() override; + + virtual void CancelEvent() override; + +signals: + void Done(); + +private: + ThreadPool* pool_; + + RenderTicketPtr ticket_; + + QMutex mutex_; + + QWaitCondition wait_cond_; + +}; + +} + +#endif // THREADPOOL_H diff --git a/app/render/backend/renderticket.cpp b/app/threading/threadticket.cpp similarity index 57% rename from app/render/backend/renderticket.cpp rename to app/threading/threadticket.cpp index 027683cd1..9a30fc37f 100644 --- a/app/render/backend/renderticket.cpp +++ b/app/threading/threadticket.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -18,17 +18,16 @@ ***/ -#include "renderticket.h" +#include "threadticket.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -RenderTicket::RenderTicket(Type type, const QVariant &time) : +RenderTicket::RenderTicket() : + started_(false), finished_(false), - cancelled_(false), - time_(time), - type_(type), - job_time_(0) + cancelled_(false) { + SetJobTime(); } void RenderTicket::WaitForFinished() @@ -42,12 +41,10 @@ void RenderTicket::WaitForFinished() QVariant RenderTicket::Get() { - QMutexLocker locker(&lock_); - - if (!finished_) { - wait_.wait(&lock_); - } + WaitForFinished(); + // We don't have to mutex around this because there is no way to write to `result_` after + // the ticket has finished and the above function blocks the calling thread until it is finished return result_; } @@ -73,32 +70,55 @@ bool RenderTicket::WasCancelled() return cancelled_; } -void RenderTicket::Finish(QVariant result) +void RenderTicket::Start() { QMutexLocker locker(&lock_); - finished_ = true; - result_ = result; + if (!started_ && !finished_) { + started_ = true; + } +} - wait_.wakeAll(); +void RenderTicket::Finish(QVariant result, bool cancelled) +{ + QMutexLocker locker(&lock_); - locker.unlock(); + if (!started_) { + qWarning() << "Tried to finish a ticket that hadn't started"; + } else if (finished_) { + // Do nothing + return; + } else { + finished_ = true; + cancelled_ = cancelled; - emit Finished(); + result_ = result; + + wait_.wakeAll(); + + locker.unlock(); + + emit Finished(); + } } void RenderTicket::Cancel() { QMutexLocker locker(&lock_); - finished_ = true; - cancelled_ = true; + if (!finished_) { + cancelled_ = true; - wait_.wakeAll(); + if (!started_) { + finished_ = true; - locker.unlock(); + wait_.wakeAll(); - emit Finished(); + locker.unlock(); + + emit Finished(); + } + } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/render/backend/renderticket.h b/app/threading/threadticket.h similarity index 78% rename from app/render/backend/renderticket.h rename to app/threading/threadticket.h index f4fca0c6b..5ead976b6 100644 --- a/app/render/backend/renderticket.h +++ b/app/threading/threadticket.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,20 +28,15 @@ #include "codec/frame.h" #include "codec/samplebuffer.h" #include "common/timerange.h" +#include "node/output/viewer/viewer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class RenderTicket : public QObject { Q_OBJECT public: - enum Type { - kTypeHash, - kTypeVideo, - kTypeAudio - }; - - RenderTicket(Type type, const QVariant& time); + RenderTicket(); qint64 GetJobTime() const { @@ -53,16 +48,6 @@ public: job_time_ = QDateTime::currentMSecsSinceEpoch(); } - const QVariant& GetTime() const - { - return time_; - } - - Type GetType() const - { - return type_; - } - void WaitForFinished(); QVariant Get(); @@ -76,7 +61,9 @@ public: return &lock_; } - void Finish(QVariant result); + void Start(); + + void Finish(QVariant result, bool cancelled); void Cancel(); @@ -84,6 +71,8 @@ signals: void Finished(); private: + bool started_; + bool finished_; bool cancelled_; @@ -94,18 +83,14 @@ private: QWaitCondition wait_; - QVariant time_; - - Type type_; - qint64 job_time_; }; using RenderTicketPtr = std::shared_ptr; -OLIVE_NAMESPACE_EXIT +} -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::RenderTicketPtr) +Q_DECLARE_METATYPE(olive::RenderTicketPtr) #endif // RENDERTICKET_H diff --git a/app/render/backend/renderticketwatcher.cpp b/app/threading/threadticketwatcher.cpp similarity index 74% rename from app/render/backend/renderticketwatcher.cpp rename to app/threading/threadticketwatcher.cpp index d5860311d..34ba594ed 100644 --- a/app/render/backend/renderticketwatcher.cpp +++ b/app/threading/threadticketwatcher.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -18,9 +18,9 @@ ***/ -#include "renderticketwatcher.h" +#include "threadticketwatcher.h" -OLIVE_NAMESPACE_ENTER +namespace olive { RenderTicketWatcher::RenderTicketWatcher(QObject *parent) : QObject(parent), @@ -30,8 +30,15 @@ RenderTicketWatcher::RenderTicketWatcher(QObject *parent) : void RenderTicketWatcher::SetTicket(RenderTicketPtr ticket) { - // Ensure that a ticket has NOT already been set and that this ticket is NOT NULL - Q_ASSERT(!ticket_ && ticket); + if (ticket_) { + qCritical() << "Tried to set a ticket on a RenderTicketWatcher twice"; + return; + } + + if (!ticket) { + qCritical() << "Tried to set a null ticket on a RenderTicketWatcher"; + return; + } ticket_ = ticket; @@ -39,9 +46,9 @@ void RenderTicketWatcher::SetTicket(RenderTicketPtr ticket) if (ticket_->IsFinished(false)) { locker.unlock(); - emit Finished(); + emit Finished(this); } else { - connect(ticket_.get(), &RenderTicket::Finished, this, &RenderTicketWatcher::Finished); + connect(ticket_.get(), &RenderTicket::Finished, this, &RenderTicketWatcher::TicketFinished); } } @@ -79,4 +86,16 @@ QVariant RenderTicketWatcher::Get() } } -OLIVE_NAMESPACE_EXIT +void RenderTicketWatcher::Cancel() +{ + if (ticket_) { + ticket_->Cancel(); + } +} + +void RenderTicketWatcher::TicketFinished() +{ + emit Finished(this); +} + +} diff --git a/app/render/backend/renderticketwatcher.h b/app/threading/threadticketwatcher.h similarity index 87% rename from app/render/backend/renderticketwatcher.h rename to app/threading/threadticketwatcher.h index fba301a3b..a6de21e1a 100644 --- a/app/render/backend/renderticketwatcher.h +++ b/app/threading/threadticketwatcher.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,9 +21,9 @@ #ifndef RENDERTICKETWATCHER_H #define RENDERTICKETWATCHER_H -#include "renderticket.h" +#include "threadticket.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class RenderTicketWatcher : public QObject { @@ -38,6 +38,8 @@ public: void SetTicket(RenderTicketPtr ticket); + void Cancel(); + bool WasCancelled(); bool IsFinished(); @@ -47,13 +49,15 @@ public: QVariant Get(); signals: - void Finished(); + void Finished(RenderTicketWatcher* watcher); private: + void TicketFinished(); + RenderTicketPtr ticket_; }; -OLIVE_NAMESPACE_EXIT +} #endif // RENDERTICKETWATCHER_H diff --git a/app/timeline/CMakeLists.txt b/app/timeline/CMakeLists.txt index 58249246c..07015f985 100644 --- a/app/timeline/CMakeLists.txt +++ b/app/timeline/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/timeline/timelinecommon.h b/app/timeline/timelinecommon.h index 8bd042de0..3646eb907 100644 --- a/app/timeline/timelinecommon.h +++ b/app/timeline/timelinecommon.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "common/define.h" #include "common/rational.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Block; class TrackOutput; @@ -59,6 +59,6 @@ public: // FIXME: Hardcoded (but that might be okay here) #define PLAYHEAD_COLOR Qt::red -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINECOMMON_H diff --git a/app/timeline/timelinecoordinate.cpp b/app/timeline/timelinecoordinate.cpp index aaef2415e..5b9882901 100644 --- a/app/timeline/timelinecoordinate.cpp +++ b/app/timeline/timelinecoordinate.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "timelinecoordinate.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimelineCoordinate::TimelineCoordinate() : track_(Timeline::kTrackTypeNone, 0) @@ -59,4 +59,4 @@ void TimelineCoordinate::SetTrack(const TrackReference &track) track_ = track; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/timeline/timelinecoordinate.h b/app/timeline/timelinecoordinate.h index ee37f3f30..98fa8b34d 100644 --- a/app/timeline/timelinecoordinate.h +++ b/app/timeline/timelinecoordinate.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "common/rational.h" #include "trackreference.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimelineCoordinate { @@ -46,6 +46,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINECOORDINATE_H diff --git a/app/timeline/timelinemarker.cpp b/app/timeline/timelinemarker.cpp index 5ee6f031d..9d5632919 100644 --- a/app/timeline/timelinemarker.cpp +++ b/app/timeline/timelinemarker.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "common/xmlutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimelineMarker::TimelineMarker(const TimeRange &time, const QString &name, QObject *parent) : QObject(parent), @@ -72,11 +72,12 @@ TimelineMarkerList::~TimelineMarkerList() qDeleteAll(markers_); } -void TimelineMarkerList::AddMarker(const TimeRange &time, const QString &name) +TimelineMarker* TimelineMarkerList::AddMarker(const TimeRange &time, const QString &name) { TimelineMarker* m = new TimelineMarker(time, name); markers_.append(m); emit MarkerAdded(m); + return m; } void TimelineMarkerList::RemoveMarker(TimelineMarker *marker) @@ -120,4 +121,4 @@ void TimelineMarkerList::Load(QXmlStreamReader *reader) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/timeline/timelinemarker.h b/app/timeline/timelinemarker.h index 09d005c51..0466aa689 100644 --- a/app/timeline/timelinemarker.h +++ b/app/timeline/timelinemarker.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/timerange.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimelineMarker : public QObject { @@ -61,7 +61,7 @@ public: virtual ~TimelineMarkerList() override; - void AddMarker(const TimeRange& time = TimeRange(), const QString& name = QString()); + TimelineMarker *AddMarker(const TimeRange& time = TimeRange(), const QString& name = QString()); void RemoveMarker(TimelineMarker* marker); @@ -80,6 +80,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEMARKER_H diff --git a/app/timeline/timelinepoints.cpp b/app/timeline/timelinepoints.cpp index ba8c6e4e8..06e87dac0 100644 --- a/app/timeline/timelinepoints.cpp +++ b/app/timeline/timelinepoints.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "common/xmlutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimelineMarkerList *TimelinePoints::markers() { @@ -68,4 +68,4 @@ TimelineWorkArea *TimelinePoints::workarea() return &workarea_; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/timeline/timelinepoints.h b/app/timeline/timelinepoints.h index 698adb156..437aeb493 100644 --- a/app/timeline/timelinepoints.h +++ b/app/timeline/timelinepoints.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "timelinemarker.h" #include "timelineworkarea.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimelinePoints { @@ -50,6 +50,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEPOINTS_H diff --git a/app/timeline/timelineworkarea.cpp b/app/timeline/timelineworkarea.cpp index 3206d4be3..fd57b2295 100644 --- a/app/timeline/timelineworkarea.cpp +++ b/app/timeline/timelineworkarea.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "common/xmlutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { const rational TimelineWorkArea::kResetIn = 0; const rational TimelineWorkArea::kResetOut = RATIONAL_MAX; @@ -101,4 +101,4 @@ const rational &TimelineWorkArea::length() const return workarea_range_.length(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/timeline/timelineworkarea.h b/app/timeline/timelineworkarea.h index 602d88b43..579bd747f 100644 --- a/app/timeline/timelineworkarea.h +++ b/app/timeline/timelineworkarea.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/timerange.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimelineWorkArea : public QObject { @@ -62,6 +62,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEWORKAREA_H diff --git a/app/timeline/trackreference.cpp b/app/timeline/trackreference.cpp index 7080ea186..f558ea03d 100644 --- a/app/timeline/trackreference.cpp +++ b/app/timeline/trackreference.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "trackreference.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TrackReference::TrackReference() : type_(Timeline::kTrackTypeNone), @@ -62,4 +62,4 @@ uint qHash(const TrackReference &r, uint seed) seed); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/timeline/trackreference.h b/app/timeline/trackreference.h index 7ae13d444..827422fc6 100644 --- a/app/timeline/trackreference.h +++ b/app/timeline/trackreference.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "timeline/timelinecommon.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TrackReference { @@ -51,6 +51,6 @@ private: uint qHash(const TrackReference& r, uint seed); -OLIVE_NAMESPACE_EXIT +} #endif // TRACKREFERENCE_H diff --git a/app/tool/CMakeLists.txt b/app/tool/CMakeLists.txt index 47d10b945..e54b7c3e6 100644 --- a/app/tool/CMakeLists.txt +++ b/app/tool/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/tool/tool.h b/app/tool/tool.h index c67c9ba84..95a745c59 100644 --- a/app/tool/tool.h +++ b/app/tool/tool.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class Tool { public: @@ -121,6 +121,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // TOOL_H diff --git a/app/ts/CMakeLists.txt b/app/ts/CMakeLists.txt new file mode 100644 index 000000000..3b996602d --- /dev/null +++ b/app/ts/CMakeLists.txt @@ -0,0 +1,35 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2020 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 . + +set(OLIVE_TS_FILES + ts/ar_AR.ts + ts/bs_BA.ts + ts/cs_CZ.ts + ts/de_DE.ts + ts/en_US.ts + ts/es_ES.ts + ts/fr_FR.ts + ts/id_ID.ts + ts/it_IT.ts + ts/pt_BR.ts + ts/ru_RU.ts + ts/sr_RS.ts + ts/tr_TR.ts + ts/uk_UK.ts + ts/zh_CN.ts + ts/zh_TW.ts + PARENT_SCOPE +) diff --git a/app/ts/ar_AR.ts b/app/ts/ar_AR.ts new file mode 100644 index 000000000..42663dcfa --- /dev/null +++ b/app/ts/ar_AR.ts @@ -0,0 +1,4767 @@ + + + + + AudioParams + + + %1 Hz + + + + + Mono + اُحادي + + + + Stereo + مُجسم + + + + 2.1 + 2.1 + + + + 5.1 + 5.1 + + + + 7.1 + 7.1 + + + + Unknown (0x%1) + + + + + Config + + + Error loading settings + + + + + Failed to load application settings. This session will use defaults. + +%1 + + + + + Error saving settings + + + + + Failed to save application settings. The application may lack write permissions to this location. + + + + + Footage + + + %1 FPS + + + + + %1 Hz + + + + + Filename: %1 + + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + + + + + Automatically Detect Parameters From Footage + + + + + Set Parameters Manually + + + + + MoveItemCommand + + + Move Item + + + + + NodeCopyPasteWidget + + + Error pasting nodes + + + + + Failed to paste nodes: %1 + + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + + + + + Set preset name: + + + + + Invalid preset name + + + + + You must enter a preset name + + + + + Preset exists + + + + + A preset with this name already exists. Would you like to replace it? + + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + + + + + %1: Unknown + + + + + %1: Image - %2x%3 + + + + + %1: Video - %2x%3 + + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + + + + + Bars + ألواح + + + + Solid + + + + + Title + عنوان + + + + Tone + نغّم + + + + Unknown + + + + + VideoParams + + + 8-bit + + + + + 16-bit Integer + + + + + Half-Float (16-bit) + + + + + Full-Float (32-bit) + + + + + Unknown (0x%1) + + + + + %1 FPS + + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + + + + + Show application version + + + + + Start in full-screen mode + + + + + Export only (No GUI) + + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + + + + + olive::AboutDialog + + + About %1 + + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + زيتون هو محرر فيديو غير خطي. هذا البرنامج حر ومحمي بموجب رخصة جنو العمومية. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + فريق زيتون ملزم بإخبار مستخدميه بأن الشفرة المصدرية لزيتون متوفرة للتنزيل عبر موقعه الإلكتروني. + + + + olive::ActionSearch + + + Search for action... + ابحث عن إجراء... + + + + olive::AudioInput + + + Audio Input + + + + + Audio + الصوت + + + + Import an audio footage stream. + + + + + olive::AudioMonitorPanel + + + Audio Monitor + + + + + olive::Block + + + Length + + + + + Media In + + + + + Enabled + + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + + + + + Blurs an image. + + + + + Input + + + + + Method + + + + + Box + + + + + Gaussian + + + + + Radius + + + + + Horizontal + + + + + Vertical + + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + + + + + A time-based node that represents a media source. + + + + + Buffer + + + + + olive::ColorDialog + + + Select Color + + + + + olive::ColorSpaceChooser + + + Color Management + + + + + Input: + + + + + Color Space: + + + + + Display: + + + + + View: + + + + + Look: + + + + + (None) + + + + + olive::ColorValuesTab + + + Red + + + + + Green + + + + + Blue + + + + + olive::ColorValuesWidget + + + Preview + + + + + Input + + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + مجلد جديد + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + + + + + + Error + خطأ + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + + + + + Load Project + + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + + + + + Save All + + + + + Don't Save + + + + + Don't Save All + + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + + + + + Send Error Report + + + + + Don't Send + + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CrossDissolveTransition + + + Cross Dissolve + + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + خطي + + + + Bezier + بيزير + + + + Hold + أمسك + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + + + + + Disk Cache Settings + + + + + Maximum Disk Cache: + + + + + %1 GB + + + + + + + Clear Disk Cache + + + + + Automatically clear disk cache on close + + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + + + + + olive::DiskManager + + + + Disk Cache Error + + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + + + + + Pixel + + + + + Pixel Format: + + + + + Performance + + + + + Threads: + + + + + olive::ExportAudioTab + + + Codec: + مرماز: + + + + Sample Rate: + معدل الإعتيان: + + + + Channel Layout: + + + + + Format: + صيغة: + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + + + + + olive::ExportDialog + + + Filename: + أسم الملف: + + + + Browse for exported file filename + + + + + Preset: + قالب: + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + المدى: + + + + Entire Sequence + كل المقطع + + + + In to Out + الدخل إلى الخرج + + + + Format: + صيغة: + + + + Export Video + + + + + Export Audio + + + + + Video + فيديو + + + + Audio + الصوت + + + + + Export + تصدير + + + + Preview + + + + + Invalid parameters + + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + + + + + olive::ExportTask + + + Exporting "%1" + + + + + Failed to create encoder + + + + + Failed to open file + + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + العرض: + + + + Height: + الطول: + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + + + + + Fit + وائم + + + + Stretch + + + + + Crop + + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + معدل نسبة البيكسل: + + + + Interlacing: + المشابكة: + + + + Quality: + + + + + Codec + + + + + Codec: + مرماز: + + + + Advanced + + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + "%1" الخصائص + + + + Name: + اﻷسم: + + + + Tracks: + المقطوعات: + + + + olive::FootageRelinkDialog + + + Footage + + + + + Filename + + + + + Actions + + + + + Browse + تصفّح + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + كل الملفات + + + + olive::FootageViewerPanel + + + Footage Viewer + + + + + olive::GapBlock + + + Gap + + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + + + + + Maximum Bit Rate (Mbps): + + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + حجم الملف الهدف (مب): + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + + + + + Constant Rate Factor + + + + + Target Bit Rate + + + + + Target File Size + + + + + olive::ImageSection + + + Image Sequence: + + + + + olive::InterlacedComboBox + + + None (Progressive) + لا شيء (متفاقم) + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + + + + + In: + + + + + Out: + + + + + Linear + خطي + + + + Hold + أمسك + + + + Bezier + بيزير + + + + olive::KeyframeViewBase + + + Linear + خطي + + + + Bezier + بيزير + + + + Hold + أمسك + + + + P&roperties + + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + + + + + Save '%1' &As + + + + + Close '%1' + + + + + Close All Except '%1' + + + + + &Save Project + &أحفظ المشروع + + + + Save Project &As + أحفظ المشروع &ك + + + + Close Project + + + + + Close All Except Current Project + + + + + (None) + + + + + &File + &ملف + + + + &New + &جديد + + + + &Open Project + &أفتح مشروع + + + + Open &Recent + + + + + &Clear Recent List + + + + + Sa&ve All Projects + + + + + &Import... + &أستيراد + + + + &Export + + + + + &Media... + + + + + &Project Properties... + + + + + Close All Projects + + + + + E&xit + خ&روج + + + + &Edit + &تعديل + + + + Insert + + + + + Overwrite + + + + + Select &All + تحديد &الكل + + + + Deselect All + إلغاء تحديد الكل + + + + Ripple to In Point + موجة لنقطة إدخال + + + + Ripple to Out Point + موجة لنقطة إخراج + + + + Edit to In Point + عدّل لنقطة إدخال + + + + Edit to Out Point + عدّل لنقطة إخراج + + + + Delete In/Out Point + محو نقطة الدخل/الخرج + + + + Ripple Delete In/Out Point + موجة حذف نقطة الإدخال/الإخراج + + + + Set/Edit Marker + حدد/عدّل اﻹشارات + + + + &View + &أظهر + + + + Zoom In + تقريب + + + + Zoom Out + أبتعاد + + + + Increase Track Height + زدّ طول المسار + + + + Decrease Track Height + قلل طول المسار + + + + Toggle Show All + فعل إظهار الكل + + + + Full Screen + ملء الشاشة + + + + Full Screen Viewer + عارض ملء الشاشة + + + + &Playback + &الترديد + + + + Go to Start + أذهب للبداية + + + + Previous Frame + الإطار السابق + + + + Play/Pause + تشغيل/أستئناف + + + + Play In to Out + شغل من الإدخال إلى الإخراج + + + + Next Frame + اﻹطار التالي + + + + Go to End + أذهب للنهاية + + + + Go to Previous Cut + أذهب للقطعة السابقة + + + + Go to Next Cut + أذهب للقطعة التالية + + + + Go to In Point + أذهب لنقطة إدخال + + + + Go to Out Point + أذهب لنقطة إخراج + + + + Shuttle Left + توشع اليسار + + + + Shuttle Stop + إيقاف التوشع + + + + Shuttle Right + توشع اليمين + + + + Loop + حلقة + + + + &Sequence + &مقطع + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Maximize Panel + ضخّم اللائحة + + + + Lock Panels + + + + + Reset to Default Layout + صفّر للتخطيط المبدئي + + + + &Tools + &اﻷدوات + + + + Pointer Tool + أداة المؤشر + + + + Edit Tool + أداة التحرير + + + + Ripple Tool + أداة الموجة + + + + Rolling Tool + + + + + Razor Tool + أداة القطع + + + + Slip Tool + أداة المنزلقة + + + + Slide Tool + أداة الشريحة + + + + Hand Tool + أداة اليد + + + + Zoom Tool + + + + + Transition Tool + أداة اﻷنتقال + + + + Enable Snapping + فعّل السحب + + + + Preferences + التفضيلات + + + + &Help + &مساعدة + + + + A&ction Search + ب&حث إجراء + + + + Send &Feedback... + + + + + &About... + &حول... + + + + olive::MainStatusBar + + + Welcome to %1 %2 + مرحباً في %1 %2 + + + + Running %1 background tasks + + + + + olive::MainWindow + + + Driver Warning + + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + + + + + No color manager connected + + + + + Display + + + + + View + أظهر + + + + Look + + + + + (None) + + + + + OpenColorIO Error + + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + أضف + + + + Subtract + + + + + Multiply + ضاعف + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + الموضع + + + + Rotation + الدوران + + + + Scale + المقياس + + + + Uniform Scale + المقياس الموحد + + + + Anchor Point + نقطة المرساة + + + + olive::MediaInput + + + Footage + + + + + olive::MenuShared + + + &Project + &المشروع + + + + &Sequence + &مقطع + + + + &Folder + &مجلد + + + + Cu&t + قط&ع + + + + Cop&y + &نسخ + + + + &Paste + &لصق + + + + Paste Insert + ألصق أدرج + + + + Duplicate + أستنساخ + + + + Delete + حذف + + + + Ripple Delete + حذف موجة + + + + Split + أنقسام + + + + Set In Point + ضع في نقطة + + + + Set Out Point + ضع خارج نقطة + + + + Reset In Point + صفر في النقطة + + + + Reset Out Point + صفّر النقطة + + + + Clear In/Out Point + محو نقطة الدخل/الخرج + + + + Add Default Transition + أضف اﻷنتقال الأفتراضي + + + + Link/Unlink + ربط/فصل + + + + Enable/Disable + تفعيل/تعطيل + + + + Nest + تداخل + + + + Frames + اﻹطارات + + + + Drop Frame + أفلت إطار + + + + Non-Drop Frame + إطار غير مُفلت + + + + Milliseconds + جزء من الثانية + + + + Seconds + + + + + olive::MergeNode + + + Merge + + + + + Merge two textures together. + + + + + Base + + + + + Blend + + + + + olive::Node + + + Input + + + + + Output + + + + + General + عام + + + + Math + + + + + Color + اللون + + + + Filter + + + + + Timeline + الخط الزمني + + + + Generator + + + + + Channel + + + + + Transition + + + + + Uncategorized + + + + + olive::NodeInput + + + Input + + + + + olive::NodeOutput + + + Output + + + + + olive::NodePanel + + + Node Editor + + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + اللون + + + + Matrix + + + + + Text + النص + + + + Font + الخط + + + + File + + + + + Texture + + + + + Samples + + + + + Footage + + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + + + + + Nothing + + + + + Disconnect + + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + تحذير + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + + + + + olive::NodeTableView + + + Type + + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + (غير معلوم) + + + + olive::NodeTreeView + + + Nodes + + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + + + + + Filter + + + + + Show All + + + + + Show Selected Blocks Only + + + + + Direction + + + + + Top to Bottom + + + + + Bottom to Top + + + + + Left to Right + + + + + Right to Left + + + + + Add + أضف + + + + olive::PanNode + + + + Pan + تسطّح + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + + + + + (none) + (لا شيء) + + + + (multiple) + + + + + olive::PathWidget + + + Browse + تصفّح + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + اللون + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + اللون + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + + + + + Node Color Scheme + + + + + olive::PreferencesAudioTab + + + Output Device: + جهاز اﻹخراج: + + + + Input Device: + جهاز اﻹدخال: + + + + Sample Rate: + معدل الإعتيان: + + + + Audio Recording: + تسجيل الصوت: + + + + Mono + اُحادي + + + + Stereo + مُجسم + + + + Refresh Devices + + + + + Please wait... + + + + + Default + إفتراضي + + + + olive::PreferencesBehaviorTab + + + Behavior + السلوك + + + + General + عام + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + الصوت + + + + Enable audio scrubbing + + + + + Timeline + الخط الزمني + + + + Auto-Seek to Imported Clips + + + + + Edit Tool Also Seeks + أداة التحرير تعرض إيضاً + + + + Edit Tool Selects Links + أداة التحرير تحدد الروابط + + + + Enable Drag Files to Timeline + أسمح بسحب الملفات للخط الزمني + + + + Invert Timeline Scroll Axes + + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + العرض يحدد إيضاً + + + + Seek to the End of Pastes + أعرض لنهاية الملصوقات + + + + Selecting Also Seeks + تحديد العروضات إيضاً + + + + Playback + الترديد + + + + Ask For Name When Setting Marker + أسال عن اﻷسم حين وضع المؤشر + + + + Automatically rewind at the end of a sequence + + + + + Project + المشروع + + + + Drop Files on Media to Replace + + + + + Nodes + + + + + Add Default Effects to New Clips + + + + + Auto-Scale By Default + التحجيم-التلقائي إفتراضياً + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + التفضيلات + + + + General + عام + + + + Appearance + + + + + Behavior + السلوك + + + + Disk + + + + + Audio + الصوت + + + + Keyboard + لوحة المفاتيح + + + + olive::PreferencesDiskTab + + + Disk Management + + + + + Disk Cache Location: + + + + + Disk Cache Settings + + + + + Cache Behavior + + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + اللغة: + + + + Auto-Scroll Method: + + + + + None + + + + + Page Scrolling + + + + + Smooth Scrolling + + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + ابحث عن إجراء أو أختصار + + + + Action + إجراء + + + + Shortcut + أختصار + + + + Import + أستيراد + + + + Export + تصدير + + + + Reset Selected + صفّر المحدد + + + + Reset All + صفّر الجميع + + + + Confirm Reset All Shortcuts + أكّد تصفير كل اﻹختصارات + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + هل أنت متأكد أنك ترغب بتصفير جميع أختصارات لوحة المفاتيح لقيمهم اﻹفتراضية؟ + + + + Import Keyboard Shortcuts + أستيراد أخصارات لوحة المفاتيح + + + + + Error saving shortcuts + خطأ حفظ اﻹختصارات + + + + Failed to open file for reading + فشل في فتح الملف للقراءة + + + + Export Keyboard Shortcuts + تصدير أختصارات لوحة المفاتيح + + + + Export Shortcuts + تصدير اﻹختصارات + + + + Shortcuts exported successfully + صُدرت اﻷختصارات بنجاح + + + + Failed to open file for writing + فشل في فتح الملف للكتابة + + + + olive::ProgressDialog + + + Cancel + إلغاء + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + &جديد + + + + &Import... + &أستيراد + + + + &Project Properties... + + + + + Open in New Tab + + + + + Open in New Window + + + + + Reveal in Explorer + أظهر في الكاشف + + + + Reveal in Finder + أظهر في البحث + + + + Reveal in File Manager + أظهر بمتصفح الملفات + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + + + + + Project + المشروع + + + + (none) + (لا شيء) + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + + + + + OpenColorIO Configuration: + + + + + (default) + + + + + Default Input Color Space: + + + + + Browse + تصفّح + + + + Color Management + + + + + Use Default Location + + + + + Store Alongside Project + + + + + Use Custom Location: + + + + + Disk Cache Settings + + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + + + + + OpenColorIO Config Error + + + + + Failed to set OpenColorIO configuration: %1 + + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + + + + + olive::ProjectSaveTask + + + Saving '%1' + + + + + Failed to write XML data + + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + + + + + Open Project + + + + + Save Project + + + + + Undo + + + + + Redo + أعد + + + + Search media, markers, etc. + بحث وسائط, علامات, إلخ. + + + + Switch to Tree View + + + + + Switch to List View + + + + + Switch to Icon View + + + + + olive::ProjectViewModel + + + Name + اﻷسم + + + + Duration + المدة + + + + Rate + النسبة + + + + Move Items + + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + + + + + Bold + + + + + I + + + + + Italic + + + + + U + + + + + Underline + + + + + S + + + + + Strikethrough + + + + + Font Family + + + + + Font Size + + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + + + + + Histogram + + + + + Scope + + + + + olive::SequenceDialog + + + Name: + اﻷسم: + + + + New Sequence + مقطع جديد + + + + Editing "%1" + تعديل "%1" + + + + Error editing Sequence + + + + + Please enter a name for this Sequence. + + + + + olive::SequenceDialogParameterTab + + + Video + فيديو + + + + Width: + العرض: + + + + Height: + الطول: + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + معدل نسبة البيكسل: + + + + Interlacing: + المشابكة: + + + + Audio + الصوت + + + + Sample Rate: + معدل الإعتيان: + + + + Channels: + + + + + Preview + + + + + Resolution: + + + + + Quality: + + + + + Save Preset + + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + + + + + My Presets + + + + + 4K UHD + + + + + 1080p + 1080p + + + + 720p + 720p + + + + NTSC + + + + + PAL + + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + + + + + olive::SequenceViewerPanel + + + Sequence Viewer + عارض المقطع + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + + + + + Generate a solid color. + + + + + Color + اللون + + + + olive::StringSlider + + + (none) + (لا شيء) + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + + + + + Color + اللون + + + + Radius + + + + + Opacity + العتمة + + + + Inner + + + + + olive::Task + + + Task + + + + + Unknown error + + + + + olive::TaskDialog + + + Task Failed + + + + + olive::TaskManagerPanel + + + Task Manager + + + + + olive::TaskViewItem + + + Error: %1 + + + + + olive::TextGenerator + + + Sample Text + عينة نص + + + + + Text + النص + + + + Generate rich text. + + + + + Font + الخط + + + + Font Size + + + + + Color + اللون + + + + Vertical Align + + + + + Top + أعلى + + + + Center + المركز + + + + Bottom + القاع + + + + olive::TimeBasedPanel + + + (none) + (لا شيء) + + + + olive::TimeBasedWidget + + + Set Marker + ضع وسم + + + + Marker name: + + + + + olive::TimeInput + + + Time + + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + الخط الزمني + + + + olive::TimelineWidget + + + + Properties + + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + + + + + olive::Toolbar + + + Pointer Tool + أداة المؤشر + + + + Edit Tool + أداة التحرير + + + + Ripple Tool + أداة الموجة + + + + Rolling Tool + + + + + Razor Tool + أداة القطع + + + + Slip Tool + أداة المنزلقة + + + + Slide Tool + أداة الشريحة + + + + Hand Tool + أداة اليد + + + + Zoom Tool + + + + + Transition Tool + أداة اﻷنتقال + + + + Record Tool + + + + + Add Tool + + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + + + + + Audio %1 + + + + + Subtitle %1 + + + + + Track %1 + + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + + + + + Linear + خطي + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + + + + + Perform a trigonometry operation on a value. + + + + + Sine + + + + + Cosine + + + + + Tangent + + + + + Inverse Sine + + + + + Inverse Cosine + + + + + Inverse Tangent + + + + + Hyperbolic Sine + + + + + Hyperbolic Cosine + + + + + Hyperbolic Tangent + + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + 1/%1 + + + + olive::VideoInput + + + Video Input + + + + + Video + فيديو + + + + Import a video footage stream. + + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + المشابكة: + + + + Color Space: + + + + + Default (%1) + + + + + Premultiplied Alpha + + + + + Image Sequence + + + + + Start Index: + + + + + End Index: + + + + + Frame Rate: + + + + + Invalid Configuration + + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + + + + + Interface between a Viewer panel and the node system. + + + + + Texture + + + + + Samples + + + + + Video Tracks + + + + + Audio Tracks + + + + + Subtitle Tracks + + + + + olive::ViewerPanel + + + Viewer + + + + + olive::ViewerWidget + + + Error + خطأ + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + قرّب + + + + Fit + وائم + + + + %1% + + + + + Full Screen + ملء الشاشة + + + + Screen %1: %2x%3 + الشاشة %1: %2x%3 + + + + Deinterlace + + + + + Scopes + + + + + Cache + + + + + Auto-Cache + + + + + Pause Auto-Cache During Playback + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Off + مطفئ + + + + On + + + + + Custom Aspect + + + + + Show Audio Waveform + + + + + olive::VolumeNode + + + + Volume + درجة الصوت + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/bs_BA.ts b/app/ts/bs_BA.ts new file mode 100644 index 000000000..cb5cba83d --- /dev/null +++ b/app/ts/bs_BA.ts @@ -0,0 +1,4773 @@ + + + + + AudioParams + + + %1 Hz + %1 Hz + + + + Mono + Mono + + + + Stereo + Stereo + + + + 2.1 + 2.1 + + + + 5.1 + 5.1 + + + + 7.1 + 7.1 + + + + Unknown (0x%1) + Nepoznato (0x%1) + + + + Config + + + Error loading settings + Greška pri učitavanju postavki + + + + Failed to load application settings. This session will use defaults. + +%1 + “Sesija” might not be the most adequate term for “session” + Neuspješno učitavanje postavki aplikacije. Ova sesija će koristiti zadane postavke. + +%1 + + + + Error saving settings + Greška pri spašavanju postavki + + + + Failed to save application settings. The application may lack write permissions for this location. + Neuspješno spašavanje postavki aplikacije. Aplikaciji možda nedostaju dopuštenja za pisanje u ovoj lokaciji. + + + + Footage + + + %1 FPS + + + + + %1 Hz + %1 Hz + + + + Filename: %1 + + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + + + + + Automatically Detect Parameters From Footage + + + + + Set Parameters Manually + + + + + MoveItemCommand + + + Move Item + + + + + NodeCopyPasteWidget + + + Error pasting nodes + + + + + Failed to paste nodes: %1 + + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + + + + + Set preset name: + + + + + Invalid preset name + + + + + You must enter a preset name + + + + + Preset exists + + + + + A preset with this name already exists. Would you like to replace it? + + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + + + + + %1: Unknown + + + + + %1: Image - %2x%3 + + + + + %1: Video - %2x%3 + + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + + + + + Bars + + + + + Solid + + + + + Title + + + + + Tone + + + + + Unknown + + + + + VideoParams + + + 8-bit + + + + + 16-bit Integer + + + + + Half-Float (16-bit) + + + + + Full-Float (32-bit) + + + + + Unknown (0x%1) + Nepoznato (0x%1) + + + + %1 FPS + + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + + + + + Show application version + + + + + Start in full-screen mode + + + + + Export only (No GUI) + + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + + + + + olive::AboutDialog + + + About %1 + O %1 + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive je nelinearni video uređivač. Ovaj softver je slobodan i zaštićen GNU GPL-om. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + Olive tim je pod obavezom da obavijesti korisnike da je Olive-ov izvorni kod dostupan za preuzimanje sa njegove web stranice. + + + + olive::ActionSearch + + + Search for action... + Potražite radnju... + + + + olive::AudioMonitorPanel + + + Audio Monitor + + + + + olive::Block + + + Length + + + + + Media In + + + + + Enabled + + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + + + + + Blurs an image. + + + + + Input + + + + + Method + + + + + Box + + + + + Gaussian + + + + + Radius + + + + + Horizontal + + + + + Vertical + + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + + + + + A time-based node that represents a media source. + + + + + Buffer + + + + + olive::ColorDialog + + + Select Color + + + + + olive::ColorSpaceChooser + + + Color Management + + + + + Input: + + + + + Color Space: + + + + + Display: + + + + + View: + + + + + Look: + + + + + (None) + + + + + olive::ColorValuesTab + + + Red + + + + + Green + + + + + Blue + + + + + olive::ColorValuesWidget + + + Preview + + + + + Input + + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + + + + + + Error + + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + + + + + Load Project + + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + + + + + Save All + + + + + Don't Save + + + + + Don't Save All + + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + + + + + Send Error Report + + + + + Don't Send + + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CrossDissolveTransition + + + Cross Dissolve + + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + Linearno + + + + Bezier + Bezier + + + + Hold + Drži + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + + + + + Disk Cache Settings + + + + + Maximum Disk Cache: + + + + + %1 GB + + + + + + + Clear Disk Cache + + + + + Automatically clear disk cache on close + + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + + + + + olive::DiskManager + + + + Disk Cache Error + + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + Napredno + + + + Pixel + + + + + Pixel Format: + Format piksela: + + + + Performance + + + + + Threads: + + + + + olive::ExportAudioTab + + + Codec: + Kodek: + + + + Sample Rate: + + + + + Channel Layout: + + + + + Format: + Format: + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + + + + + olive::ExportDialog + + + Filename: + + + + + Browse for exported file filename + + + + + Preset: + + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + Raspon: + + + + Entire Sequence + Čitava sekvenca + + + + In to Out + Od početka do kraja + + + + Format: + Format: + + + + Export Video + + + + + Export Audio + + + + + Video + Video + + + + Audio + Audio + + + + + Export + + + + + Preview + + + + + Invalid parameters + + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + + + + + olive::ExportTask + + + Exporting "%1" + + + + + Failed to create encoder + + + + + Failed to open file + + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + Širina: + + + + Height: + Visina: + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + + + + + Fit + + + + + Stretch + + + + + Crop + + + + + Frame Rate: + Okvirna stopa: + + + + Pixel Aspect Ratio: + + + + + Interlacing: + + + + + Quality: + + + + + Codec + + + + + Codec: + Kodek: + + + + Advanced + Napredno + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + + + + + Name: + + + + + Tracks: + + + + + olive::FootageRelinkDialog + + + Footage + + + + + Filename + + + + + Actions + + + + + Browse + + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + + + + + olive::FootageViewerPanel + + + Footage Viewer + + + + + olive::GapBlock + + + Gap + + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + + + + + Maximum Bit Rate (Mbps): + + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + Željena veličina datoteke (MB): + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + + + + + Constant Rate Factor + + + + + Target Bit Rate + + + + + Target File Size + + + + + olive::ImageSection + + + Image Sequence: + + + + + olive::InterlacedComboBox + + + None (Progressive) + Nema (progresivno) + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + + + + + In: + + + + + Out: + + + + + Linear + Linearno + + + + Hold + Drži + + + + Bezier + Bezier + + + + olive::KeyframeViewBase + + + Linear + Linearno + + + + Bezier + Bezier + + + + Hold + Drži + + + + P&roperties + + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + + + + + Save '%1' &As + + + + + Close '%1' + + + + + Close All Except '%1' + + + + + &Save Project + + + + + Save Project &As + + + + + Close Project + + + + + Close All Except Current Project + + + + + (None) + + + + + &File + + + + + &New + + + + + &Open Project + + + + + Open &Recent + + + + + &Clear Recent List + + + + + Sa&ve All Projects + + + + + &Import... + + + + + &Export + + + + + &Media... + + + + + &Project Properties... + + + + + Close All Projects + + + + + E&xit + + + + + &Edit + + + + + Insert + + + + + Overwrite + + + + + Select &All + + + + + Deselect All + + + + + Ripple to In Point + + + + + Ripple to Out Point + + + + + Edit to In Point + + + + + Edit to Out Point + + + + + Delete In/Out Point + + + + + Ripple Delete In/Out Point + + + + + Set/Edit Marker + + + + + &View + + + + + Zoom In + + + + + Zoom Out + + + + + Increase Track Height + + + + + Decrease Track Height + + + + + Toggle Show All + + + + + Full Screen + + + + + Full Screen Viewer + + + + + &Playback + + + + + Go to Start + + + + + Previous Frame + + + + + Play/Pause + + + + + Play In to Out + + + + + Next Frame + + + + + Go to End + + + + + Go to Previous Cut + + + + + Go to Next Cut + + + + + Go to In Point + + + + + Go to Out Point + + + + + Shuttle Left + + + + + Shuttle Stop + + + + + Shuttle Right + + + + + Loop + + + + + &Sequence + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + &Window + + + + + Maximize Panel + + + + + Lock Panels + + + + + Reset to Default Layout + + + + + &Tools + + + + + Pointer Tool + + + + + Edit Tool + + + + + Ripple Tool + + + + + Rolling Tool + + + + + Razor Tool + + + + + Slip Tool + + + + + Slide Tool + + + + + Hand Tool + + + + + Zoom Tool + + + + + Transition Tool + + + + + Enable Snapping + + + + + Preferences + + + + + &Help + + + + + A&ction Search + + + + + Send &Feedback... + + + + + &About... + + + + + olive::MainStatusBar + + + Welcome to %1 %2 + Dobrodišli u %1 %2 + + + + Running %1 background tasks + + + + + olive::MainWindow + + + Driver Warning + + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + + + + + No color manager connected + + + + + Display + + + + + View + + + + + Look + + + + + (None) + + + + + OpenColorIO Error + + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + + + + + Subtract + + + + + Multiply + + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + + + + + Rotation + + + + + Scale + + + + + Uniform Scale + + + + + Anchor Point + + + + + olive::MediaInput + + + + Media + + + + + Import footage into the node graph. + + + + + olive::MenuShared + + + &Project + + + + + &Sequence + + + + + &Folder + + + + + Cu&t + &Reži + + + + Cop&y + + + + + &Paste + &Zalijepi + + + + Paste Insert + + + + + Duplicate + + + + + Delete + + + + + Ripple Delete + + + + + Split + + + + + Set In Point + + + + + Set Out Point + + + + + Reset In Point + + + + + Reset Out Point + + + + + Clear In/Out Point + + + + + Add Default Transition + + + + + Link/Unlink + + + + + Enable/Disable + + + + + Nest + + + + + Frames + + + + + Drop Frame + + + + + Non-Drop Frame + + + + + Milliseconds + + + + + Seconds + + + + + olive::MergeNode + + + Merge + + + + + Merge two textures together. + + + + + Base + + + + + Blend + + + + + olive::MosaicFilterNode + + + Texture + + + + + Horizontal + + + + + Vertical + + + + + Mosaic + + + + + Apply a pixelated mosaic filter to video. + + + + + olive::Node + + + Input + + + + + Output + + + + + General + + + + + Math + + + + + Color + + + + + Filter + + + + + Timeline + + + + + Generator + + + + + Channel + + + + + Transition + + + + + Uncategorized + + + + + olive::NodeInput + + + Input + + + + + olive::NodeOutput + + + Output + + + + + olive::NodePanel + + + Node Editor + + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + + + + + Matrix + + + + + Text + + + + + Font + + + + + File + + + + + Texture + + + + + Samples + + + + + Footage + + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + + + + + Nothing + + + + + Disconnect + + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + + + + + olive::NodeTableView + + + Type + Tip + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + + + + + olive::NodeTreeView + + + Nodes + + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + + + + + Filter + + + + + Show All + + + + + Show Selected Blocks Only + + + + + Direction + + + + + Top to Bottom + + + + + Bottom to Top + + + + + Left to Right + + + + + Right to Left + + + + + Add + + + + + olive::PanNode + + + + Pan + + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + + + + + (none) + (nema) + + + + (multiple) + + + + + olive::PathWidget + + + Browse + + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + + + + + Node Color Scheme + + + + + olive::PreferencesAudioTab + + + Output Device: + + + + + Input Device: + + + + + Sample Rate: + + + + + Audio Recording: + + + + + Mono + Mono + + + + Stereo + Stereo + + + + Refresh Devices + + + + + Please wait... + + + + + Default + + + + + olive::PreferencesBehaviorTab + + + Behavior + + + + + General + + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + Audio + + + + Enable audio scrubbing + + + + + Timeline + + + + + Auto-Seek to Imported Clips + + + + + Edit Tool Also Seeks + + + + + Edit Tool Selects Links + + + + + Enable Drag Files to Timeline + + + + + Invert Timeline Scroll Axes + + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + + + + + Seek to the End of Pastes + + + + + Selecting Also Seeks + + + + + Playback + + + + + Ask For Name When Setting Marker + + + + + Automatically rewind at the end of a sequence + + + + + Project + + + + + Drop Files on Media to Replace + + + + + Nodes + + + + + Add Default Effects to New Clips + + + + + Auto-Scale By Default + + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + + + + + General + + + + + Appearance + + + + + Behavior + + + + + Disk + + + + + Audio + Audio + + + + Keyboard + + + + + olive::PreferencesDiskTab + + + Disk Management + + + + + Disk Cache Location: + + + + + Disk Cache Settings + + + + + Cache Behavior + + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + + + + + Auto-Scroll Method: + + + + + None + + + + + Page Scrolling + + + + + Smooth Scrolling + + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + + + + + Action + + + + + Shortcut + + + + + Import + + + + + Export + + + + + Reset Selected + + + + + Reset All + + + + + Confirm Reset All Shortcuts + + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + + + + + Import Keyboard Shortcuts + + + + + + Error saving shortcuts + + + + + Failed to open file for reading + + + + + Export Keyboard Shortcuts + + + + + Export Shortcuts + + + + + Shortcuts exported successfully + + + + + Failed to open file for writing + + + + + olive::ProgressDialog + + + Cancel + Prekini + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + + + + + &Import... + + + + + &Project Properties... + + + + + Open in New Tab + + + + + Open in New Window + + + + + Reveal in Explorer + + + + + Reveal in Finder + + + + + Reveal in File Manager + + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + + + + + Project + + + + + (none) + (nema) + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + + + + + OpenColorIO Configuration: + + + + + (default) + + + + + Default Input Color Space: + + + + + Browse + + + + + Color Management + + + + + Use Default Location + + + + + Store Alongside Project + + + + + Use Custom Location: + + + + + Disk Cache Settings + + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + + + + + OpenColorIO Config Error + + + + + Failed to set OpenColorIO configuration: %1 + + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + + + + + olive::ProjectSaveTask + + + Saving '%1' + + + + + Failed to write XML data + + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + + + + + Open Project + + + + + Save Project + + + + + Undo + + + + + Redo + + + + + Search media, markers, etc. + + + + + Switch to Tree View + + + + + Switch to List View + + + + + Switch to Icon View + + + + + olive::ProjectViewModel + + + Name + + + + + Duration + + + + + Rate + + + + + Move Items + + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + + + + + Bold + + + + + I + + + + + Italic + + + + + U + + + + + Underline + + + + + S + + + + + Strikethrough + + + + + Font Family + + + + + Font Size + + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + + + + + Histogram + + + + + Scope + + + + + olive::SequenceDialog + + + Name: + + + + + New Sequence + + + + + Editing "%1" + + + + + Error editing Sequence + + + + + Please enter a name for this Sequence. + + + + + olive::SequenceDialogParameterTab + + + Video + Video + + + + Width: + Širina: + + + + Height: + Visina: + + + + Frame Rate: + Okvirna stopa: + + + + Pixel Aspect Ratio: + + + + + Interlacing: + + + + + Audio + Audio + + + + Sample Rate: + + + + + Channels: + + + + + Preview + + + + + Resolution: + + + + + Quality: + + + + + Save Preset + + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + + + + + My Presets + + + + + 4K UHD + + + + + 1080p + 1080p + + + + 720p + 720p + + + + NTSC + + + + + PAL + + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + + + + + olive::SequenceViewerPanel + + + Sequence Viewer + + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + + + + + Generate a solid color. + + + + + Color + + + + + olive::StringSlider + + + (none) + (nema) + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + + + + + Color + + + + + Radius + + + + + Opacity + + + + + Inner + + + + + olive::Task + + + Task + + + + + Unknown error + + + + + olive::TaskDialog + + + Task Failed + + + + + olive::TaskManagerPanel + + + Task Manager + + + + + olive::TaskViewItem + + + Error: %1 + + + + + olive::TextGenerator + + + Sample Text + + + + + + Text + + + + + Generate rich text. + + + + + Font + + + + + Font Size + + + + + Color + + + + + Vertical Align + + + + + Top + + + + + Center + + + + + Bottom + + + + + olive::TimeBasedPanel + + + (none) + (nema) + + + + olive::TimeBasedWidget + + + Set Marker + + + + + Marker name: + + + + + olive::TimeInput + + + Time + + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + + + + + olive::TimelineWidget + + + + Properties + + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + + + + + olive::Toolbar + + + Pointer Tool + + + + + Edit Tool + + + + + Ripple Tool + + + + + Rolling Tool + + + + + Razor Tool + + + + + Slip Tool + + + + + Slide Tool + + + + + Hand Tool + + + + + Zoom Tool + + + + + Transition Tool + + + + + Record Tool + + + + + Add Tool + + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + + + + + Audio %1 + + + + + Subtitle %1 + + + + + Track %1 + + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + + + + + Linear + Linearno + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + + + + + Perform a trigonometry operation on a value. + + + + + Sine + + + + + Cosine + + + + + Tangent + + + + + Inverse Sine + + + + + Inverse Cosine + + + + + Inverse Tangent + + + + + Hyperbolic Sine + + + + + Hyperbolic Cosine + + + + + Hyperbolic Tangent + + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + 1/%1 + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + + + + + Color Space: + + + + + Default (%1) + + + + + Premultiplied Alpha + + + + + Image Sequence + + + + + Start Index: + + + + + End Index: + + + + + Frame Rate: + Okvirna stopa: + + + + Invalid Configuration + + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + + + + + Interface between a Viewer panel and the node system. + + + + + Texture + + + + + Samples + + + + + Video Tracks + + + + + Audio Tracks + + + + + Subtitle Tracks + + + + + olive::ViewerPanel + + + Viewer + + + + + olive::ViewerWidget + + + Error + + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + + + + + Fit + + + + + %1% + + + + + Full Screen + + + + + Screen %1: %2x%3 + + + + + Deinterlace + + + + + Scopes + + + + + Cache + + + + + Auto-Cache + + + + + Pause Auto-Cache During Playback + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Off + + + + + On + + + + + Custom Aspect + + + + + Show Audio Waveform + + + + + olive::VolumeNode + + + + Volume + + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/cs_CZ.ts b/app/ts/cs_CZ.ts new file mode 100644 index 000000000..a8f1345b4 --- /dev/null +++ b/app/ts/cs_CZ.ts @@ -0,0 +1,3903 @@ + + + + + AudioParams + + %1 Hz + %1 Hz + + + Mono + Mono + + + Stereo + Stereo + + + 2.1 + 2.1 + + + 5.1 + 5.1 + + + 7.1 + 7.1 + + + Unknown (0x%1) + Neznámé (0x%1) + + + + Config + + Error loading settings + Chyba při nahrávání nastavení + + + Failed to load application settings. This session will use defaults. + +%1 + Nepodařilo se nahrát nastavení programu. Toto sezení bude používat výchozí nastavení. + +%1 + + + Error saving settings + Chyba při ukládání nastavení + + + Failed to save application settings. The application may lack write permissions to this location. + Nepodařilo se uložit nastavení programu. Program může postrádat oprávnění k zápisu do tohoto umístění. + + + + Footage + + %1 FPS + %1 FPS + + + %1 Hz + %1 Hz + + + Filename: %1 + Název souboru: %1 + + + This footage is not valid for use + Tento záznam není platný pro použití + + + + ImportTool + + Don't ask me again + Neptat se znovu + + + No Active Sequence + Žádný činný úryvek (sled záběrů) + + + No sequence is currently open. Would you like to create one? + V současnosti není otevřen žádný úryvek (sled záběrů). Chcete jeden vytvořit? + + + Automatically Detect Parameters From Footage + Parametry zjistit automaticky ze záznamu + + + Set Parameters Manually + Nastavit parametry ručně + + + + MoveItemCommand + + Move Item + Přesunout položku + + + + NodeCopyPasteWidget + + Error pasting nodes + Chyba při vkládání uzlů + + + Failed to paste nodes: %1 + Nepodařilo se vložit uzly: %1 + + + + NodeFactory + + None + Žádný + + + + NodeViewItem + + %1... + %1... + + + + PresetManager + + Save Preset + Uložit přednastavení + + + Set preset name: + Nastavit název přednastavení: + + + Invalid preset name + Neplatný název přednastavení + + + You must enter a preset name + Musíte zadat název přednastavení + + + Preset exists + Přednastavení existuje + + + A preset with this name already exists. Would you like to replace it? + Již je přednastavení s tímto názvem. Chcete je nahradit? + + + + RatioDialog + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + Zadejte vlastní poměr (např. "4:3", "16/9", atd.): + + + Invalid custom ratio + Neplatný vlastní poměr + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + Nepodařilo se zpracovat "%1" do poměru stran. Naformátujte, prosím, racionální zlomek pomocí oddělovače ':' nebo a '/'. + + + + RenameItemCommand + + Rename Item + Přejmenovat položku + + + + Sequence + + %1 FPS + %1 FPS + + + + Stream + + %1: Audio - %2 Channels, %3Hz + %1: Zvuk - %2 kanály, %3 Hz + + + %1: Unknown + %1: Neznámý + + + %1: Image - %2x%3 + %1: Obrázek - %2x%3 + + + %1: Video - %2x%3 + %1: Obraz - %2x%3 + + + + TimelineViewBlockItem + + %1 + +In: %2 +Out: %3 +Length: %4 + %1 + +Začátek: %2 +Konec: %3 +Délka: %4 + + + + Tool + + Empty + Prázdné + + + Bars + Pruhy + + + Solid + Plný + + + Title + Název + + + Tone + Odstín + + + Unknown + Neznámý + + + + VideoParams + + 8-bit + 8-bitů + + + 16-bit Integer + 16-bitů celé číslo + + + Half-Float (16-bit) + Poloviční plovoucí (16-bitů) + + + Full-Float (32-bit) + Celý plovoucí (32-bitů) + + + Unknown (0x%1) + Neznámý (0x%1) + + + %1 FPS + %1 FPS + + + Square Pixels (%1) + Čtvercové pixely (%1) + + + NTSC Standard (%1) + Standard NTSC (%1) + + + NTSC Widescreen (%1) + Širokoúhlé NTSC (%1) + + + PAL Standard (%1) + Standard PAL (%1) + + + PAL Widescreen (%1) + Širokoúhlé PAL (%1) + + + HD Anamorphic 1080 (%1) + HD deformované 1080 (%1) + + + + main + + Show this help text + Ukázat tento text s nápovědou + + + Show application version + Ukázat verzi programu + + + Start in full-screen mode + Začít v režimu na celou obrazovku + + + Export only (No GUI) + Pouze vyvést (žádné tozhraní) + + + Override language with file + Přepsat jazyk souborem + + + qm-file + Soubor .qm + + + Project to open on startup + Projekt k otevření při spuštění + + + + olive::AboutDialog + + About %1 + O programu %1 + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive je nelineární editor obrazového záznamu. Tento program je zdarma a chráněn GNU GPL. + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + Vývojáři Olive dává uživatelům na vědomí, že zdrojové kódy Olive jsou dostupné pro stažení na internetové stránce projektu. + + + + olive::ActionSearch + + Search for action... + Hledat činnost... + + + + olive::AudioInput + + Audio Input + Vstup zvuku + + + Audio + Zvuk + + + Import an audio footage stream. + Zavést zvukový záznam. + + + + olive::AudioMonitorPanel + + Audio Monitor + Sledování zvuku + + + + olive::Block + + Length + Délka + + + Media In + Začátek záznamu + + + Enabled + Povoleno + + + Speed + Rychlost + + + + olive::BlurFilterNode + + Blur + Rozmazání + + + Blurs an image. + Rozmaže obrázek. + + + Input + Vstup + + + Method + Metoda + + + Box + Rámeček + + + Gaussian + Gausovské + + + Radius + Poloměr + + + Horizontal + Vodorovné + + + Vertical + Svislé + + + Repeat Edge Pixels + Opakovat okrajové pixely + + + + olive::ClipBlock + + Clip + Záběr + + + A time-based node that represents a media source. + Časově založený uzel, který představuje zdroj záznamu. + + + Buffer + Vyrovnávací paměť + + + + olive::ColorDialog + + Select Color + Vybrat barvu + + + + olive::ColorSpaceChooser + + Color Management + Správa barev + + + Input: + Vstup: + + + Color Space: + Barevný prostor: + + + Display: + Zobrazení: + + + View: + Pohled: + + + Look: + Vzhled: + + + (None) + (žádný) + + + + olive::ColorValuesTab + + Red + Červená + + + Green + Zelená + + + Blue + Modrá + + + + olive::ColorValuesWidget + + Preview + Náhled + + + Input + Vstup + + + Reference + Odkaz + + + Display + Zobrazení + + + + olive::ConformTask + + Conforming Audio %1:%2 + Přizpůsobující se zvuk %1:%2 + + + + olive::Core + + Import error + Chyba při zavádění + + + Nothing to import + Nic k zavedení + + + Importing... + Zavádí se... + + + Import footage... + Zavést záznam... + + + Failed to import footage + Nepodařilo se zavést záznam + + + Failed to find active Project panel + Nepodařilo se najít panel s činným projektem + + + No Active Project + Žádný činný projekt + + + No project is currently open to set the properties for + V současnosti není otevřen projekt, pro nějž by se daly nastavit vlastnosti + + + Failed to create new folder + Nepodařilo se vytvořit novou složku + + + Failed to find active project + Nepodařilo se najít činný projekt + + + New Folder + Nová složka + + + Failed to create new sequence + Nepodařilo se vytvořit nový úryvek + + + Possible image sequence detected + Zjištěna možná obrázková řada + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + Soubor '%1' vypadá na to, že by mohl být součástí obrázkové řady. Chcete jej zavést jako takový? + + + You must specify a project file to export + Musíte určit soubor projektu, který chcete vyvést + + + Specified project does not exist + Daný projekt neexistuje + + + Project contains no sequences, nothing to export + Projekt neobsahuje žádné úryvky, není co vyvést + + + This project has multiple sequences. Which do you wish to export? + V tomto projektu je více úryvků. Který chcete vyvést? + + + Enter number (or %1 to cancel): + Zadejte číslo (nebo %1 pro zrušení): + + + Invalid sequence number + Neplatné číslo úryvku + + + Export succeeded + Podařilo se vyvést + + + Export failed: %1 + Nepodařilo se vyvést: %1 + + + Project failed to load: %1 + Projekt se nepodařilo nahrát: %1 + + + Failed to open startup file + Nepodařilo se otevřít spouštěcí soubor + + + The project "%1" doesn't exist. A new project will be started instead. + Projekt "%1" neexistuje. Místo toho bude zahájen nový projekt. + + + Missing OpenTimelineIO Libraries + Chybí knihovny OpenTimelineIO + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + Toto sestavení bylo přeloženo bez OpenTimelineIO, a proto nemůže otevřít soubory OpenTimelineIO. + + + Save Project + Uložit projekt + + + Error + Chyba + + + This Sequence is empty. There is nothing to export. + Tento úryvek je prázdný. Není co vyvádět. + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + Nezjištěn žádný platný úryvek. + +Ujistěte se, že je úryvek nahrán a má připojený uzel prohlížeče. + + + Olive Project + Projekt Olive + + + OpenTimelineIO + OpenTimelineIO + + + Save Project As + Uložit projekt jako + + + Load Project + Nahrát projekt + + + Label Node + Označit uzel + + + Set node label + Nastavit štítek uzlu + + + Sequence %1 + Úryvek %1 + + + Cannot open recent project + Nelze otevřít nedávný projekt + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + Projekt "%1" neexistuje. Chcete tento soubor odstranit ze seznamu nedávno otevřených souborů? + + + Unsaved Changes + Neuložené změny + + + The project '%1' has unsaved changes. Would you like to save them? + Projekt '%1' má neuložené změny. Chcete je uložit? + + + Save + Uložit + + + Save All + Uložit vše + + + Don't Save + Neukládat + + + Don't Save All + Neukládat vše + + + Failed to cache sequence + Úryvek se nepodařilo uložit do vyrovnávací paměti + + + No active viewer found with this sequence. + Nenalezen žádný prohlížeč s tímto úryvkem. + + + Open Project + Otevřít projekt + + + + olive::CrashHandlerDialog + + Olive + Olive + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + Je nám to líto, ale Olive spadl. Pomozte nám jej opravit zasláním chybové zprávy. + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + Co nejpodrobněji popište, co jste dělal. Pokud můžete, poskytněte popis kroků k zopakování tohoto pádu. + + + Crash Report: + Zpráva o pádu: + + + Send Error Report + Poslat zprávu o chybě + + + Don't Send + Neposílat + + + Waiting for crash report to be generated... + Čeká se na vytvoření zprávy o pádu... + + + Upload Failed + Nahrání selhalo + + + Failed to send error report. Please try again later. + Nepodařilo se poslat zprávu o chybě. Zkuste to, prosím, znovu později. + + + No Crash Summary + Žádné shrnutí pádu + + + Are you sure you want to send an error report with no crash summary? + Opravdu chcete odeslat zprávu o chybě bez shrnutí okolností pádu? + + + + olive::CrossDissolveTransition + + Cross Dissolve + Prolínat obraz křížem + + + Smoothly transition between two clips. + Plynulý přechod mezi dvěma záběry. + + + + olive::CurvePanel + + Curve Editor + Editor křivky + + + + olive::CurveView + + Zoom to Fit + Zvětšit pro přizpůsobení + + + + olive::CurveWidget + + Linear + Lineární + + + Bezier + Bézier + + + Hold + Držet + + + + olive::DipToColorTransition + + Dip To Color + Ponořit do barvy + + + Transition between clips by dipping to a color. + Přechod mezi záběry ponořením do barvy. + + + + olive::DiskCacheDialog + + Disk Cache: %1 + Disková vyrovnávací paměť: %1 + + + Disk Cache Settings + Nastavení diskové vyrovnávací paměti + + + Maximum Disk Cache: + Největší disková vyrovnávací paměť: + + + %1 GB + %1 GB + + + Clear Disk Cache + Vyprázdnit diskovou vyrovnávací paměť + + + Automatically clear disk cache on close + Při zavření automaticky vyprázdnit diskovou vyrovnávací paměť + + + Are you sure you want to clear the disk cache in '%1'? + Opravdu chcete vyprázdnit diskovou vyrovnávací paměť v '%1'? + + + Disk Cache Cleared + Disková vyrovnávací paměť vyprázdněna + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + Diskovou vyrovnávací paměť se nepodařilo plně vyprázdnit. Možná budete muset soubory vyrovnávací paměti odstranit ručně. + + + Disk Cache Partially Cleared + Disková vyrovnávací paměť vyprázdněna částečně + + + + olive::DiskManager + + Disk Cache Error + Chyba diskové vyrovnávací paměti + + + Unable to set custom application disk cache. Using default instead. + Nelze nastavit diskovou vyrovnávací paměť vlastní aplikace. Místo toho se používá výchozí. + + + Disk Cache + Disková vyrovnávací paměť + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + Rozhodl jste se změnit výchozí umístění diskové vyrovnávací paměti disku. To zneplatní vaši nynější vyrovnávací paměť. Chcete pokračovat? + + + Failed to open disk cache at "%1". Try a different folder. + Nepodařilo se otevřít diskovou vyrovnávací paměť "%1". Zkuste jinou složku. + + + + olive::ElapsedCounterWidget + + Elapsed: %1 + Uplynulo: %1 + + + Remaining: %1 + Zbývá: %1 + + + + olive::ExportAdvancedVideoDialog + + Advanced + Pokročilé + + + Pixel + Obrazový bod + + + Pixel Format: + Formát pixelu: + + + Performance + Provedení + + + Threads: + Vlákna: + + + + olive::ExportAudioTab + + Codec: + Kodek: + + + Sample Rate: + Vzorkovací kmitočet: + + + Channel Layout: + Rozložení kanálu: + + + Format: + Formát: + + + + olive::ExportCodec + + DNxHD + DNxHD + + + H.264 + H.264 + + + H.265 + H.265 + + + OpenEXR + OpenEXR + + + PNG + PNG + + + ProRes + ProRes + + + TIFF + TIFF + + + MP2 + MP2 + + + MP3 + MP3 + + + AAC + AAC + + + PCM (Uncompressed) + PCM (nekomprimovaný) + + + Unknown + Neznámý + + + + olive::ExportDialog + + Filename: + Název souboru: + + + Browse for exported file filename + Procházet na souborový název vyvedeného souboru + + + Preset: + Přednastavení: + + + Same As Source - High Quality + Stejné jako zdroj - vysoká jakost + + + Same As Source - Medium Quality + Stejné jako zdroj - střední jakost + + + Same As Source - Low Quality + Stejné jako zdroj - nízká jakost + + + Range: + Rozsah: + + + Entire Sequence + Celý úryvek + + + In to Out + Od začátku po konec + + + Format: + Formát: + + + Export Video + Vyvést obraz + + + Export Audio + Vyvést zvuk + + + Video + Obraz + + + Audio + Zvuk + + + Export + Vyvést + + + Preview + Náhled + + + Invalid parameters + Neplatné parametry + + + Both video and audio are disabled. There's nothing to export. + Obraz i zvuk jsou vypnuty. Není co vyvádět. + + + Invalid filename + Neplatný název souboru + + + The filename must contain the extension "%1". Would you like to append it automatically? + Název souboru musí obsahovat příponu "%1". Chcete ji připojit automaticky? + + + Failed to create output directory + Nepodařilo se vytvořit výstupní adresář + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + Zamýšlený výstupní adresář neexistuje a Olive jej nemohl vytvořit. Vyberte jiný název souboru. + + + Confirm Overwrite + Potvrdit přepsání + + + The file "%1" already exists. Do you want to overwrite it? + Soubor "%1" již existuje. Chcete jej přepsat? + + + Invalid Parameters + Neplatné parametry + + + Width and height must be multiples of 2. + Šířka a výška musí být násobkem 2. + + + + olive::ExportFormat + + DNxHD + DNxHD + + + Matroska Video + Video Matroska + + + MPEG-4 Video + Video MPEG-4 + + + OpenEXR + OpenEXR + + + PNG + PNG + + + TIFF + TIFF + + + QuickTime + QuickTime + + + Unknown + Neznámý + + + + olive::ExportTask + + Exporting "%1" + Vyvádí se "%1" + + + Failed to create encoder + Nepodařilo se vytvořit kodér + + + Failed to open file + Nepodařilo se otevřít soubor + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + Nepodařilo se přepsat "%1". Vyvedení bylo místo toho uloženo jako "%2". + + + + olive::ExportVideoTab + + Basic + Základní + + + Width: + Šířka: + + + Height: + Výška: + + + Maintain Aspect Ratio: + Zachovat poměr stran: + + + Scaling Method: + Způsob změny velikosti: + + + Fit + Přizpůsobit + + + Stretch + Roztáhnout + + + Crop + Oříznout + + + Frame Rate: + Snímkování: + + + Pixel Aspect Ratio: + Poměr stran pixelu: + + + Interlacing: + Prokládání: + + + Quality: + Jakost: + + + Codec + Kodek + + + Codec: + Kodek: + + + Advanced + Pokročilé + + + + olive::FloatSlider + + %1 dB + %1 dB + + + %1% + %1% + + + + olive::FootagePropertiesDialog + + "%1" Properties + "%1" Vlastnosti + + + Name: + Název: + + + Tracks: + Stopy: + + + + olive::FootageRelinkDialog + + Footage + Záznam + + + Filename + Název souboru + + + Actions + Činnosti + + + Browse + Procházet + + + Relink Footage + Opětovně propojit záběry + + + Relink "%1" + Opětovně propojit "%1" + + + All Files + Všechny soubory + + + + olive::FootageViewerPanel + + Footage Viewer + Prohlížeč záznamu + + + + olive::GapBlock + + Gap + Mezera + + + A time-based node that represents an empty space. + Na čase založený uzel představující prázdné místo. + + + + olive::H264BitRateSection + + Target Bit Rate (Mbps): + Cílový datový tok (MB/s): + + + Maximum Bit Rate (Mbps): + Největší datový tok (MB/s): + + + Two-Pass + Dva průchody + + + + olive::H264FileSizeSection + + Target File Size (MB): + Cílová velikost souboru (MB): + + + Two-Pass + Dva průchody + + + + olive::H264Section + + Compression Method: + Kompresní postup: + + + Constant Rate Factor + Činitel stálého datového toku + + + Target Bit Rate + Cílový datový tok + + + Target File Size + Cílová velikost souboru + + + + olive::ImageSection + + Image Sequence: + Obrázková řada: + + + + olive::InterlacedComboBox + + None (Progressive) + Žádný (progresivní) + + + Top-Field First + Nejprve horní pole + + + Bottom-Field First + Nejprve dolní pole + + + + olive::KeyframePropertiesDialog + + Keyframe Properties + Vlastnosti klíčového snímku + + + In: + Začátek: + + + Out: + Konec: + + + Linear + Lineární + + + Hold + Držet + + + Bezier + Bézier + + + + olive::KeyframeViewBase + + Linear + Lineární + + + Bezier + Bézier + + + Hold + Držet + + + P&roperties + &Vlastnosti + + + + olive::LoadOTIOTask + + Failed to load OpenTimelineIO from file "%1" + Nepodařilo se nahrát OpenTimelineIO ze souboru "%1" + + + Unknown OpenTimelineIO root element + Neznámý kořenový prvek OpenTimelineIO + + + Failed to load clip + Nepodařilo se nahrát záběr + + + + olive::MainMenu + + &Save '%1' + &Uložit '%1' + + + Save '%1' &As + Uložit '%1' &jako + + + Close '%1' + Zavřít '%1' + + + Close All Except '%1' + Zavřít vše vyjma '%1' + + + &Save Project + &Uložit projekt + + + Save Project &As + Uložit projekt j&ako + + + Close Project + Zavřít projekt + + + Close All Except Current Project + Zavřít vše vyjma nynějšího projektu + + + (None) + (žádný) + + + &File + &Soubor + + + &New + &Nový + + + &Open Project + &Otevřít projekt + + + Open &Recent + Otevřít &nedávný + + + &Clear Recent List + V&yprázdnit seznam nedávno otevřených + + + Sa&ve All Projects + &Uložit všechny projekty + + + &Import... + &Zavést... + + + &Export + &Vyvést + + + &Media... + &Záznamy... + + + &Project Properties... + Vlastnosti &projektu... + + + Close All Projects + Zavřít všechny projekty + + + E&xit + &Ukončit + + + &Edit + Úp&ravy + + + Insert + Vložit + + + Overwrite + Přepsat + + + Select &All + Vybrat &vše + + + Deselect All + Zrušit výběr všeho + + + Ripple to In Point + Vložit a posunout k bodu začátku + + + Ripple to Out Point + Vložit a posunout k bodu konce + + + Edit to In Point + Upravit po bod začátku + + + Edit to Out Point + Upravit po bod konce + + + Delete In/Out Point + Smazat bod začátku/konce + + + Ripple Delete In/Out Point + Vytáhnout bod začátku/konce + + + Set/Edit Marker + Nastavit/Upravit značku + + + &View + &Pohled + + + Zoom In + Přiblížit + + + Zoom Out + Oddálit + + + Increase Track Height + Zvětšit výšku stopy + + + Decrease Track Height + Zmenšit výšku stopy + + + Toggle Show All + Přepnout ukázání všeho + + + Full Screen + Celá obrazovka + + + Full Screen Viewer + Prohlížeč na celou obrazovku + + + &Playback + &Přehrávání + + + Go to Start + Jít na začátek + + + Previous Frame + Předchozí snímek + + + Play/Pause + Přehrát/Pozastavit + + + Play In to Out + Přehrát od začátku po konec + + + Next Frame + Další snímek + + + Go to End + Jít na konec + + + Go to Previous Cut + Jít na předchozí záběr + + + Go to Next Cut + Jít na další záběr + + + Go to In Point + Jít na bod začátku + + + Go to Out Point + Jít na bod konce + + + Shuttle Left + Jezdit tam a zpět vlevo + + + Shuttle Stop + Zastavit pendlování + + + Shuttle Right + Jezdit tam a zpět vpravo + + + Loop + Smyčka + + + &Sequence + Ú&ryvek + + + Cache Entire Sequence + Uložit celý úryvek do vyrovnávací paměti + + + Cache Sequence In/Out + Uložit začátek/konec úryvku do vyrovnávací paměti + + + Maximize Panel + Zvětšit panel + + + Lock Panels + Uzamknout panely + + + Reset to Default Layout + Obnovit výchozí rozvržení + + + &Tools + &Nástroje + + + Pointer Tool + Ukazovátko + + + Edit Tool + Upravení + + + Ripple Tool + Vložení a posunutí + + + Rolling Tool + Válcování + + + Razor Tool + Břitva + + + Slip Tool + Skluz + + + Slide Tool + Posouvání + + + Hand Tool + Ručička + + + Zoom Tool + Zvětšení + + + Transition Tool + Přechod + + + Enable Snapping + Povolit přichytávání + + + Preferences + Nastavení + + + &Help + Nápo&věda + + + A&ction Search + Hledání č&inností + + + Send &Feedback... + Odeslat &zpětnou vazbu... + + + &About... + &O programu... + + + + olive::MainStatusBar + + Welcome to %1 %2 + Vítejte v %1 %2 + + + Running %1 background tasks + Na pozadí běží %1 úloh + + + + olive::MainWindow + + Driver Warning + Varování týkající se ovladače + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + Olive zjistil, že systém používá grafický ovladač Nouveau. + +Je známo, že tento ovladač má u Olive problémy se stabilitou a výkonem. Důrazně doporučujeme, abyste si před dalším používáním Olive nainstalovali vlastní ovladač NVIDIA. + + + + olive::ManagedDisplayWidget + + Color Space + Barevný prostor + + + No color manager connected + Není připojen žádný správce barev + + + Display + Zobrazení + + + View + Pohled + + + Look + Vzhled + + + (None) + (žádný) + + + OpenColorIO Error + Chyba v OpenColorIO + + + Failed to set color configuration: %1 + Nepodařilo se nastavit nastavení barev: %1 + + + + olive::ManagedPixelSamplerWidget + + Display + Zobrazení + + + Reference + Odkaz + + + + olive::MathNode + + Math + Matematika + + + Perform a mathematical operation between two values. + Provést matematickou operaci mezi dvěma hodnotami. + + + Method + Metoda + + + Value + Hodnota + + + Add + Sčítat + + + Subtract + Odčítat + + + Multiply + Násobit + + + Divide + Dělit + + + Power + Mocnina + + + + olive::MatrixGenerator + + Orthographic Matrix + Pravopisná matice + + + Ortho + Pravopis + + + Generate an orthographic matrix using position, rotation, and scale. + Vytvořte ortografickou matici pomocí polohy, otočení a měřítka. + + + Position + Poloha + + + Rotation + Otočení + + + Scale + Měřítko + + + Uniform Scale + Jednotné měřítko + + + Anchor Point + Bod ukotvení + + + + olive::MediaInput + + Footage + Záznam + + + + olive::MenuShared + + &Project + &Projekt + + + &Sequence + Ú&ryvek + + + &Folder + &Složka + + + Cu&t + Vyjmou&t + + + Cop&y + &Kopírovat + + + &Paste + &Vložit + + + Paste Insert + Vložit/Přidat + + + Duplicate + Zdvojit + + + Delete + Smazat + + + Ripple Delete + Vytáhnout + + + Split + Rozdělit + + + Set In Point + Nastavit bod začátku + + + Set Out Point + Nastavit bod konce + + + Reset In Point + Obnovit výchozí bod začátku + + + Reset Out Point + Obnovit výchozí bod konce + + + Clear In/Out Point + Vymazat bod začátku/konce + + + Add Default Transition + Přidat výchozí přechod + + + Link/Unlink + Spojit/Oddělit + + + Enable/Disable + Povolit/Zakázat + + + Nest + Vnořovat + + + Frames + Snímky + + + Drop Frame + Zahodit snímek + + + Non-Drop Frame + Nezahodit snímek + + + Milliseconds + Milisekundy + + + Seconds + Sekundy + + + + olive::MergeNode + + Merge + Sloučit + + + Merge two textures together. + Sloučit dva povrchy dohromady. + + + Base + Základ + + + Blend + Směs + + + + olive::Node + + Input + Vstup + + + Output + Výstup + + + General + Obecné + + + Math + Matematika + + + Color + Barva + + + Filter + Filtr + + + Timeline + Časová osa + + + Generator + Tvůrce + + + Channel + Kanál + + + Transition + Přechod + + + Uncategorized + Nezařazeno + + + + olive::NodeInput + + Input + Vstup + + + + olive::NodeOutput + + Output + Výstup + + + + olive::NodePanel + + Node Editor + Editor uzlu + + + + olive::NodeParam + + Value + Hodnota + + + None + Žádná + + + Integer + Celé číslo + + + Float + Pohyblivá desetinná čárka + + + Rational + Racionální + + + Boolean + Booleánská + + + Color + Barva + + + Matrix + Matice + + + Text + Text + + + Font + Písmo + + + File + Soubor + + + Texture + Povrch + + + Samples + Vzorky + + + Footage + Záznam + + + Vector 2D + Vektor 2D + + + Vector 3D + Vektor 3D + + + Vector 4D + Vektor 4D + + + Unknown + Neznámý + + + + olive::NodeParamViewArrayWidget + + + + + + + + %1 elements + %1 prvků + + + + olive::NodeParamViewConnectedLabel + + Connected to + Spojeno s + + + Nothing + Nic + + + Disconnect + Rozpojit + + + + olive::NodeParamViewItem + + %1 (%2) + %1 (%2) + + + + olive::NodeParamViewItemBody + + %1: + %1: + + + + olive::NodeParamViewKeyframeControl + + Warning + Varování + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + Opravdu chcete zakázat klíčování snímků na této hodnotě? Tím budou vyprázdněny všechny stávající klíčové snímky. + + + + olive::NodeTablePanel + + Table View + Tabulkové zobrazení + + + + olive::NodeTableView + + Type + Typ + + + Source + Zdroj + + + R/X + Č/X + + + G/Y + Z/Y + + + B/Z + M/Z + + + A/W + A/W + + + (unknown) + (neznámý) + + + + olive::NodeTreeView + + Nodes + Uzly + + + + olive::NodeView + + Label + Štítek + + + Auto-Position + Automatické umístění + + + Smooth Edges + Jemné okraje + + + Filter + Filtr + + + Show All + Ukázat vše + + + Show Selected Blocks Only + Ukázat pouze vybrané bloky + + + Direction + Směr + + + Top to Bottom + Shora dolů + + + Bottom to Top + Zdola nahoru + + + Left to Right + Zleva doprava + + + Right to Left + Zprava doleva + + + Add + Přidat + + + + olive::PanNode + + Pan + Vyvážení + + + Adjust the stereo panning of an audio source. + Upravit vyvážení sterea zdroje zvuku. + + + Samples + Vzorky + + + + olive::PanelWidget + + %1: %2 + %1: %2 + + + + olive::ParamPanel + + Parameter Editor + Editor parametru + + + (none) + (žádný) + + + (multiple) + (více) + + + + olive::PathWidget + + Browse + Procházet + + + Browse for path + Procházet cestu + + + + olive::PixelAspectRatioComboBox + + Set Custom Pixel Aspect Ratio + Nastavit vlastní poměr stran obrazového bodu + + + Custom... + Vlastní... + + + Custom (%1) + Vlastní (%1) + + + + olive::PixelSamplerPanel + + Pixel Sampler + Vzorkovač obrazového bodu + + + + olive::PixelSamplerWidget + + Color + Barva + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + <html><font color='#FF8080'>Č: %1</font><br><font color='#80FF80'>Z: %2</font><br><font color='#8080FF'>M: %3</font><br>A: %4</html> + + + + olive::PolygonGenerator + + Polygon + Mnohoúhelník + + + Generate a 2D polygon of any amount of points. + Vytvořit dvojrozměrný mnohoúhelník o jakémkoli počtu bodů. + + + Points + Body + + + Color + Barva + + + + olive::PreCacheTask + + Pre-caching %1:%2 + Ukládání do vyrovnávací paměti dopředu %1:%2 + + + + olive::PreferencesAppearanceTab + + Theme + Vzhled + + + Node Color Scheme + Barevné schéma uzlu + + + + olive::PreferencesAudioTab + + Output Device: + Výstupní zařízení: + + + Input Device: + Vstupní zařízení: + + + Sample Rate: + Vzorkovací kmitočet: + + + Audio Recording: + Nahrávání zvuku: + + + Mono + Mono + + + Stereo + Stereo + + + Refresh Devices + Obnovit zařízení + + + Please wait... + Počkejte, prosím... + + + Default + Výchozí + + + + olive::PreferencesBehaviorTab + + Behavior + Chování + + + General + Obecné + + + Enable hover focus + Povolit zaměření přejetím + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + Panely budou považovány za zaměřené, když je ukazovátko myši nad nimi, aniž byste na ně museli klepat. + + + Scroll wheel zooms by default instead of scrolling + Ve výchozím nastavení kolečko myši místo posunování zvětšuje + + + Holding CTRL while using Olive toggles this setting + Toto nastavení při používání Olive přepnete podržením klávesy Ctrl + + + Audio + Zvuk + + + Enable audio scrubbing + Povolit přehrávání zvuku proměnlivou rychlostí + + + Timeline + Časová osa + + + Auto-Seek to Imported Clips + Přehrávat automaticky normální rychlostí s přeskakováním k zavedeným záběrům + + + Edit Tool Also Seeks + Nástroj pro úpravy také přehrává normální rychlostí s přeskakováním + + + Edit Tool Selects Links + Nástroj pro úpravy vybírá odkazy + + + Enable Drag Files to Timeline + Povolit tažení souborů na časovou osu + + + Invert Timeline Scroll Axes + Obrátit osy posunování časové osy + + + Hold ALT on any UI element to switch scrolling axes + Podržení Alt na libovolném prvku uživatelského rozhraní pro přepnutí os posunování + + + Seek Also Selects + Přehrávání normální rychlostí s přeskakováním také vybírá + + + Seek to the End of Pastes + Přehrávání normální rychlostí s přeskakováním po konec vložení + + + Selecting Also Seeks + Výběr také přehrává normální rychlostí s přeskakováním + + + Playback + Přehrávání + + + Ask For Name When Setting Marker + Požádat o název při nastavení značky + + + Automatically rewind at the end of a sequence + Automaticky přetočit zpět na konci úryvku + + + Project + Projekt + + + Drop Files on Media to Replace + Upustit soubory na záznam pro nahrazení + + + Nodes + Uzly + + + Add Default Effects to New Clips + Přidat výchozí efekty do nových záběrů + + + Auto-Scale By Default + Automaticky měnit velikost + + + Splitting Clips Copies Dependencies + Při rozdělení záběrů se kopírují závislosti + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + Více uzlů může sdílet stejné uzly. Toto zakažte, aby se automaticky sdílely závislosti uzlů mezi záběry při jejich kopírování nebo rozdělování. + + + + olive::PreferencesDialog + + Preferences + Nastavení + + + General + Obecné + + + Appearance + Vzhled + + + Behavior + Chování + + + Disk + Disk + + + Audio + Zvuk + + + Keyboard + Klávesnice + + + + olive::PreferencesDiskTab + + Disk Management + Správa disku + + + Disk Cache Location: + Umístění diskové vyrovnávací paměti: + + + Disk Cache Settings + Nastavení diskové vyrovnávací paměti + + + Cache Behavior + Chování vyrovnávací paměti + + + Cache Ahead: + Vyrovnávací paměť napřed: + + + %1 seconds + %1 sekund + + + Cache Behind: + Vyrovnávací paměť pozadu: + + + Disk Cache + Disková vyrovnávací paměť + + + Failed to set disk cache location. Access was denied. + Nepodařilo se nastavit umístění diskové vyrovnávací paměti. Přístup byl odepřen. + + + + olive::PreferencesGeneralTab + + Language: + Jazyk: + + + Auto-Scroll Method: + Způsob automatického posunování: + + + None + Žádný + + + Page Scrolling + Posunování strany + + + Smooth Scrolling + Plynulý posun + + + Rectified Waveforms: + Usměrněné tvary vln: + + + Default Still Image Length: + Výchozí délka statického obrazu: + + + %1 seconds + %1 sekund + + + %1 (%2) + %1 (%2) + + + + olive::PreferencesKeyboardTab + + Search for action or shortcut + Hledat činnosti nebo klávesové zkratky + + + Action + Činnost + + + Shortcut + Zkratka + + + Import + Zavést + + + Export + Vyvést + + + Reset Selected + Obnovit výchozí hodnotu u vybraného + + + Reset All + Obnovit výchozí hodnotu u všeho + + + Confirm Reset All Shortcuts + Potvrdit obnovení výchozího nastavení všech klávesových zkratek + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + Jste si jistý, že chcete vrátit nastavení všech klávesových zkratek do jejich výchozího stavu? + + + Import Keyboard Shortcuts + Zavést klávesové zkratky + + + Error saving shortcuts + Chyba při ukládání klávesových zkratek + + + Failed to open file for reading + Soubor se nepodařilo otevřít pro čtení + + + Export Keyboard Shortcuts + Vyvést klávesové zkratky + + + Export Shortcuts + Vyvést zkratky + + + Shortcuts exported successfully + Zkratky úspěšně vyvedeny + + + Failed to open file for writing + Soubor se nepodařilo otevřít pro zápis + + + + olive::ProgressDialog + + Cancel + Zrušit + + + + olive::Project + + (untitled) + (bez názvu) + + + + olive::ProjectExplorer + + &New + &Nový + + + &Import... + &Zavést... + + + &Project Properties... + Vlastnosti &projektu... + + + Open in New Tab + Otevřít v nové kartě + + + Open in New Window + Otevřít v novém okně + + + Reveal in Explorer + Ukázat v průzkumníku + + + Reveal in Finder + Ukázat v hledači + + + Reveal in File Manager + Ukázat ve správci souborů + + + Pre-Cache + Uložit dopředu do vyrovnávací paměti + + + No sequences exist in project + V projektu není žádný úryvek + + + For "%1" + Pro "%1" + + + P&roperties + &Vlastnosti + + + Confirm Footage Deletion + Potvrdit smazání záznamu + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + Záznam "%1" se nyní používá v následujících úryvcích: + +%2 +Co byste s těmito záběry chtěli dělat? + + + Offline Footage + Nespřažený záznam + + + Delete Clips + Smazat záběry + + + + olive::ProjectExplorerNavigation + + Go to parent folder + Přejít do nadřazené složky + + + + olive::ProjectImportErrorDialog + + Import Error + Chyba při zavádění + + + The following files failed to import. Olive likely does not support their formats. + Následující soubory se nepodařilo zavést. Olive pravděpodobně nepodporuje jejich formáty. + + + + olive::ProjectImportTask + + Importing %1 files + Zavádí se %1 souborů + + + + olive::ProjectLoadBaseTask + + Loading '%1' + Nahrává se '%1' + + + + olive::ProjectLoadTask + + This project is newer than this version of Olive and cannot be opened. + Tento projekt je novější než tato verze Olive a nelze jej otevřít. + + + This project is from a version of Olive that is no longer supported in this version. + Tento projekt pochází z verze Olive, která již v této verzi není podporována. + + + Failed to read file "%1" for reading. + Nepodařilo se přečíst soubor "%1" pro čtení. + + + + olive::ProjectPanel + + Folder + Složka + + + Project + Projekt + + + (none) + (žádný) + + + + olive::ProjectPropertiesDialog + + Project Properties for '%1' + Vlastnosti projektu pro '%1' + + + OpenColorIO Configuration: + Nastavení OpenColorIO: + + + (default) + (výchozí) + + + Default Input Color Space: + Výchozí vstupní barevný prostor: + + + Browse + Procházet + + + Color Management + Správa barev + + + Use Default Location + Použít výchozí umístění + + + Store Alongside Project + Uložit projekt vedle + + + Use Custom Location: + Použít vlastní umístění: + + + Disk Cache Settings + Nastavení vyrovnávací paměti + + + "Store alignside project" functionality not implemented yet + Funkce pro Uložit projekt vedle dosud není udělána + + + Disk Cache + Disková vyrovnávací paměť + + + OpenColorIO Config Error + Chyba nastavení OpenColorIO + + + Failed to set OpenColorIO configuration: %1 + Nepodařilo se nastavit nastavení OpenColorIO: %1 + + + Invalid path + Neplatná cesta + + + The cache path is invalid. Please check it and try again. + Cesta k vyrovnávací paměti je neplatná. Ověřte ji a zkuste to znovu. + + + Browse for OpenColorIO configuration + Procházet pro nastavení OpenColorIO + + + + olive::ProjectSaveTask + + Saving '%1' + Ukládá se '%1' + + + Failed to write XML data + Nepodařilo se zapsat data XML + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + Nepodařilo se přepsat "%1". Projekt byl místo toho uložen jako "%2". + + + Failed to open temporary file "%1" for writing. + Nepodařilo se otevřít dočasný soubor "%1" pro zápis. + + + + olive::ProjectToolbar + + New... + Nový... + + + Open Project + Otevřít projekt + + + Save Project + Uložit projekt + + + Undo + Zpět + + + Redo + Znovu + + + Search media, markers, etc. + Hledat záznam, značky atd. + + + Switch to Tree View + Přepnout na stromové zobrazení + + + Switch to List View + Přepnout na zobrazení seznamu + + + Switch to Icon View + Přepnout na zobrazení ikon + + + + olive::ProjectViewModel + + Name + Název + + + Duration + Doba trvání + + + Rate + Rychlost + + + Move Items + Přesunout položky + + + + olive::RenderCancelDialog + + Waiting for workers to finish... + Čeká se na dokončení dělníky... + + + Renderer + Vykreslovač + + + + olive::RichTextDialog + + B + B + + + Bold + Tučné + + + I + I + + + Italic + Kurzíva + + + U + U + + + Underline + Podtržení + + + S + S + + + Strikethrough + Přeškrtnutí + + + Font Family + Rodina písma + + + Font Size + Velikost písma + + + L + L + + + Left Align + Zarovnat doleva + + + C + C + + + Center Align + Na střed + + + R + R + + + Right Align + Zarovnat doprava + + + J + J + + + Justify Align + Zarovnat do bloku + + + + olive::SaveOTIOTask + + Exporting project to OpenTimelineIO + Projekt se vyvádí do OpenTimelineIO + + + Project contains no sequences to export. + Projekt neobsahuje žádné úryvky k vyvedení. + + + Failed to serialize sequence "%1" + Nepodařilo se vydat na pokračování úryvek "%1" + + + + olive::ScopePanel + + Waveform + Tvar křivky + + + Histogram + Sloupcový graf + + + Scope + Oblast + + + + olive::SequenceDialog + + Name: + Název: + + + New Sequence + Nový úryvek + + + Editing "%1" + Upravuje se "%1" + + + Error editing Sequence + Chyba při upravování úryvku + + + Please enter a name for this Sequence. + Zadejte název tohoto úryvku. + + + + olive::SequenceDialogParameterTab + + Video + Obraz + + + Width: + Šířka: + + + Height: + Výška: + + + Frame Rate: + Snímkování: + + + Pixel Aspect Ratio: + Poměr stran pixelu: + + + Interlacing: + Prokládání: + + + Audio + Zvuk + + + Sample Rate: + Vzorkovací kmitočet: + + + Channels: + Kanály: + + + Preview + Náhled + + + Resolution: + Rozlišení: + + + Quality: + Jakost: + + + Save Preset + Uložit přednastavení + + + (%1x%2) + (%1x%2) + + + + olive::SequenceDialogPresetTab + + Preset + Přednastavení + + + My Presets + Moje přednastavení + + + 4K UHD + 4K UHD + + + 1080p + 1080p + + + 720p + 720p + + + NTSC + NTSC + + + PAL + PAL + + + %1 23.976 FPS + %1 23.976 snímků za sekundu + + + %1 25 FPS + %1 25 snímků za sekundu + + + %1 29.97 FPS + %1 29.97 snímků za sekundu + + + %1 50 FPS + %1 50 snímků za sekundu + + + %1 59.94 FPS + %1 59.94 snímků za sekundu + + + %1 Standard + %1 standard + + + %1 Widescreen + %1 širokoúhlé + + + Delete Preset + Smazat přednastavení + + + + olive::SequenceViewerPanel + + Sequence Viewer + Prohlížeč úryvku + + + + olive::SliderBase + + Invalid Value + Neplatná hodnota + + + The entered value is not valid for this field. + Zadaná hodnota není pro toto pole platná. + + + + olive::SolidGenerator + + Solid + Plná + + + Generate a solid color. + Vytvořit jednobarevné. + + + Color + Barva + + + + olive::StringSlider + + (none) + (žádný) + + + + olive::StrokeFilterNode + + Stroke + Tah + + + Creates a stroke outline around an image. + Vytvoří obrys tahu kolem obrázku. + + + Input + Vstup + + + Color + Barva + + + Radius + Poloměr + + + Opacity + Neprůhlednost + + + Inner + Vnitřní + + + + olive::Task + + Task + Úloha + + + Unknown error + Neznámá chyba + + + + olive::TaskDialog + + Task Failed + Úloha selhala + + + + olive::TaskManagerPanel + + Task Manager + Správce úloh + + + + olive::TaskViewItem + + Error: %1 + Chyba: %1 + + + + olive::TextGenerator + + Sample Text + Text příkladu + + + Text + Text + + + Generate rich text. + Vytvořit formátovaný text. + + + Font + Písmo + + + Font Size + Velikost písma + + + Color + Barva + + + Vertical Align + Zarovnat svisle + + + Top + Nahoře + + + Center + Na střed + + + Bottom + Dole + + + + olive::TimeBasedPanel + + (none) + (žádný) + + + + olive::TimeBasedWidget + + Set Marker + Nastavit značku + + + Marker name: + Název značky: + + + + olive::TimeInput + + Time + Čas + + + Generates the time (in seconds) at this frame + Vytvořit na tomto snímku čas (v sekundách) + + + + olive::TimelinePanel + + Timeline + Časová osa + + + + olive::TimelineWidget + + Properties + Vlastnosti + + + Use Audio Time Units + Použít jednotky času zvuku + + + + olive::ToolPanel + + Tools + Nástroje + + + + olive::Toolbar + + Pointer Tool + Ukazovátko + + + Edit Tool + Upravení + + + Ripple Tool + Vložení a posunutí + + + Rolling Tool + Válcování + + + Razor Tool + Břitva + + + Slip Tool + Skluz + + + Slide Tool + Posouvání + + + Hand Tool + Ručička + + + Zoom Tool + Zvětšení + + + Transition Tool + Přechod + + + Record Tool + Nahrávání + + + Add Tool + Přidání + + + Toggle Snapping + Přepnout přichytávání + + + + olive::TrackOutput + + Track + Stopa + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + Uzel pro znázornění a zpracování jednoho pole bloků seřazených podle času. Představuje také konec úryvku. + + + Blocks + Bloky + + + Muted + Ztlumeno + + + Video %1 + Obraz %1 + + + Audio %1 + Zvuk %1 + + + Subtitle %1 + Titulek %1 + + + Track %1 + Stopa %1 + + + + olive::TrackViewItem + + M + M + + + L + L + + + + olive::TransitionBlock + + From + Od + + + To + Do + + + Curve + Křivka + + + Linear + Lineární + + + Exponential + Exponenciální + + + Logarithmic + Logaritmický + + + + olive::TrigonometryNode + + Trigonometry + Trigonometrie + + + Perform a trigonometry operation on a value. + Provést s hodnotou trigonometrickou operaci. + + + Sine + Sinus + + + Cosine + Cosinus + + + Tangent + Tangens + + + Inverse Sine + Obrátit sinus + + + Inverse Cosine + Obrátit cosinus + + + Inverse Tangent + Obrátit tangens + + + Hyperbolic Sine + Hyperbolický sinus + + + Hyperbolic Cosine + Hyperbolický cosinus + + + Hyperbolic Tangent + Hyperbolický tangens + + + Method + Metoda + + + + olive::VideoDividerComboBox + + Full + Plný + + + 1/%1 + 1/%1 + + + + olive::VideoInput + + Video Input + Vstup obrazu + + + Video + Obraz + + + Import a video footage stream. + Zavést obrazový záznam. + + + + olive::VideoStreamProperties + + Pixel Aspect: + Poměr stran pixelu: + + + Interlacing: + Prokládání: + + + Color Space: + Barevný prostor: + + + Default (%1) + Výchozí (%1) + + + Premultiplied Alpha + Přednásobená alfa + + + Image Sequence + Obrázková řada + + + Start Index: + Počáteční číslo: + + + End Index: + Konečné číslo: + + + Frame Rate: + Snímkování: + + + Invalid Configuration + Neplatné nastavení + + + Image sequence end index must be a value higher than the start index. + Konečné číslo obrázkové řady musí být hodnota vyšší než počáteční číslo. + + + + olive::ViewerOutput + + Viewer + Prohlížeč + + + Interface between a Viewer panel and the node system. + Rozhraní mezi panelem prohlížeče a uzlovou soustavou. + + + Texture + Povrch + + + Samples + Vzorky + + + Video Tracks + Obrazové stopy + + + Audio Tracks + Zvukové stopy + + + Subtitle Tracks + Titulkové stopy + + + + olive::ViewerPanel + + Viewer + Prohlížeč + + + + olive::ViewerWidget + + Error + Chyba + + + No in or out points are set to cache. + Do vyrovnávací paměti nejsou nastaveny žádný bod začátku nebo konce. + + + Safe Margins + Bezpečné okraje + + + Zoom + Zvětšení + + + Fit + Přizpůsobit + + + %1% + %1% + + + Full Screen + Celá obrazovka + + + Screen %1: %2x%3 + Obrazovka %1: %2x%3 + + + Deinterlace + Zrušit prokládání + + + Scopes + Oblasti + + + Cache + Vyrovnávací paměť + + + Auto-Cache + Automatická vyrovnávací paměť + + + Pause Auto-Cache During Playback + Pozastavit automatickou vyrovnávací paměť během přehrávání + + + Cache Entire Sequence + Uložit celý úryvek do vyrovnávací paměti + + + Cache Sequence In/Out + Uložit začátek/konec úryvku do vyrovnávací paměti + + + Off + Vypnuto + + + On + Zapnuto + + + Custom Aspect + Vlastní poměr + + + Show Audio Waveform + Ukázat tvar křivky zvuku + + + + olive::VolumeNode + + Volume + Hlasitost + + + Adjusts the volume of an audio source. + Upraví hlasitost zvukového zdroje. + + + Samples + Vzorky + + + diff --git a/app/ts/de_DE.ts b/app/ts/de_DE.ts new file mode 100644 index 000000000..a565f5c74 --- /dev/null +++ b/app/ts/de_DE.ts @@ -0,0 +1,4767 @@ + + + + + AudioParams + + + %1 Hz + + + + + Mono + Mono + + + + Stereo + Stereo + + + + 2.1 + 144p {2.1?} + + + + 5.1 + 144p {5.1?} + + + + 7.1 + 144p {7.1?} + + + + Unknown (0x%1) + + + + + Config + + + Error loading settings + + + + + Failed to load application settings. This session will use defaults. + +%1 + + + + + Error saving settings + + + + + Failed to save application settings. The application may lack write permissions to this location. + + + + + Footage + + + %1 FPS + + + + + %1 Hz + + + + + Filename: %1 + + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + + + + + Automatically Detect Parameters From Footage + + + + + Set Parameters Manually + + + + + MoveItemCommand + + + Move Item + + + + + NodeCopyPasteWidget + + + Error pasting nodes + + + + + Failed to paste nodes: %1 + + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + + + + + Set preset name: + + + + + Invalid preset name + + + + + You must enter a preset name + + + + + Preset exists + + + + + A preset with this name already exists. Would you like to replace it? + + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + + + + + %1: Unknown + + + + + %1: Image - %2x%3 + + + + + %1: Video - %2x%3 + + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + + + + + Bars + Balken + + + + Solid + + + + + Title + Titel + + + + Tone + Ton + + + + Unknown + + + + + VideoParams + + + 8-bit + + + + + 16-bit Integer + + + + + Half-Float (16-bit) + + + + + Full-Float (32-bit) + + + + + Unknown (0x%1) + + + + + %1 FPS + + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + + + + + Show application version + + + + + Start in full-screen mode + + + + + Export only (No GUI) + + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + + + + + olive::AboutDialog + + + About %1 + + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive ist ein nicht-lineares Videoschnittprogramm. Diese Software ist frei und durch die GNU GPL geschützt. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + Das Olive Team ist dazu verpflichtet, die Nutzer darüber zu informieren, dass der Quellcode von der Webseite heruntergeladen werden kann. + + + + olive::ActionSearch + + + Search for action... + Nach Aktion suchen... + + + + olive::AudioInput + + + Audio Input + + + + + Audio + Audio + + + + Import an audio footage stream. + + + + + olive::AudioMonitorPanel + + + Audio Monitor + + + + + olive::Block + + + Length + Länge + + + + Media In + + + + + Enabled + + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + + + + + Blurs an image. + + + + + Input + + + + + Method + + + + + Box + + + + + Gaussian + + + + + Radius + + + + + Horizontal + + + + + Vertical + + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + + + + + A time-based node that represents a media source. + + + + + Buffer + + + + + olive::ColorDialog + + + Select Color + + + + + olive::ColorSpaceChooser + + + Color Management + + + + + Input: + + + + + Color Space: + + + + + Display: + + + + + View: + + + + + Look: + + + + + (None) + + + + + olive::ColorValuesTab + + + Red + + + + + Green + + + + + Blue + + + + + olive::ColorValuesWidget + + + Preview + + + + + Input + + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + Neuer Ordner: + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + Projekt speichern + + + + + Error + Fehler + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + + + + + Load Project + + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + + + + + Save All + + + + + Don't Save + + + + + Don't Save All + + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + Projekt öffnen + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + + + + + Send Error Report + + + + + Don't Send + + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CrossDissolveTransition + + + Cross Dissolve + + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + Linear + + + + Bezier + Bezier + + + + Hold + Halten + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + + + + + Disk Cache Settings + + + + + Maximum Disk Cache: + + + + + %1 GB + + + + + + + Clear Disk Cache + + + + + Automatically clear disk cache on close + + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + + + + + olive::DiskManager + + + + Disk Cache Error + + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + Erweitert + + + + Pixel + + + + + Pixel Format: + Pixelformat: + + + + Performance + + + + + Threads: + Threads: + + + + olive::ExportAudioTab + + + Codec: + Codec: + + + + Sample Rate: + Abtastrate: + + + + Channel Layout: + + + + + Format: + Format: + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + + + + + olive::ExportDialog + + + Filename: + Dateiname: + + + + Browse for exported file filename + + + + + Preset: + Vorgabe: + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + Bereich: + + + + Entire Sequence + Komplette Sequenz + + + + In to Out + In to Out + + + + Format: + Format: + + + + Export Video + + + + + Export Audio + + + + + Video + Video + + + + Audio + Audio + + + + + Export + Exportieren + + + + Preview + + + + + Invalid parameters + + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + + + + + olive::ExportTask + + + Exporting "%1" + + + + + Failed to create encoder + + + + + Failed to open file + + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + Breite: + + + + Height: + Höhe: + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + + + + + Fit + Einpassen + + + + Stretch + + + + + Crop + + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + Pixel-Seitenverhältnis: + + + + Interlacing: + Interlacing: + + + + Quality: + + + + + Codec + + + + + Codec: + Codec: + + + + Advanced + Erweitert + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + "%1" Eigenschaften + + + + Name: + Name: + + + + Tracks: + Spuren: + + + + olive::FootageRelinkDialog + + + Footage + + + + + Filename + + + + + Actions + + + + + Browse + Durchsuchen + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + Alle Dateien + + + + olive::FootageViewerPanel + + + Footage Viewer + + + + + olive::GapBlock + + + Gap + + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + + + + + Maximum Bit Rate (Mbps): + + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + Ziel-Dateigröße (MB): + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + + + + + Constant Rate Factor + + + + + Target Bit Rate + + + + + Target File Size + + + + + olive::ImageSection + + + Image Sequence: + + + + + olive::InterlacedComboBox + + + None (Progressive) + Keine (Progressive) + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + + + + + In: + + + + + Out: + + + + + Linear + Linear + + + + Hold + Halten + + + + Bezier + Bezier + + + + olive::KeyframeViewBase + + + Linear + Linear + + + + Bezier + Bezier + + + + Hold + Halten + + + + P&roperties + + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + + + + + Save '%1' &As + + + + + Close '%1' + + + + + Close All Except '%1' + + + + + &Save Project + &Projekt speichern + + + + Save Project &As + Projekt speichern &als... + + + + Close Project + + + + + Close All Except Current Project + + + + + (None) + + + + + &File + &Datei + + + + &New + &Neu + + + + &Open Project + Projekt &öffnen + + + + Open &Recent + + + + + &Clear Recent List + + + + + Sa&ve All Projects + + + + + &Import... + &Importieren... + + + + &Export + + + + + &Media... + + + + + &Project Properties... + + + + + Close All Projects + + + + + E&xit + B&eenden + + + + &Edit + &Bearbeiten + + + + Insert + + + + + Overwrite + + + + + Select &All + Alles &auswählen + + + + Deselect All + Auswahl aufheben + + + + Ripple to In Point + + + + + Ripple to Out Point + + + + + Edit to In Point + + + + + Edit to Out Point + + + + + Delete In/Out Point + + + + + Ripple Delete In/Out Point + + + + + Set/Edit Marker + Marker setzen/bearbeiten + + + + &View + &Ansicht + + + + Zoom In + + + + + Zoom Out + Herauszoomen + + + + Increase Track Height + Spurhöhe erhöhen + + + + Decrease Track Height + Spurhöhe verringern + + + + Toggle Show All + + + + + Full Screen + Vollbild + + + + Full Screen Viewer + Vollbild-Viewer + + + + &Playback + &Wiedergabe + + + + Go to Start + Zum Start gehen + + + + Previous Frame + Vorheriger Frame + + + + Play/Pause + Play/Pause + + + + Play In to Out + Von Anfang bis Ende wiedergeben + + + + Next Frame + Nächster Frame + + + + Go to End + Zum Ende springen + + + + Go to Previous Cut + Zum vorherigen Schnitt springen + + + + Go to Next Cut + Zum nächsten Schnitt springen + + + + Go to In Point + Zum Anfangspunkt springen + + + + Go to Out Point + Zum Endpunkt springen + + + + Shuttle Left + + + + + Shuttle Stop + + + + + Shuttle Right + + + + + Loop + Schleife + + + + &Sequence + &Sequenz + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Maximize Panel + Panel maximieren + + + + Lock Panels + Panel sperren + + + + Reset to Default Layout + Zum Standard-Layout zurücksetzen + + + + &Tools + &Werkzeuge + + + + Pointer Tool + + + + + Edit Tool + Bearbeitungs-Werkzeug + + + + Ripple Tool + Ripple-Werkzeug + + + + Rolling Tool + + + + + Razor Tool + Schneide-Werkzeug + + + + Slip Tool + + + + + Slide Tool + + + + + Hand Tool + Hand-Werkzeug + + + + Zoom Tool + + + + + Transition Tool + Übergangs-Werkzeug + + + + Enable Snapping + Snapping aktivieren + + + + Preferences + Einstellungen + + + + &Help + &Hilfe + + + + A&ction Search + &Aktionensuche + + + + Send &Feedback... + + + + + &About... + &Über... + + + + olive::MainStatusBar + + + Welcome to %1 %2 + Willkommen in %1 %2 + + + + Running %1 background tasks + + + + + olive::MainWindow + + + Driver Warning + + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + + + + + No color manager connected + + + + + Display + + + + + View + Ansicht + + + + Look + + + + + (None) + + + + + OpenColorIO Error + + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + Hinzufügen + + + + Subtract + + + + + Multiply + Vervielfachen + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + Position + + + + Rotation + Rotation + + + + Scale + Skalierung + + + + Uniform Scale + Einheitliche Skalierung + + + + Anchor Point + Ankerpunkt + + + + olive::MediaInput + + + Footage + + + + + olive::MenuShared + + + &Project + &Projekt + + + + &Sequence + &Sequenz + + + + &Folder + &Ordner + + + + Cu&t + &Ausschneiden + + + + Cop&y + &Kopieren + + + + &Paste + &Einfügen + + + + Paste Insert + + + + + Duplicate + Duplizieren + + + + Delete + Löschen + + + + Ripple Delete + Ripple Delete + + + + Split + Teilen + + + + Set In Point + Anfangspunkt festlegen + + + + Set Out Point + Endpunkt festlegen + + + + Reset In Point + Anfangspunkt zurücksetzen + + + + Reset Out Point + Endpunkt zurücksetzen + + + + Clear In/Out Point + Anfangs-/Endpunkt löschen + + + + Add Default Transition + Standardübergang einfügen + + + + Link/Unlink + Verbinden/Trennen + + + + Enable/Disable + Einblenden/Ausblenden + + + + Nest + Schachteln + + + + Frames + Frames + + + + Drop Frame + Drop Frame + + + + Non-Drop Frame + Non-Drop Frame + + + + Milliseconds + Millisekunden + + + + Seconds + + + + + olive::MergeNode + + + Merge + + + + + Merge two textures together. + + + + + Base + + + + + Blend + + + + + olive::Node + + + Input + + + + + Output + + + + + General + Allgemein + + + + Math + + + + + Color + Farbe + + + + Filter + + + + + Timeline + Timeline + + + + Generator + + + + + Channel + + + + + Transition + + + + + Uncategorized + + + + + olive::NodeInput + + + Input + + + + + olive::NodeOutput + + + Output + + + + + olive::NodePanel + + + Node Editor + + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + Farbe + + + + Matrix + + + + + Text + Text + + + + Font + Schriftart + + + + File + + + + + Texture + + + + + Samples + + + + + Footage + + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + + + + + Nothing + + + + + Disconnect + + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + Achtung + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + + + + + olive::NodeTableView + + + Type + Typ + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + (unbekannt) + + + + olive::NodeTreeView + + + Nodes + + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + + + + + Filter + + + + + Show All + + + + + Show Selected Blocks Only + + + + + Direction + + + + + Top to Bottom + + + + + Bottom to Top + + + + + Left to Right + + + + + Right to Left + + + + + Add + Hinzufügen + + + + olive::PanNode + + + + Pan + Schwenken + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + + + + + (none) + (keine) + + + + (multiple) + (mehrere) + + + + olive::PathWidget + + + Browse + Durchsuchen + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + Farbe + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + Farbe + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + Thema + + + + Node Color Scheme + + + + + olive::PreferencesAudioTab + + + Output Device: + Ausgabegerät: + + + + Input Device: + Eingabegerät: + + + + Sample Rate: + Abtastrate: + + + + Audio Recording: + Audioaufnahmen: + + + + Mono + Mono + + + + Stereo + Stereo + + + + Refresh Devices + + + + + Please wait... + + + + + Default + Standard + + + + olive::PreferencesBehaviorTab + + + Behavior + Verhalten + + + + General + Allgemein + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + Audio + + + + Enable audio scrubbing + + + + + Timeline + Timeline + + + + Auto-Seek to Imported Clips + + + + + Edit Tool Also Seeks + + + + + Edit Tool Selects Links + + + + + Enable Drag Files to Timeline + Dateien auf Timeline ziehen aktivieren + + + + Invert Timeline Scroll Axes + + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + + + + + Seek to the End of Pastes + + + + + Selecting Also Seeks + + + + + Playback + Wiedergabe + + + + Ask For Name When Setting Marker + Nach Namen fragen, wenn Marker gesetzt wird + + + + Automatically rewind at the end of a sequence + + + + + Project + Projekt + + + + Drop Files on Media to Replace + + + + + Nodes + + + + + Add Default Effects to New Clips + + + + + Auto-Scale By Default + Skaliere automatisch + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + Einstellungen + + + + General + Allgemein + + + + Appearance + Erscheinungsbild + + + + Behavior + Verhalten + + + + Disk + + + + + Audio + Audio + + + + Keyboard + Tastatur + + + + olive::PreferencesDiskTab + + + Disk Management + + + + + Disk Cache Location: + + + + + Disk Cache Settings + + + + + Cache Behavior + + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + Sprache: + + + + Auto-Scroll Method: + + + + + None + + + + + Page Scrolling + + + + + Smooth Scrolling + + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + Nach Eintrag oder Shortcut suchen + + + + Action + Eintrag + + + + Shortcut + Shortcut + + + + Import + Importieren + + + + Export + Exportieren + + + + Reset Selected + Ausgewählte zurücksetzen + + + + Reset All + Alle zurücksetzen + + + + Confirm Reset All Shortcuts + Bestätige das Zurücksetzen aller Shortcuts + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + Sind Sie sicher, dass Sie alle Tastatur-Shortcuts zurücksetzen wollen? + + + + Import Keyboard Shortcuts + Tastatur-Shortcuts importieren + + + + + Error saving shortcuts + Fehler beim Speichern der Shortcuts + + + + Failed to open file for reading + Fehler beim öffnen der Datei + + + + Export Keyboard Shortcuts + Tastatur-Shortcuts exportieren + + + + Export Shortcuts + Shortcuts exportieren + + + + Shortcuts exported successfully + Shortcuts wurden erfolgreich exportiert + + + + Failed to open file for writing + Fehler beim Schreiben der Datei + + + + olive::ProgressDialog + + + Cancel + Abbrechen + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + &Neu + + + + &Import... + &Importieren... + + + + &Project Properties... + + + + + Open in New Tab + + + + + Open in New Window + + + + + Reveal in Explorer + Im Explorer anzeigen + + + + Reveal in Finder + Im Finder anzeigen + + + + Reveal in File Manager + Im File Manager anzeigen + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + + + + + Project + Projekt + + + + (none) + (keine) + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + + + + + OpenColorIO Configuration: + + + + + (default) + + + + + Default Input Color Space: + + + + + Browse + Durchsuchen + + + + Color Management + + + + + Use Default Location + + + + + Store Alongside Project + + + + + Use Custom Location: + + + + + Disk Cache Settings + + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + + + + + OpenColorIO Config Error + + + + + Failed to set OpenColorIO configuration: %1 + + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + + + + + olive::ProjectSaveTask + + + Saving '%1' + + + + + Failed to write XML data + + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + + + + + Open Project + Projekt öffnen + + + + Save Project + Projekt speichern + + + + Undo + + + + + Redo + Wiederholen + + + + Search media, markers, etc. + + + + + Switch to Tree View + + + + + Switch to List View + + + + + Switch to Icon View + + + + + olive::ProjectViewModel + + + Name + Name + + + + Duration + Dauer + + + + Rate + Rate + + + + Move Items + + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + + + + + Bold + + + + + I + + + + + Italic + + + + + U + + + + + Underline + + + + + S + + + + + Strikethrough + + + + + Font Family + + + + + Font Size + + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + + + + + Histogram + + + + + Scope + + + + + olive::SequenceDialog + + + Name: + Name: + + + + New Sequence + Neue Sequenz + + + + Editing "%1" + Bearbeitung von "%1" + + + + Error editing Sequence + + + + + Please enter a name for this Sequence. + + + + + olive::SequenceDialogParameterTab + + + Video + Video + + + + Width: + Breite: + + + + Height: + Höhe: + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + Pixel-Seitenverhältnis: + + + + Interlacing: + Interlacing: + + + + Audio + Audio + + + + Sample Rate: + Abtastrate: + + + + Channels: + + + + + Preview + + + + + Resolution: + + + + + Quality: + + + + + Save Preset + + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + + + + + My Presets + + + + + 4K UHD + + + + + 1080p + 1080p + + + + 720p + 720p + + + + NTSC + + + + + PAL + + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + + + + + olive::SequenceViewerPanel + + + Sequence Viewer + + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + + + + + Generate a solid color. + + + + + Color + Farbe + + + + olive::StringSlider + + + (none) + (keine) + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + + + + + Color + Farbe + + + + Radius + + + + + Opacity + Deckkraft + + + + Inner + + + + + olive::Task + + + Task + + + + + Unknown error + + + + + olive::TaskDialog + + + Task Failed + + + + + olive::TaskManagerPanel + + + Task Manager + + + + + olive::TaskViewItem + + + Error: %1 + + + + + olive::TextGenerator + + + Sample Text + Beispieltext + + + + + Text + Text + + + + Generate rich text. + + + + + Font + Schriftart + + + + Font Size + + + + + Color + Farbe + + + + Vertical Align + + + + + Top + Oben + + + + Center + Mitte + + + + Bottom + Unten + + + + olive::TimeBasedPanel + + + (none) + (keine) + + + + olive::TimeBasedWidget + + + Set Marker + Marker setzen + + + + Marker name: + + + + + olive::TimeInput + + + Time + + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + Timeline + + + + olive::TimelineWidget + + + + Properties + Eigenschaften + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + + + + + olive::Toolbar + + + Pointer Tool + + + + + Edit Tool + Bearbeitungs-Werkzeug + + + + Ripple Tool + Ripple-Werkzeug + + + + Rolling Tool + + + + + Razor Tool + Schneide-Werkzeug + + + + Slip Tool + + + + + Slide Tool + + + + + Hand Tool + Hand-Werkzeug + + + + Zoom Tool + + + + + Transition Tool + Übergangs-Werkzeug + + + + Record Tool + + + + + Add Tool + + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + + + + + Audio %1 + + + + + Subtitle %1 + + + + + Track %1 + + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + + + + + Linear + Linear + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + + + + + Perform a trigonometry operation on a value. + + + + + Sine + Sinus + + + + Cosine + + + + + Tangent + + + + + Inverse Sine + + + + + Inverse Cosine + + + + + Inverse Tangent + + + + + Hyperbolic Sine + + + + + Hyperbolic Cosine + + + + + Hyperbolic Tangent + + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + 144p {1/%1?} + + + + olive::VideoInput + + + Video Input + + + + + Video + Video + + + + Import a video footage stream. + + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + Interlacing: + + + + Color Space: + + + + + Default (%1) + + + + + Premultiplied Alpha + + + + + Image Sequence + + + + + Start Index: + + + + + End Index: + + + + + Frame Rate: + + + + + Invalid Configuration + + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + + + + + Interface between a Viewer panel and the node system. + + + + + Texture + + + + + Samples + + + + + Video Tracks + + + + + Audio Tracks + + + + + Subtitle Tracks + + + + + olive::ViewerPanel + + + Viewer + + + + + olive::ViewerWidget + + + Error + Fehler + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + Zoom + + + + Fit + Einpassen + + + + %1% + + + + + Full Screen + Vollbild + + + + Screen %1: %2x%3 + Screen %1:%2x%3 + + + + Deinterlace + + + + + Scopes + + + + + Cache + + + + + Auto-Cache + + + + + Pause Auto-Cache During Playback + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Off + Aus + + + + On + + + + + Custom Aspect + + + + + Show Audio Waveform + + + + + olive::VolumeNode + + + + Volume + Lautstärke + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/en_US.ts b/app/ts/en_US.ts new file mode 100644 index 000000000..6e8cb8d60 --- /dev/null +++ b/app/ts/en_US.ts @@ -0,0 +1,4767 @@ + + + + + AudioParams + + + %1 Hz + + + + + Mono + + + + + Stereo + + + + + 2.1 + + + + + 5.1 + + + + + 7.1 + + + + + Unknown (0x%1) + + + + + Config + + + Error loading settings + + + + + Failed to load application settings. This session will use defaults. + +%1 + + + + + Error saving settings + + + + + Failed to save application settings. The application may lack write permissions to this location. + + + + + Footage + + + %1 FPS + + + + + %1 Hz + + + + + Filename: %1 + + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + + + + + Automatically Detect Parameters From Footage + + + + + Set Parameters Manually + + + + + MoveItemCommand + + + Move Item + + + + + NodeCopyPasteWidget + + + Error pasting nodes + + + + + Failed to paste nodes: %1 + + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + + + + + Set preset name: + + + + + Invalid preset name + + + + + You must enter a preset name + + + + + Preset exists + + + + + A preset with this name already exists. Would you like to replace it? + + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + + + + + %1: Unknown + + + + + %1: Image - %2x%3 + + + + + %1: Video - %2x%3 + + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + + + + + Bars + + + + + Solid + + + + + Title + + + + + Tone + + + + + Unknown + + + + + VideoParams + + + 8-bit + + + + + 16-bit Integer + + + + + Half-Float (16-bit) + + + + + Full-Float (32-bit) + + + + + Unknown (0x%1) + + + + + %1 FPS + + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + + + + + Show application version + + + + + Start in full-screen mode + + + + + Export only (No GUI) + + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + + + + + olive::AboutDialog + + + About %1 + + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + + + + + olive::ActionSearch + + + Search for action... + + + + + olive::AudioInput + + + Audio Input + + + + + Audio + + + + + Import an audio footage stream. + + + + + olive::AudioMonitorPanel + + + Audio Monitor + + + + + olive::Block + + + Length + + + + + Media In + + + + + Enabled + + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + + + + + Blurs an image. + + + + + Input + + + + + Method + + + + + Box + + + + + Gaussian + + + + + Radius + + + + + Horizontal + + + + + Vertical + + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + + + + + A time-based node that represents a media source. + + + + + Buffer + + + + + olive::ColorDialog + + + Select Color + + + + + olive::ColorSpaceChooser + + + Color Management + + + + + Input: + + + + + Color Space: + + + + + Display: + + + + + View: + + + + + Look: + + + + + (None) + + + + + olive::ColorValuesTab + + + Red + + + + + Green + + + + + Blue + + + + + olive::ColorValuesWidget + + + Preview + + + + + Input + + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + + + + + + Error + + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + + + + + Load Project + + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + + + + + Save All + + + + + Don't Save + + + + + Don't Save All + + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + + + + + Send Error Report + + + + + Don't Send + + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CrossDissolveTransition + + + Cross Dissolve + + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + + + + + Bezier + + + + + Hold + + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + + + + + Disk Cache Settings + + + + + Maximum Disk Cache: + + + + + %1 GB + + + + + + + Clear Disk Cache + + + + + Automatically clear disk cache on close + + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + + + + + olive::DiskManager + + + + Disk Cache Error + + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + + + + + Pixel + + + + + Pixel Format: + + + + + Performance + + + + + Threads: + + + + + olive::ExportAudioTab + + + Codec: + + + + + Sample Rate: + + + + + Channel Layout: + + + + + Format: + + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + + + + + olive::ExportDialog + + + Filename: + + + + + Browse for exported file filename + + + + + Preset: + + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + + + + + Entire Sequence + + + + + In to Out + + + + + Format: + + + + + Export Video + + + + + Export Audio + + + + + Video + + + + + Audio + + + + + + Export + + + + + Preview + + + + + Invalid parameters + + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + + + + + olive::ExportTask + + + Exporting "%1" + + + + + Failed to create encoder + + + + + Failed to open file + + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + + + + + Height: + + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + + + + + Fit + + + + + Stretch + + + + + Crop + + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + + + + + Interlacing: + + + + + Quality: + + + + + Codec + + + + + Codec: + + + + + Advanced + + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + + + + + Name: + + + + + Tracks: + + + + + olive::FootageRelinkDialog + + + Footage + + + + + Filename + + + + + Actions + + + + + Browse + + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + + + + + olive::FootageViewerPanel + + + Footage Viewer + + + + + olive::GapBlock + + + Gap + + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + + + + + Maximum Bit Rate (Mbps): + + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + + + + + Constant Rate Factor + + + + + Target Bit Rate + + + + + Target File Size + + + + + olive::ImageSection + + + Image Sequence: + + + + + olive::InterlacedComboBox + + + None (Progressive) + + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + + + + + In: + + + + + Out: + + + + + Linear + + + + + Hold + + + + + Bezier + + + + + olive::KeyframeViewBase + + + Linear + + + + + Bezier + + + + + Hold + + + + + P&roperties + + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + + + + + Save '%1' &As + + + + + Close '%1' + + + + + Close All Except '%1' + + + + + &Save Project + + + + + Save Project &As + + + + + Close Project + + + + + Close All Except Current Project + + + + + (None) + + + + + &File + + + + + &New + + + + + &Open Project + + + + + Open &Recent + + + + + &Clear Recent List + + + + + Sa&ve All Projects + + + + + &Import... + + + + + &Export + + + + + &Media... + + + + + &Project Properties... + + + + + Close All Projects + + + + + E&xit + + + + + &Edit + + + + + Insert + + + + + Overwrite + + + + + Select &All + + + + + Deselect All + + + + + Ripple to In Point + + + + + Ripple to Out Point + + + + + Edit to In Point + + + + + Edit to Out Point + + + + + Delete In/Out Point + + + + + Ripple Delete In/Out Point + + + + + Set/Edit Marker + + + + + &View + + + + + Zoom In + + + + + Zoom Out + + + + + Increase Track Height + + + + + Decrease Track Height + + + + + Toggle Show All + + + + + Full Screen + + + + + Full Screen Viewer + + + + + &Playback + + + + + Go to Start + + + + + Previous Frame + + + + + Play/Pause + + + + + Play In to Out + + + + + Next Frame + + + + + Go to End + + + + + Go to Previous Cut + + + + + Go to Next Cut + + + + + Go to In Point + + + + + Go to Out Point + + + + + Shuttle Left + + + + + Shuttle Stop + + + + + Shuttle Right + + + + + Loop + + + + + &Sequence + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Maximize Panel + + + + + Lock Panels + + + + + Reset to Default Layout + + + + + &Tools + + + + + Pointer Tool + + + + + Edit Tool + + + + + Ripple Tool + + + + + Rolling Tool + + + + + Razor Tool + + + + + Slip Tool + + + + + Slide Tool + + + + + Hand Tool + + + + + Zoom Tool + + + + + Transition Tool + + + + + Enable Snapping + + + + + Preferences + + + + + &Help + + + + + A&ction Search + + + + + Send &Feedback... + + + + + &About... + + + + + olive::MainStatusBar + + + Welcome to %1 %2 + + + + + Running %1 background tasks + + + + + olive::MainWindow + + + Driver Warning + + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + + + + + No color manager connected + + + + + Display + + + + + View + + + + + Look + + + + + (None) + + + + + OpenColorIO Error + + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + + + + + Subtract + + + + + Multiply + + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + + + + + Rotation + + + + + Scale + + + + + Uniform Scale + + + + + Anchor Point + + + + + olive::MediaInput + + + Footage + + + + + olive::MenuShared + + + &Project + + + + + &Sequence + + + + + &Folder + + + + + Cu&t + + + + + Cop&y + + + + + &Paste + + + + + Paste Insert + + + + + Duplicate + + + + + Delete + + + + + Ripple Delete + + + + + Split + + + + + Set In Point + + + + + Set Out Point + + + + + Reset In Point + + + + + Reset Out Point + + + + + Clear In/Out Point + + + + + Add Default Transition + + + + + Link/Unlink + + + + + Enable/Disable + + + + + Nest + + + + + Frames + + + + + Drop Frame + + + + + Non-Drop Frame + + + + + Milliseconds + + + + + Seconds + + + + + olive::MergeNode + + + Merge + + + + + Merge two textures together. + + + + + Base + + + + + Blend + + + + + olive::Node + + + Input + + + + + Output + + + + + General + + + + + Math + + + + + Color + + + + + Filter + + + + + Timeline + + + + + Generator + + + + + Channel + + + + + Transition + + + + + Uncategorized + + + + + olive::NodeInput + + + Input + + + + + olive::NodeOutput + + + Output + + + + + olive::NodePanel + + + Node Editor + + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + + + + + Matrix + + + + + Text + + + + + Font + + + + + File + + + + + Texture + + + + + Samples + + + + + Footage + + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + + + + + Nothing + + + + + Disconnect + + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + + + + + olive::NodeTableView + + + Type + + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + + + + + olive::NodeTreeView + + + Nodes + + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + + + + + Filter + + + + + Show All + + + + + Show Selected Blocks Only + + + + + Direction + + + + + Top to Bottom + + + + + Bottom to Top + + + + + Left to Right + + + + + Right to Left + + + + + Add + + + + + olive::PanNode + + + + Pan + + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + + + + + (none) + + + + + (multiple) + + + + + olive::PathWidget + + + Browse + + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + + + + + Node Color Scheme + + + + + olive::PreferencesAudioTab + + + Output Device: + + + + + Input Device: + + + + + Sample Rate: + + + + + Audio Recording: + + + + + Mono + + + + + Stereo + + + + + Refresh Devices + + + + + Please wait... + + + + + Default + + + + + olive::PreferencesBehaviorTab + + + Behavior + + + + + General + + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + + + + + Enable audio scrubbing + + + + + Timeline + + + + + Auto-Seek to Imported Clips + + + + + Edit Tool Also Seeks + + + + + Edit Tool Selects Links + + + + + Enable Drag Files to Timeline + + + + + Invert Timeline Scroll Axes + + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + + + + + Seek to the End of Pastes + + + + + Selecting Also Seeks + + + + + Playback + + + + + Ask For Name When Setting Marker + + + + + Automatically rewind at the end of a sequence + + + + + Project + + + + + Drop Files on Media to Replace + + + + + Nodes + + + + + Add Default Effects to New Clips + + + + + Auto-Scale By Default + + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + + + + + General + + + + + Appearance + + + + + Behavior + + + + + Disk + + + + + Audio + + + + + Keyboard + + + + + olive::PreferencesDiskTab + + + Disk Management + + + + + Disk Cache Location: + + + + + Disk Cache Settings + + + + + Cache Behavior + + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + + + + + Auto-Scroll Method: + + + + + None + + + + + Page Scrolling + + + + + Smooth Scrolling + + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + + + + + Action + + + + + Shortcut + + + + + Import + + + + + Export + + + + + Reset Selected + + + + + Reset All + + + + + Confirm Reset All Shortcuts + + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + + + + + Import Keyboard Shortcuts + + + + + + Error saving shortcuts + + + + + Failed to open file for reading + + + + + Export Keyboard Shortcuts + + + + + Export Shortcuts + + + + + Shortcuts exported successfully + + + + + Failed to open file for writing + + + + + olive::ProgressDialog + + + Cancel + + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + + + + + &Import... + + + + + &Project Properties... + + + + + Open in New Tab + + + + + Open in New Window + + + + + Reveal in Explorer + + + + + Reveal in Finder + + + + + Reveal in File Manager + + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + + + + + Project + + + + + (none) + + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + + + + + OpenColorIO Configuration: + + + + + (default) + + + + + Default Input Color Space: + + + + + Browse + + + + + Color Management + + + + + Use Default Location + + + + + Store Alongside Project + + + + + Use Custom Location: + + + + + Disk Cache Settings + + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + + + + + OpenColorIO Config Error + + + + + Failed to set OpenColorIO configuration: %1 + + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + + + + + olive::ProjectSaveTask + + + Saving '%1' + + + + + Failed to write XML data + + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + + + + + Open Project + + + + + Save Project + + + + + Undo + + + + + Redo + + + + + Search media, markers, etc. + + + + + Switch to Tree View + + + + + Switch to List View + + + + + Switch to Icon View + + + + + olive::ProjectViewModel + + + Name + + + + + Duration + + + + + Rate + + + + + Move Items + + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + + + + + Bold + + + + + I + + + + + Italic + + + + + U + + + + + Underline + + + + + S + + + + + Strikethrough + + + + + Font Family + + + + + Font Size + + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + + + + + Histogram + + + + + Scope + + + + + olive::SequenceDialog + + + Name: + + + + + New Sequence + + + + + Editing "%1" + + + + + Error editing Sequence + + + + + Please enter a name for this Sequence. + + + + + olive::SequenceDialogParameterTab + + + Video + + + + + Width: + + + + + Height: + + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + + + + + Interlacing: + + + + + Audio + + + + + Sample Rate: + + + + + Channels: + + + + + Preview + + + + + Resolution: + + + + + Quality: + + + + + Save Preset + + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + + + + + My Presets + + + + + 4K UHD + + + + + 1080p + + + + + 720p + + + + + NTSC + + + + + PAL + + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + + + + + olive::SequenceViewerPanel + + + Sequence Viewer + + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + + + + + Generate a solid color. + + + + + Color + + + + + olive::StringSlider + + + (none) + + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + + + + + Color + + + + + Radius + + + + + Opacity + + + + + Inner + + + + + olive::Task + + + Task + + + + + Unknown error + + + + + olive::TaskDialog + + + Task Failed + + + + + olive::TaskManagerPanel + + + Task Manager + + + + + olive::TaskViewItem + + + Error: %1 + + + + + olive::TextGenerator + + + Sample Text + + + + + + Text + + + + + Generate rich text. + + + + + Font + + + + + Font Size + + + + + Color + + + + + Vertical Align + + + + + Top + + + + + Center + + + + + Bottom + + + + + olive::TimeBasedPanel + + + (none) + + + + + olive::TimeBasedWidget + + + Set Marker + + + + + Marker name: + + + + + olive::TimeInput + + + Time + + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + + + + + olive::TimelineWidget + + + + Properties + + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + + + + + olive::Toolbar + + + Pointer Tool + + + + + Edit Tool + + + + + Ripple Tool + + + + + Rolling Tool + + + + + Razor Tool + + + + + Slip Tool + + + + + Slide Tool + + + + + Hand Tool + + + + + Zoom Tool + + + + + Transition Tool + + + + + Record Tool + + + + + Add Tool + + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + + + + + Audio %1 + + + + + Subtitle %1 + + + + + Track %1 + + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + + + + + Linear + + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + + + + + Perform a trigonometry operation on a value. + + + + + Sine + + + + + Cosine + + + + + Tangent + + + + + Inverse Sine + + + + + Inverse Cosine + + + + + Inverse Tangent + + + + + Hyperbolic Sine + + + + + Hyperbolic Cosine + + + + + Hyperbolic Tangent + + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + + + + + olive::VideoInput + + + Video Input + + + + + Video + + + + + Import a video footage stream. + + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + + + + + Color Space: + + + + + Default (%1) + + + + + Premultiplied Alpha + + + + + Image Sequence + + + + + Start Index: + + + + + End Index: + + + + + Frame Rate: + + + + + Invalid Configuration + + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + + + + + Interface between a Viewer panel and the node system. + + + + + Texture + + + + + Samples + + + + + Video Tracks + + + + + Audio Tracks + + + + + Subtitle Tracks + + + + + olive::ViewerPanel + + + Viewer + + + + + olive::ViewerWidget + + + Error + + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + + + + + Fit + + + + + %1% + + + + + Full Screen + + + + + Screen %1: %2x%3 + + + + + Deinterlace + + + + + Scopes + + + + + Cache + + + + + Auto-Cache + + + + + Pause Auto-Cache During Playback + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Off + + + + + On + + + + + Custom Aspect + + + + + Show Audio Waveform + + + + + olive::VolumeNode + + + + Volume + + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/es_ES.ts b/app/ts/es_ES.ts new file mode 100644 index 000000000..c655010ac --- /dev/null +++ b/app/ts/es_ES.ts @@ -0,0 +1,4771 @@ + + + + + AudioParams + + + %1 Hz + + + + + Mono + + + + + Stereo + + + + + 2.1 + 144p {2.1?} + + + + 5.1 + 144p {5.1?} + + + + 7.1 + 144p {7.1?} + + + + Unknown (0x%1) + + + + + Config + + + Error loading settings + + + + + Failed to load application settings. This session will use defaults. + +%1 + + + + + Error saving settings + + + + + Failed to save application settings. The application may lack write permissions to this location. + + + + + Footage + + + %1 FPS + + + + + %1 Hz + + + + + Filename: %1 + + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + + + + + Automatically Detect Parameters From Footage + + + + + Set Parameters Manually + + + + + MoveItemCommand + + + Move Item + + + + + NodeCopyPasteWidget + + + Error pasting nodes + + + + + Failed to paste nodes: %1 + + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + + + + + Set preset name: + + + + + Invalid preset name + + + + + You must enter a preset name + + + + + Preset exists + + + + + A preset with this name already exists. Would you like to replace it? + + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + + + + + %1: Unknown + + + + + %1: Image - %2x%3 + + + + + %1: Video - %2x%3 + + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + + + + + Bars + Barras + + + + Solid + Sólido + + + + Title + Título + + + + Tone + Tono + + + + Unknown + + + + + VideoParams + + + 8-bit + 8-bit + + + + 16-bit Integer + 16-bit Entero + + + + Half-Float (16-bit) + Medio-Coma-Flotante (16-bit) + + + + Full-Float (32-bit) + Máximo-Coma-Flotante (32-bit) + + + + Unknown (0x%1) + + + + + %1 FPS + + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + + + + + Show application version + + + + + Start in full-screen mode + + + + + Export only (No GUI) + + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + + + + + olive::AboutDialog + + + About %1 + + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive es un editor de vídeo no lineal. Esta aplicación es gratuita y está protegida bajo la licencia GNU GPL. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + El equipo de Olive está obligado a informar a los usuarios que el código fuente de la aplicación esta disponible para su descarga desde su sitio web. + + + + olive::ActionSearch + + + Search for action... + Búsqueda de acción... + + + + olive::AudioInput + + + Audio Input + + + + + Audio + Audio + + + + Import an audio footage stream. + + + + + olive::AudioMonitorPanel + + + Audio Monitor + + + + + olive::Block + + + Length + Longitud + + + + Media In + + + + + Enabled + + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + + + + + Blurs an image. + + + + + Input + + + + + Method + + + + + Box + + + + + Gaussian + + + + + Radius + + + + + Horizontal + + + + + Vertical + + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + + + + + A time-based node that represents a media source. + + + + + Buffer + + + + + olive::ColorDialog + + + Select Color + + + + + olive::ColorSpaceChooser + + + Color Management + Manejo del color + + + + Input: + + + + + Color Space: + Espacio de color: + + + + Display: + Monitor: + + + + View: + Ver: + + + + Look: + Mira: + + + + (None) + (Nada) + + + + olive::ColorValuesTab + + + Red + + + + + Green + + + + + Blue + + + + + olive::ColorValuesWidget + + + Preview + + + + + Input + + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + Nueva Carpeta + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + Guardar Proyecto + + + + + Error + Error + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + + + + + Load Project + + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + Secuencia %1 + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + + + + + Save All + + + + + Don't Save + + + + + Don't Save All + + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + Abrir Proyecto + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + + + + + Send Error Report + + + + + Don't Send + + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CrossDissolveTransition + + + Cross Dissolve + Fundido Cruzado + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + Lineal + + + + Bezier + Bézier + + + + Hold + Mantener + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + + + + + Disk Cache Settings + + + + + Maximum Disk Cache: + + + + + %1 GB + + + + + + + Clear Disk Cache + + + + + Automatically clear disk cache on close + + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + + + + + olive::DiskManager + + + + Disk Cache Error + + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + Avanzado + + + + Pixel + + + + + Pixel Format: + Formato de Píxel: + + + + Performance + + + + + Threads: + Hilos (Threads): + + + + olive::ExportAudioTab + + + Codec: + Codificación (Códec): + + + + Sample Rate: + Frecuencia de muestreo: + + + + Channel Layout: + + + + + Format: + Formato: + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + + + + + olive::ExportDialog + + + Filename: + Nombre de Archivo: + + + + Browse for exported file filename + + + + + Preset: + Preestablecidos: + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + Rango: + + + + Entire Sequence + Secuencia entera + + + + In to Out + De entrada a salida + + + + Format: + Formato: + + + + Export Video + + + + + Export Audio + + + + + Video + Vídeo + + + + Audio + Audio + + + + + Export + Exportar + + + + Preview + + + + + Invalid parameters + + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + + + + + olive::ExportTask + + + Exporting "%1" + + + + + Failed to create encoder + + + + + Failed to open file + + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + Ancho: + + + + Height: + Alto: + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + + + + + Fit + Ajuste Automático + + + + Stretch + + + + + Crop + + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + Relación de aspecto de píxeles: + + + + Interlacing: + Entrelazado: + + + + Quality: + + + + + Codec + + + + + Codec: + Codificación (Códec): + + + + Advanced + Avanzado + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + "%1" Propiedades + + + + Name: + + + + + Tracks: + Pistas: + + + + olive::FootageRelinkDialog + + + Footage + + + + + Filename + + + + + Actions + + + + + Browse + Buscar + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + + + + + olive::FootageViewerPanel + + + Footage Viewer + + + + + olive::GapBlock + + + Gap + + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + + + + + Maximum Bit Rate (Mbps): + + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + Tamaño del archivo de destino (MB): + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + + + + + Constant Rate Factor + + + + + Target Bit Rate + + + + + Target File Size + + + + + olive::ImageSection + + + Image Sequence: + + + + + olive::InterlacedComboBox + + + None (Progressive) + Ninguno (Progresivo) + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + + + + + In: + + + + + Out: + + + + + Linear + Lineal + + + + Hold + Mantener + + + + Bezier + Bézier + + + + olive::KeyframeViewBase + + + Linear + Lineal + + + + Bezier + Bézier + + + + Hold + Mantener + + + + P&roperties + + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + + + + + Save '%1' &As + + + + + Close '%1' + + + + + Close All Except '%1' + + + + + &Save Project + &Guardar Proyecto + + + + Save Project &As + G&uardar Proyecto Como + + + + Close Project + + + + + Close All Except Current Project + + + + + (None) + (Nada) + + + + &File + &Archivo + + + + &New + &Nuevo + + + + &Open Project + &Abrir Proyecto + + + + Open &Recent + + + + + &Clear Recent List + + + + + Sa&ve All Projects + + + + + &Import... + &Importar... + + + + &Export + + + + + &Media... + + + + + &Project Properties... + + + + + Close All Projects + + + + + E&xit + &Cerrar la aplicación + + + + &Edit + &Editar + + + + Insert + + + + + Overwrite + + + + + Select &All + Seleccion&ar Todo + + + + Deselect All + Deseleccionar Todo + + + + Ripple to In Point + Extraer desde el punto de inicio del clip + + + + Ripple to Out Point + Extraer desde el punto final del clip + + + + Edit to In Point + Eliminar desde el punto de inicio del clip + + + + Edit to Out Point + Eliminar desde el punto final del clip + + + + Delete In/Out Point + Eliminar lo comprendido entre los puntos de Entrada/Salida + + + + Ripple Delete In/Out Point + Extraer lo comprendido entre los puntos de Entrada/Salida + + + + Set/Edit Marker + Establecer/Editar Marcador + + + + &View + &Ver + + + + Zoom In + + + + + Zoom Out + + + + + Increase Track Height + Aumentar la altura de la pista + + + + Decrease Track Height + Disminuir la altura de la pista + + + + Toggle Show All + Alternar Mostrar Todo + + + + Full Screen + Pantalla completa + + + + Full Screen Viewer + Visor a pantalla completa + + + + &Playback + &Reproducción + + + + Go to Start + Ir al inicio + + + + Previous Frame + Fotograma anterior + + + + Play/Pause + Reproducir/Pausar + + + + Play In to Out + Reproducir desde la marca de entrada a la marca de salida + + + + Next Frame + Siguiente fotograma + + + + Go to End + Ir al final + + + + Go to Previous Cut + Ir al corte anterior + + + + Go to Next Cut + Ir al siguiente corte + + + + Go to In Point + Ir al punto de entrada + + + + Go to Out Point + Ir al punto de salida + + + + Shuttle Left + Reproducir hacia la Izquierda (Inversa) + + + + Shuttle Stop + Parar la Reproducción + + + + Shuttle Right + Reproducir hacia la Derecha (Normal) + + + + Loop + Bucle (Loop) + + + + &Sequence + &Sequencia + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Maximize Panel + Maximizar Panel + + + + Lock Panels + Bloquear Paneles + + + + Reset to Default Layout + Restaurar valores por defecto de la interfaz + + + + &Tools + &Herramientas + + + + Pointer Tool + Puntero de Selección/Edición/Mover Clips + + + + Edit Tool + Herramienta de Selección + + + + Ripple Tool + Herramienta para Enrrollar/Desenrrollar + + + + Rolling Tool + + + + + Razor Tool + + + + + Slip Tool + Deslizar clip sin desplazar + + + + Slide Tool + Desplazar clip afectando a los clips contiguos + + + + Hand Tool + + + + + Zoom Tool + + + + + Transition Tool + Herramienta para Inserción de Transiciones + + + + Enable Snapping + Habilitar Imán de Ajuste + + + + Preferences + Preferencias + + + + &Help + A&yuda + + + + A&ction Search + &Buscar + + + + Send &Feedback... + + + + + &About... + &Acerca de... + + + + olive::MainStatusBar + + + Welcome to %1 %2 + Bienvenido a %1 %2 + + + + Running %1 background tasks + + + + + olive::MainWindow + + + Driver Warning + + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + + + + + No color manager connected + + + + + Display + + + + + View + Ver + + + + Look + + + + + (None) + (Nada) + + + + OpenColorIO Error + + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + Añadir + + + + Subtract + + + + + Multiply + + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + Posición + + + + Rotation + Rotación + + + + Scale + Escala + + + + Uniform Scale + Escala Uniforme + + + + Anchor Point + Punto de Ancla + + + + olive::MediaInput + + + Footage + + + + + olive::MenuShared + + + &Project + &Proyecto + + + + &Sequence + &Sequencia + + + + &Folder + &Carpeta + + + + Cu&t + + + + + Cop&y + &Copiar + + + + &Paste + &Pegar + + + + Paste Insert + Insertar (Pegar) + + + + Duplicate + Duplicar + + + + Delete + + + + + Ripple Delete + Extraer Selección (Elimina el hueco) + + + + Split + Dividir clips + + + + Set In Point + Establecer punto de entrada + + + + Set Out Point + Establecer punto de salida + + + + Reset In Point + Resetear punto de entrada + + + + Reset Out Point + Resetear punto de salida + + + + Clear In/Out Point + Limpiar puntos de Entrada/Salida + + + + Add Default Transition + Añadir Transición predeterminada + + + + Link/Unlink + Unir/Separar clips seleccionados + + + + Enable/Disable + Habilitar/Deshabilitar clips seleccionados + + + + Nest + Anidar selección en una secuencia + + + + Frames + Fotogramas + + + + Drop Frame + Descartar fotograma (Drop Frame) + + + + Non-Drop Frame + No descartar fotograma (Non-Drop Frame) + + + + Milliseconds + Milisegundos + + + + Seconds + + + + + olive::MergeNode + + + Merge + + + + + Merge two textures together. + + + + + Base + + + + + Blend + + + + + olive::Node + + + Input + + + + + Output + + + + + General + General + + + + Math + + + + + Color + Color + + + + Filter + + + + + Timeline + Línea de Tiempo + + + + Generator + + + + + Channel + + + + + Transition + + + + + Uncategorized + + + + + olive::NodeInput + + + Input + + + + + olive::NodeOutput + + + Output + + + + + olive::NodePanel + + + Node Editor + Editor de Nodos + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + Color + + + + Matrix + Matriz + + + + Text + Texto + + + + Font + Fuente + + + + File + + + + + Texture + Textura + + + + Samples + + + + + Footage + + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + + + + + Nothing + + + + + Disconnect + + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + + + + + olive::NodeTableView + + + Type + Tipo + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + (Desconocido) + + + + olive::NodeTreeView + + + Nodes + + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + + + + + Filter + + + + + Show All + + + + + Show Selected Blocks Only + + + + + Direction + + + + + Top to Bottom + + + + + Bottom to Top + + + + + Left to Right + + + + + Right to Left + + + + + Add + Añadir + + + + olive::PanNode + + + + Pan + Panorámica + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + + + + + (none) + + + + + (multiple) + (múltiple) + + + + olive::PathWidget + + + Browse + Buscar + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + Color + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + Color + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + Tema + + + + Node Color Scheme + + + + + olive::PreferencesAudioTab + + + Output Device: + Dispositivo de Salida: + + + + Input Device: + Dispositivo de Entrada: + + + + Sample Rate: + Frecuencia de muestreo: + + + + Audio Recording: + Grabación de audio en: + + + + Mono + + + + + Stereo + + + + + Refresh Devices + + + + + Please wait... + + + + + Default + Por defecto + + + + olive::PreferencesBehaviorTab + + + Behavior + Comportamiento + + + + General + General + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + Audio + + + + Enable audio scrubbing + + + + + Timeline + Línea de Tiempo + + + + Auto-Seek to Imported Clips + Búsqueda automática de clips importados + + + + Edit Tool Also Seeks + Poner el cursor de reproducción +al inicio de la selección + + + + Edit Tool Selects Links + La selección incluye +los clips vinculados + + + + Enable Drag Files to Timeline + Habilitar poder arrastrar archivos a la línea de tiempo + + + + Invert Timeline Scroll Axes + Rueda del ratón desplaza la línea de tiempo + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + El cursor de reproducción +selecciona los clips que cruza + + + + Seek to the End of Pastes + Desplazar el cursor al final de lo pegado + + + + Selecting Also Seeks + Al seleccionar un clip +poner el cursor en su inico + + + + Playback + Reproducir + + + + Ask For Name When Setting Marker + Preguntar por el nombre al insertar un marcador + + + + Automatically rewind at the end of a sequence + + + + + Project + Proyecto + + + + Drop Files on Media to Replace + Colocar archivos de medios para reemplazar + + + + Nodes + + + + + Add Default Effects to New Clips + Añadir efectos predeterminados a los nuevos clips + + + + Auto-Scale By Default + Escala automática por defecto + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + Preferencias + + + + General + General + + + + Appearance + Apariencia + + + + Behavior + Comportamiento + + + + Disk + + + + + Audio + Audio + + + + Keyboard + Atajos de Teclado + + + + olive::PreferencesDiskTab + + + Disk Management + + + + + Disk Cache Location: + + + + + Disk Cache Settings + + + + + Cache Behavior + + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + Idioma: + + + + Auto-Scroll Method: + + + + + None + + + + + Page Scrolling + + + + + Smooth Scrolling + + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + Buscar acción o atajo + + + + Action + Acción + + + + Shortcut + Atajo + + + + Import + Importar + + + + Export + Exportar + + + + Reset Selected + Restablecer lo Seleccionado + + + + Reset All + Restablecer Todo + + + + Confirm Reset All Shortcuts + Confirmar restablecer todos los accesos directos + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + ¿Está seguro de que desea restablecer todos los métodos abreviados de teclado a sus valores predeterminados? + + + + Import Keyboard Shortcuts + Importar Accesos Rápidos de Teclado + + + + + Error saving shortcuts + Error al guardar los Accesos Rápidos + + + + Failed to open file for reading + Error al abrir el archivo de lectura + + + + Export Keyboard Shortcuts + Exportar los Accesos Rápidos de Teclado + + + + Export Shortcuts + Exportar Accesos Rápidos + + + + Shortcuts exported successfully + Atajos exportados exitosamente + + + + Failed to open file for writing + Error al abrir el archivo para escribir + + + + olive::ProgressDialog + + + Cancel + Cancelar + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + &Nuevo + + + + &Import... + &Importar... + + + + &Project Properties... + + + + + Open in New Tab + + + + + Open in New Window + + + + + Reveal in Explorer + Revelar en el explorador + + + + Reveal in Finder + Revelar en el buscador + + + + Reveal in File Manager + Revelar en el administrador de archivos + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + + + + + Project + Proyecto + + + + (none) + + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + + + + + OpenColorIO Configuration: + + + + + (default) + + + + + Default Input Color Space: + Espacio de color de entrada predeterminado: + + + + Browse + Buscar + + + + Color Management + Manejo del color + + + + Use Default Location + + + + + Store Alongside Project + + + + + Use Custom Location: + + + + + Disk Cache Settings + + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + + + + + OpenColorIO Config Error + Error de configuración de OpenColorIO + + + + Failed to set OpenColorIO configuration: %1 + Error al establecer la configuración de OpenColorIO: %1 + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + Buscar la configuración OpenColorIO + + + + olive::ProjectSaveTask + + + Saving '%1' + + + + + Failed to write XML data + + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + + + + + Open Project + Abrir Proyecto + + + + Save Project + Guardar Proyecto + + + + Undo + Deshacer los cambiós + + + + Redo + + + + + Search media, markers, etc. + Buscar archivos multimedia, marcas, etc. + + + + Switch to Tree View + + + + + Switch to List View + + + + + Switch to Icon View + + + + + olive::ProjectViewModel + + + Name + Nombre + + + + Duration + Duración + + + + Rate + Velocidad + + + + Move Items + + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + + + + + Bold + Negrita + + + + I + + + + + Italic + + + + + U + + + + + Underline + + + + + S + + + + + Strikethrough + + + + + Font Family + + + + + Font Size + + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + + + + + Histogram + + + + + Scope + + + + + olive::SequenceDialog + + + Name: + + + + + New Sequence + Nueva Secuencia + + + + Editing "%1" + Edición "%1" + + + + Error editing Sequence + + + + + Please enter a name for this Sequence. + + + + + olive::SequenceDialogParameterTab + + + Video + Vídeo + + + + Width: + Ancho: + + + + Height: + Alto: + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + Relación de aspecto de píxeles: + + + + Interlacing: + Entrelazado: + + + + Audio + Audio + + + + Sample Rate: + Frecuencia de muestreo: + + + + Channels: + + + + + Preview + + + + + Resolution: + + + + + Quality: + + + + + Save Preset + + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + + + + + My Presets + + + + + 4K UHD + + + + + 1080p + 1080p + + + + 720p + 720p + + + + NTSC + + + + + PAL + + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + + + + + olive::SequenceViewerPanel + + + Sequence Viewer + Visor de Secuencias + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + Sólido + + + + Generate a solid color. + + + + + Color + Color + + + + olive::StringSlider + + + (none) + + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + + + + + Color + Color + + + + Radius + + + + + Opacity + Opacidad + + + + Inner + + + + + olive::Task + + + Task + + + + + Unknown error + + + + + olive::TaskDialog + + + Task Failed + + + + + olive::TaskManagerPanel + + + Task Manager + + + + + olive::TaskViewItem + + + Error: %1 + + + + + olive::TextGenerator + + + Sample Text + Texto de ejemplo + + + + + Text + Texto + + + + Generate rich text. + + + + + Font + Fuente + + + + Font Size + + + + + Color + Color + + + + Vertical Align + + + + + Top + Arriba + + + + Center + + + + + Bottom + Abajo + + + + olive::TimeBasedPanel + + + (none) + + + + + olive::TimeBasedWidget + + + Set Marker + Establecer Marca + + + + Marker name: + + + + + olive::TimeInput + + + Time + + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + Línea de Tiempo + + + + olive::TimelineWidget + + + + Properties + Propiedades + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + + + + + olive::Toolbar + + + Pointer Tool + Puntero de Selección/Edición/Mover Clips + + + + Edit Tool + Herramienta de Selección + + + + Ripple Tool + Herramienta para Enrrollar/Desenrrollar + + + + Rolling Tool + + + + + Razor Tool + + + + + Slip Tool + Deslizar clip sin desplazar + + + + Slide Tool + Desplazar clip afectando a los clips contiguos + + + + Hand Tool + + + + + Zoom Tool + + + + + Transition Tool + Herramienta para Inserción de Transiciones + + + + Record Tool + + + + + Add Tool + + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + Vídeo %1 + + + + Audio %1 + Audio %1 + + + + Subtitle %1 + Subtítulo %1 + + + + Track %1 + + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + + + + + Linear + Lineal + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + + + + + Perform a trigonometry operation on a value. + + + + + Sine + Sinusoidal + + + + Cosine + + + + + Tangent + + + + + Inverse Sine + + + + + Inverse Cosine + + + + + Inverse Tangent + + + + + Hyperbolic Sine + + + + + Hyperbolic Cosine + + + + + Hyperbolic Tangent + + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + 144p {1/%1?} + + + + olive::VideoInput + + + Video Input + + + + + Video + Vídeo + + + + Import a video footage stream. + + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + Entrelazado: + + + + Color Space: + Espacio de color: + + + + Default (%1) + + + + + Premultiplied Alpha + + + + + Image Sequence + + + + + Start Index: + + + + + End Index: + + + + + Frame Rate: + + + + + Invalid Configuration + + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + + + + + Interface between a Viewer panel and the node system. + + + + + Texture + Textura + + + + Samples + + + + + Video Tracks + + + + + Audio Tracks + + + + + Subtitle Tracks + + + + + olive::ViewerPanel + + + Viewer + + + + + olive::ViewerWidget + + + Error + Error + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + Zoom + + + + Fit + Ajuste Automático + + + + %1% + + + + + Full Screen + Pantalla completa + + + + Screen %1: %2x%3 + Pantalla %1: %2x%3 + + + + Deinterlace + + + + + Scopes + + + + + Cache + + + + + Auto-Cache + + + + + Pause Auto-Cache During Playback + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Off + Apagado + + + + On + + + + + Custom Aspect + + + + + Show Audio Waveform + + + + + olive::VolumeNode + + + + Volume + Volumen + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/fr_FR.ts b/app/ts/fr_FR.ts new file mode 100644 index 000000000..730dd10ce --- /dev/null +++ b/app/ts/fr_FR.ts @@ -0,0 +1,4767 @@ + + + + + AudioParams + + + %1 Hz + + + + + Mono + Mono + + + + Stereo + Stéréo + + + + 2.1 + 144p {2.1?} + + + + 5.1 + 144p {5.1?} + + + + 7.1 + 144p {7.1?} + + + + Unknown (0x%1) + + + + + Config + + + Error loading settings + + + + + Failed to load application settings. This session will use defaults. + +%1 + + + + + Error saving settings + + + + + Failed to save application settings. The application may lack write permissions to this location. + + + + + Footage + + + %1 FPS + + + + + %1 Hz + + + + + Filename: %1 + + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + + + + + Automatically Detect Parameters From Footage + + + + + Set Parameters Manually + + + + + MoveItemCommand + + + Move Item + + + + + NodeCopyPasteWidget + + + Error pasting nodes + + + + + Failed to paste nodes: %1 + + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + + + + + Set preset name: + + + + + Invalid preset name + + + + + You must enter a preset name + + + + + Preset exists + + + + + A preset with this name already exists. Would you like to replace it? + + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + + + + + %1: Unknown + + + + + %1: Image - %2x%3 + + + + + %1: Video - %2x%3 + + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + + + + + Bars + Barres + + + + Solid + + + + + Title + Titre + + + + Tone + Ton + + + + Unknown + + + + + VideoParams + + + 8-bit + + + + + 16-bit Integer + + + + + Half-Float (16-bit) + + + + + Full-Float (32-bit) + + + + + Unknown (0x%1) + + + + + %1 FPS + + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + + + + + Show application version + + + + + Start in full-screen mode + + + + + Export only (No GUI) + + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + + + + + olive::AboutDialog + + + About %1 + + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive est un logiciel de montage non-linéaire. Ce logiciel est libre et protégé par la licence GNU GPL. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + L'équipe d'Olive vous informe que le code source d'Olive est disponible au téléchargement sur son site Web. + + + + olive::ActionSearch + + + Search for action... + Rechercher une action… + + + + olive::AudioInput + + + Audio Input + + + + + Audio + Audio + + + + Import an audio footage stream. + + + + + olive::AudioMonitorPanel + + + Audio Monitor + + + + + olive::Block + + + Length + Longueur + + + + Media In + + + + + Enabled + + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + + + + + Blurs an image. + + + + + Input + + + + + Method + + + + + Box + + + + + Gaussian + + + + + Radius + + + + + Horizontal + + + + + Vertical + + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + + + + + A time-based node that represents a media source. + + + + + Buffer + + + + + olive::ColorDialog + + + Select Color + + + + + olive::ColorSpaceChooser + + + Color Management + + + + + Input: + + + + + Color Space: + + + + + Display: + + + + + View: + + + + + Look: + + + + + (None) + + + + + olive::ColorValuesTab + + + Red + + + + + Green + + + + + Blue + + + + + olive::ColorValuesWidget + + + Preview + + + + + Input + + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + Nouveau dossier + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + + + + + + Error + Erreur + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + + + + + Load Project + + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + + + + + Save All + + + + + Don't Save + + + + + Don't Save All + + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + + + + + Send Error Report + + + + + Don't Send + + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CrossDissolveTransition + + + Cross Dissolve + + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + Linéaire + + + + Bezier + Bézier + + + + Hold + Maintenir + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + + + + + Disk Cache Settings + + + + + Maximum Disk Cache: + + + + + %1 GB + + + + + + + Clear Disk Cache + + + + + Automatically clear disk cache on close + + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + + + + + olive::DiskManager + + + + Disk Cache Error + + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + Avancé + + + + Pixel + + + + + Pixel Format: + Format de pixel : + + + + Performance + + + + + Threads: + + + + + olive::ExportAudioTab + + + Codec: + Codec : + + + + Sample Rate: + Taux d'échantillonnage : + + + + Channel Layout: + + + + + Format: + Format : + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + + + + + olive::ExportDialog + + + Filename: + Nom de fichier : + + + + Browse for exported file filename + + + + + Preset: + Préréglage : + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + Plage : + + + + Entire Sequence + Séquence entière + + + + In to Out + Du point d'entrée au point de sortie + + + + Format: + Format : + + + + Export Video + + + + + Export Audio + + + + + Video + Vidéo + + + + Audio + Audio + + + + + Export + Exporter + + + + Preview + + + + + Invalid parameters + + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + + + + + olive::ExportTask + + + Exporting "%1" + + + + + Failed to create encoder + + + + + Failed to open file + + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + Largeur : + + + + Height: + Hauteur : + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + + + + + Fit + Ajuster + + + + Stretch + + + + + Crop + + + + + Frame Rate: + Images par seconde : + + + + Pixel Aspect Ratio: + Ratio des pixels : + + + + Interlacing: + Entrelacement : + + + + Quality: + + + + + Codec + + + + + Codec: + Codec : + + + + Advanced + Avancé + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + "%1" Propriétés + + + + Name: + Nom : + + + + Tracks: + Pistes : + + + + olive::FootageRelinkDialog + + + Footage + + + + + Filename + + + + + Actions + + + + + Browse + Parcourir + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + Tous les fichiers + + + + olive::FootageViewerPanel + + + Footage Viewer + + + + + olive::GapBlock + + + Gap + + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + + + + + Maximum Bit Rate (Mbps): + + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + Taille du fichier cible (Mo) : + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + + + + + Constant Rate Factor + + + + + Target Bit Rate + + + + + Target File Size + + + + + olive::ImageSection + + + Image Sequence: + + + + + olive::InterlacedComboBox + + + None (Progressive) + Aucun (Progressif) + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + + + + + In: + + + + + Out: + + + + + Linear + Linéaire + + + + Hold + Maintenir + + + + Bezier + Bézier + + + + olive::KeyframeViewBase + + + Linear + Linéaire + + + + Bezier + Bézier + + + + Hold + Maintenir + + + + P&roperties + + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + + + + + Save '%1' &As + + + + + Close '%1' + + + + + Close All Except '%1' + + + + + &Save Project + &Enregistrer le projet + + + + Save Project &As + Enregistrer le projet &sous + + + + Close Project + + + + + Close All Except Current Project + + + + + (None) + + + + + &File + &Fichier + + + + &New + &Nouveau + + + + &Open Project + &Ouvrir un projet + + + + Open &Recent + + + + + &Clear Recent List + + + + + Sa&ve All Projects + + + + + &Import... + &Importer… + + + + &Export + + + + + &Media... + + + + + &Project Properties... + + + + + Close All Projects + + + + + E&xit + &Quitter + + + + &Edit + &Édition + + + + Insert + + + + + Overwrite + + + + + Select &All + Sélectionner &tout + + + + Deselect All + Tout désélectionner + + + + Ripple to In Point + Propager au point d'entrée + + + + Ripple to Out Point + Propager au point de sortie + + + + Edit to In Point + Éditer comme point d'entrée + + + + Edit to Out Point + Éditer comme point de sortie + + + + Delete In/Out Point + Supprimer les points d'entrée/de sortie + + + + Ripple Delete In/Out Point + Supprimer et raccorder au point d'entrée/de sortie + + + + Set/Edit Marker + Définir/Éditer un marqueur + + + + &View + &Affichage + + + + Zoom In + + + + + Zoom Out + Dézoomer + + + + Increase Track Height + Augmenter la hauteur de piste + + + + Decrease Track Height + Diminuer la hauteur de piste + + + + Toggle Show All + Vue d'ensemble + + + + Full Screen + Plein-écran + + + + Full Screen Viewer + Lecteur en plein écran + + + + &Playback + &Lecture + + + + Go to Start + Aller au début + + + + Previous Frame + Image précédente + + + + Play/Pause + Lire/Pause + + + + Play In to Out + Lire entre les points d'entrée et de sortie + + + + Next Frame + Image suivante + + + + Go to End + Aller à la fin + + + + Go to Previous Cut + Aller au point d'édition précédent + + + + Go to Next Cut + Aller au point d'édition suivant + + + + Go to In Point + Aller au point d'entrée + + + + Go to Out Point + Aller au point de sortie + + + + Shuttle Left + Jouer vers la gauche + + + + Shuttle Stop + Arrêter + + + + Shuttle Right + Jouer vers la droite + + + + Loop + Boucle + + + + &Sequence + &Séquence + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Maximize Panel + Agrandir le panneau + + + + Lock Panels + + + + + Reset to Default Layout + Restaurer la disposition par défaut + + + + &Tools + &Outils + + + + Pointer Tool + Curseur + + + + Edit Tool + Éditer + + + + Ripple Tool + Propagation + + + + Rolling Tool + + + + + Razor Tool + Cutter + + + + Slip Tool + Déplacer dessous + + + + Slide Tool + Déplacer dessus + + + + Hand Tool + Main + + + + Zoom Tool + + + + + Transition Tool + Transition + + + + Enable Snapping + Autoriser le magnétisme + + + + Preferences + Préférences + + + + &Help + &Aide + + + + A&ction Search + Chercher une a&ction + + + + Send &Feedback... + + + + + &About... + &À propos… + + + + olive::MainStatusBar + + + Welcome to %1 %2 + Bienvenue à %1 %2 + + + + Running %1 background tasks + + + + + olive::MainWindow + + + Driver Warning + + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + + + + + No color manager connected + + + + + Display + + + + + View + Affichage + + + + Look + + + + + (None) + + + + + OpenColorIO Error + + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + Ajouter + + + + Subtract + + + + + Multiply + Multiplier + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + Position + + + + Rotation + Rotation + + + + Scale + Échelle + + + + Uniform Scale + Échelle uniforme + + + + Anchor Point + Point d'ancrage + + + + olive::MediaInput + + + Footage + + + + + olive::MenuShared + + + &Project + &Projet + + + + &Sequence + &Séquence + + + + &Folder + &Dossier + + + + Cu&t + &Couper + + + + Cop&y + Cop&ier + + + + &Paste + C&oller + + + + Paste Insert + Coller et Insérer + + + + Duplicate + Dupliquer + + + + Delete + Supprimer + + + + Ripple Delete + Supprimer et raccorder + + + + Split + Séparer + + + + Set In Point + Définir le point d'entrée + + + + Set Out Point + Définir le point de sortie + + + + Reset In Point + Réinitialiser le point d'entrée + + + + Reset Out Point + Réinitialiser le point de sortie + + + + Clear In/Out Point + Effacer le point d'entrée/de sortie + + + + Add Default Transition + Ajouter la transition par défaut + + + + Link/Unlink + Lier/Délier + + + + Enable/Disable + Activer/Désactiver + + + + Nest + Imbriquer + + + + Frames + Images + + + + Drop Frame + Drop Frame + + + + Non-Drop Frame + Non-Drop Frame + + + + Milliseconds + Millisecondes + + + + Seconds + + + + + olive::MergeNode + + + Merge + + + + + Merge two textures together. + + + + + Base + + + + + Blend + + + + + olive::Node + + + Input + + + + + Output + + + + + General + Général + + + + Math + + + + + Color + Couleur + + + + Filter + + + + + Timeline + Ligne du temps + + + + Generator + + + + + Channel + + + + + Transition + + + + + Uncategorized + + + + + olive::NodeInput + + + Input + + + + + olive::NodeOutput + + + Output + + + + + olive::NodePanel + + + Node Editor + + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + Couleur + + + + Matrix + + + + + Text + Texte + + + + Font + Police + + + + File + + + + + Texture + + + + + Samples + + + + + Footage + + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + + + + + Nothing + + + + + Disconnect + + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + Avertissement + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + + + + + olive::NodeTableView + + + Type + Type + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + (inconnu) + + + + olive::NodeTreeView + + + Nodes + + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + + + + + Filter + + + + + Show All + + + + + Show Selected Blocks Only + + + + + Direction + + + + + Top to Bottom + + + + + Bottom to Top + + + + + Left to Right + + + + + Right to Left + + + + + Add + Ajouter + + + + olive::PanNode + + + + Pan + Panoramique + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + + + + + (none) + (aucun) + + + + (multiple) + + + + + olive::PathWidget + + + Browse + Parcourir + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + Couleur + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + Couleur + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + + + + + Node Color Scheme + + + + + olive::PreferencesAudioTab + + + Output Device: + Système de sortie : + + + + Input Device: + Système d'entrée : + + + + Sample Rate: + Taux d'échantillonnage : + + + + Audio Recording: + Enregistrement audio : + + + + Mono + Mono + + + + Stereo + Stéréo + + + + Refresh Devices + + + + + Please wait... + + + + + Default + + + + + olive::PreferencesBehaviorTab + + + Behavior + Comportement + + + + General + Général + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + Audio + + + + Enable audio scrubbing + + + + + Timeline + Ligne du temps + + + + Auto-Seek to Imported Clips + + + + + Edit Tool Also Seeks + Éditer déplace la tête de lecture + + + + Edit Tool Selects Links + Éditer sélectionne les liens + + + + Enable Drag Files to Timeline + Autoriser le dépôt de fichier sur la ligne de temps + + + + Invert Timeline Scroll Axes + + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + Sélectionner avec la tête de lecture + + + + Seek to the End of Pastes + Placer la tête de lecture après le collage + + + + Selecting Also Seeks + Sélectionner déplace la tête de lecture + + + + Playback + Lecture + + + + Ask For Name When Setting Marker + Demander un nom à la création d'un marqueur + + + + Automatically rewind at the end of a sequence + + + + + Project + Projet + + + + Drop Files on Media to Replace + + + + + Nodes + + + + + Add Default Effects to New Clips + + + + + Auto-Scale By Default + Échelle automatique par défaut + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + Préférences + + + + General + Général + + + + Appearance + + + + + Behavior + Comportement + + + + Disk + + + + + Audio + Audio + + + + Keyboard + Clavier + + + + olive::PreferencesDiskTab + + + Disk Management + + + + + Disk Cache Location: + + + + + Disk Cache Settings + + + + + Cache Behavior + + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + Langue : + + + + Auto-Scroll Method: + + + + + None + + + + + Page Scrolling + + + + + Smooth Scrolling + + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + Rechercher une action ou un raccourci + + + + Action + Action + + + + Shortcut + Raccourci + + + + Import + Importer + + + + Export + Exporter + + + + Reset Selected + Réinitialiser la sélection + + + + Reset All + Tout réinitialiser + + + + Confirm Reset All Shortcuts + Confirmez la réinitialisation de tous les raccourcis clavier + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + Êtes-vous sûr⋅e de vouloir réinitialiser tous les raccourcis clavier à leur valeur par défaut ? + + + + Import Keyboard Shortcuts + Importer les raccourcis clavier + + + + + Error saving shortcuts + Erreur dans l'enregistrement des raccourcis + + + + Failed to open file for reading + Échec de l'ouverture du fichier + + + + Export Keyboard Shortcuts + Exporter les raccourcis clavier + + + + Export Shortcuts + Exporter les raccourcis + + + + Shortcuts exported successfully + Les raccourcis ont été exporté avec succès + + + + Failed to open file for writing + Échec de l'ouverture du fichier + + + + olive::ProgressDialog + + + Cancel + Annuler + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + &Nouveau + + + + &Import... + &Importer… + + + + &Project Properties... + + + + + Open in New Tab + + + + + Open in New Window + + + + + Reveal in Explorer + Montrer dans l'explorateur + + + + Reveal in Finder + Montrer dans le Finder + + + + Reveal in File Manager + Montrer dans le gestionnaire de fichiers + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + + + + + Project + Projet + + + + (none) + (aucun) + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + + + + + OpenColorIO Configuration: + + + + + (default) + + + + + Default Input Color Space: + + + + + Browse + Parcourir + + + + Color Management + + + + + Use Default Location + + + + + Store Alongside Project + + + + + Use Custom Location: + + + + + Disk Cache Settings + + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + + + + + OpenColorIO Config Error + + + + + Failed to set OpenColorIO configuration: %1 + + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + + + + + olive::ProjectSaveTask + + + Saving '%1' + + + + + Failed to write XML data + + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + + + + + Open Project + + + + + Save Project + + + + + Undo + + + + + Redo + Rétablir + + + + Search media, markers, etc. + Rechercher des médias, marqueurs, etc. + + + + Switch to Tree View + + + + + Switch to List View + + + + + Switch to Icon View + + + + + olive::ProjectViewModel + + + Name + Nom + + + + Duration + Durée + + + + Rate + Images par seconde + + + + Move Items + + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + + + + + Bold + + + + + I + + + + + Italic + + + + + U + + + + + Underline + + + + + S + + + + + Strikethrough + + + + + Font Family + + + + + Font Size + + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + + + + + Histogram + + + + + Scope + + + + + olive::SequenceDialog + + + Name: + Nom : + + + + New Sequence + Nouvelle séquence + + + + Editing "%1" + Édition "%1" + + + + Error editing Sequence + + + + + Please enter a name for this Sequence. + + + + + olive::SequenceDialogParameterTab + + + Video + Vidéo + + + + Width: + Largeur : + + + + Height: + Hauteur : + + + + Frame Rate: + Images par seconde : + + + + Pixel Aspect Ratio: + Ratio des pixels : + + + + Interlacing: + Entrelacement : + + + + Audio + Audio + + + + Sample Rate: + Taux d'échantillonnage : + + + + Channels: + + + + + Preview + + + + + Resolution: + + + + + Quality: + + + + + Save Preset + + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + + + + + My Presets + + + + + 4K UHD + + + + + 1080p + 1080p + + + + 720p + 720p + + + + NTSC + + + + + PAL + + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + + + + + olive::SequenceViewerPanel + + + Sequence Viewer + Lecteur de séquence + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + + + + + Generate a solid color. + + + + + Color + Couleur + + + + olive::StringSlider + + + (none) + (aucun) + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + + + + + Color + Couleur + + + + Radius + + + + + Opacity + Opacité + + + + Inner + + + + + olive::Task + + + Task + + + + + Unknown error + + + + + olive::TaskDialog + + + Task Failed + + + + + olive::TaskManagerPanel + + + Task Manager + + + + + olive::TaskViewItem + + + Error: %1 + + + + + olive::TextGenerator + + + Sample Text + Texte d'exemple + + + + + Text + Texte + + + + Generate rich text. + + + + + Font + Police + + + + Font Size + + + + + Color + Couleur + + + + Vertical Align + + + + + Top + En haut + + + + Center + Centrer + + + + Bottom + En bas + + + + olive::TimeBasedPanel + + + (none) + (aucun) + + + + olive::TimeBasedWidget + + + Set Marker + Définir un marqueur + + + + Marker name: + + + + + olive::TimeInput + + + Time + + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + Ligne du temps + + + + olive::TimelineWidget + + + + Properties + + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + + + + + olive::Toolbar + + + Pointer Tool + Curseur + + + + Edit Tool + Éditer + + + + Ripple Tool + Propagation + + + + Rolling Tool + + + + + Razor Tool + Cutter + + + + Slip Tool + Déplacer dessous + + + + Slide Tool + Déplacer dessus + + + + Hand Tool + Main + + + + Zoom Tool + + + + + Transition Tool + Transition + + + + Record Tool + + + + + Add Tool + + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + + + + + Audio %1 + + + + + Subtitle %1 + + + + + Track %1 + + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + + + + + Linear + Linéaire + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + + + + + Perform a trigonometry operation on a value. + + + + + Sine + + + + + Cosine + + + + + Tangent + + + + + Inverse Sine + + + + + Inverse Cosine + + + + + Inverse Tangent + + + + + Hyperbolic Sine + + + + + Hyperbolic Cosine + + + + + Hyperbolic Tangent + + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + 144p {1/%1?} + + + + olive::VideoInput + + + Video Input + + + + + Video + Vidéo + + + + Import a video footage stream. + + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + Entrelacement : + + + + Color Space: + + + + + Default (%1) + + + + + Premultiplied Alpha + + + + + Image Sequence + + + + + Start Index: + + + + + End Index: + + + + + Frame Rate: + Images par seconde : + + + + Invalid Configuration + + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + + + + + Interface between a Viewer panel and the node system. + + + + + Texture + + + + + Samples + + + + + Video Tracks + + + + + Audio Tracks + + + + + Subtitle Tracks + + + + + olive::ViewerPanel + + + Viewer + + + + + olive::ViewerWidget + + + Error + Erreur + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + Zoom + + + + Fit + Ajuster + + + + %1% + + + + + Full Screen + Plein-écran + + + + Screen %1: %2x%3 + Écran %1: %2x%3 + + + + Deinterlace + + + + + Scopes + + + + + Cache + + + + + Auto-Cache + + + + + Pause Auto-Cache During Playback + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Off + Désactivée + + + + On + + + + + Custom Aspect + + + + + Show Audio Waveform + + + + + olive::VolumeNode + + + + Volume + Volume + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/hr_HR.ts b/app/ts/hr_HR.ts new file mode 100644 index 000000000..304f3515d --- /dev/null +++ b/app/ts/hr_HR.ts @@ -0,0 +1,4773 @@ + + + + + AudioParams + + + %1 Hz + %1 Hz + + + + Mono + Mono + + + + Stereo + Stereo + + + + 2.1 + 2.1 + + + + 5.1 + 5.1 + + + + 7.1 + 7.1 + + + + Unknown (0x%1) + Nepoznato (0x%1) + + + + Config + + + Error loading settings + Greška pri učitavanju postavki + + + + Failed to load application settings. This session will use defaults. + +%1 + “Sesija” might not be the most adequate term for “session” + Neuspješno učitavanje postavki aplikacije. Ova sesija će koristiti zadane postavke. + +%1 + + + + Error saving settings + Greška pri spašavanju postavki + + + + Failed to save application settings. The application may lack write permissions for this location. + Neuspješno spašavanje postavki aplikacije. Aplikaciji možda nedostaju dopuštenja za pisanje u ovoj lokaciji. + + + + Footage + + + %1 FPS + + + + + %1 Hz + %1 Hz + + + + Filename: %1 + + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + + + + + Automatically Detect Parameters From Footage + + + + + Set Parameters Manually + + + + + MoveItemCommand + + + Move Item + + + + + NodeCopyPasteWidget + + + Error pasting nodes + + + + + Failed to paste nodes: %1 + + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + + + + + Set preset name: + + + + + Invalid preset name + + + + + You must enter a preset name + + + + + Preset exists + + + + + A preset with this name already exists. Would you like to replace it? + + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + + + + + %1: Unknown + + + + + %1: Image - %2x%3 + + + + + %1: Video - %2x%3 + + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + + + + + Bars + + + + + Solid + + + + + Title + + + + + Tone + + + + + Unknown + + + + + VideoParams + + + 8-bit + + + + + 16-bit Integer + + + + + Half-Float (16-bit) + + + + + Full-Float (32-bit) + + + + + Unknown (0x%1) + Nepoznato (0x%1) + + + + %1 FPS + + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + + + + + Show application version + + + + + Start in full-screen mode + + + + + Export only (No GUI) + + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + + + + + olive::AboutDialog + + + About %1 + O %1 + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive je nelinearni video uređivač. Ovaj softver je slobodan i zaštićen GNU GPL-om. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + Olive tim je pod obavezom da obavijesti korisnike da je Olive-ov izvorni kod dostupan za preuzimanje sa njegove web stranice. + + + + olive::ActionSearch + + + Search for action... + + + + + olive::AudioMonitorPanel + + + Audio Monitor + + + + + olive::Block + + + Length + + + + + Media In + + + + + Enabled + + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + + + + + Blurs an image. + + + + + Input + + + + + Method + + + + + Box + + + + + Gaussian + + + + + Radius + + + + + Horizontal + + + + + Vertical + + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + + + + + A time-based node that represents a media source. + + + + + Buffer + + + + + olive::ColorDialog + + + Select Color + + + + + olive::ColorSpaceChooser + + + Color Management + + + + + Input: + + + + + Color Space: + + + + + Display: + + + + + View: + + + + + Look: + + + + + (None) + + + + + olive::ColorValuesTab + + + Red + + + + + Green + + + + + Blue + + + + + olive::ColorValuesWidget + + + Preview + + + + + Input + + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + + + + + + Error + + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + + + + + Load Project + + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + + + + + Save All + + + + + Don't Save + + + + + Don't Save All + + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + + + + + Send Error Report + + + + + Don't Send + + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CrossDissolveTransition + + + Cross Dissolve + + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + + + + + Bezier + + + + + Hold + + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + + + + + Disk Cache Settings + + + + + Maximum Disk Cache: + + + + + %1 GB + + + + + + + Clear Disk Cache + + + + + Automatically clear disk cache on close + + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + + + + + olive::DiskManager + + + + Disk Cache Error + + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + + + + + Pixel + + + + + Pixel Format: + + + + + Performance + + + + + Threads: + + + + + olive::ExportAudioTab + + + Codec: + + + + + Sample Rate: + + + + + Channel Layout: + + + + + Format: + + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + + + + + olive::ExportDialog + + + Filename: + + + + + Browse for exported file filename + + + + + Preset: + + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + + + + + Entire Sequence + + + + + In to Out + + + + + Format: + + + + + Export Video + + + + + Export Audio + + + + + Video + + + + + Audio + + + + + + Export + + + + + Preview + + + + + Invalid parameters + + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + + + + + olive::ExportTask + + + Exporting "%1" + + + + + Failed to create encoder + + + + + Failed to open file + + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + + + + + Height: + + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + + + + + Fit + + + + + Stretch + + + + + Crop + + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + + + + + Interlacing: + + + + + Quality: + + + + + Codec + + + + + Codec: + + + + + Advanced + + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + + + + + Name: + + + + + Tracks: + + + + + olive::FootageRelinkDialog + + + Footage + + + + + Filename + + + + + Actions + + + + + Browse + + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + + + + + olive::FootageViewerPanel + + + Footage Viewer + + + + + olive::GapBlock + + + Gap + + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + + + + + Maximum Bit Rate (Mbps): + + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + + + + + Constant Rate Factor + + + + + Target Bit Rate + + + + + Target File Size + + + + + olive::ImageSection + + + Image Sequence: + + + + + olive::InterlacedComboBox + + + None (Progressive) + + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + + + + + In: + + + + + Out: + + + + + Linear + + + + + Hold + + + + + Bezier + + + + + olive::KeyframeViewBase + + + Linear + + + + + Bezier + + + + + Hold + + + + + P&roperties + + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + + + + + Save '%1' &As + + + + + Close '%1' + + + + + Close All Except '%1' + + + + + &Save Project + + + + + Save Project &As + + + + + Close Project + + + + + Close All Except Current Project + + + + + (None) + + + + + &File + + + + + &New + + + + + &Open Project + + + + + Open &Recent + + + + + &Clear Recent List + + + + + Sa&ve All Projects + + + + + &Import... + + + + + &Export + + + + + &Media... + + + + + &Project Properties... + + + + + Close All Projects + + + + + E&xit + + + + + &Edit + + + + + Insert + + + + + Overwrite + + + + + Select &All + + + + + Deselect All + + + + + Ripple to In Point + + + + + Ripple to Out Point + + + + + Edit to In Point + + + + + Edit to Out Point + + + + + Delete In/Out Point + + + + + Ripple Delete In/Out Point + + + + + Set/Edit Marker + + + + + &View + + + + + Zoom In + + + + + Zoom Out + + + + + Increase Track Height + + + + + Decrease Track Height + + + + + Toggle Show All + + + + + Full Screen + + + + + Full Screen Viewer + + + + + &Playback + + + + + Go to Start + + + + + Previous Frame + + + + + Play/Pause + + + + + Play In to Out + + + + + Next Frame + + + + + Go to End + + + + + Go to Previous Cut + + + + + Go to Next Cut + + + + + Go to In Point + + + + + Go to Out Point + + + + + Shuttle Left + + + + + Shuttle Stop + + + + + Shuttle Right + + + + + Loop + + + + + &Sequence + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + &Window + + + + + Maximize Panel + + + + + Lock Panels + + + + + Reset to Default Layout + + + + + &Tools + + + + + Pointer Tool + + + + + Edit Tool + + + + + Ripple Tool + + + + + Rolling Tool + + + + + Razor Tool + + + + + Slip Tool + + + + + Slide Tool + + + + + Hand Tool + + + + + Zoom Tool + + + + + Transition Tool + + + + + Enable Snapping + + + + + Preferences + + + + + &Help + + + + + A&ction Search + + + + + Send &Feedback... + + + + + &About... + + + + + olive::MainStatusBar + + + Welcome to %1 %2 + + + + + Running %1 background tasks + + + + + olive::MainWindow + + + Driver Warning + + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + + + + + No color manager connected + + + + + Display + + + + + View + + + + + Look + + + + + (None) + + + + + OpenColorIO Error + + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + + + + + Subtract + + + + + Multiply + + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + + + + + Rotation + + + + + Scale + + + + + Uniform Scale + + + + + Anchor Point + + + + + olive::MediaInput + + + + Media + + + + + Import footage into the node graph. + + + + + olive::MenuShared + + + &Project + + + + + &Sequence + + + + + &Folder + + + + + Cu&t + + + + + Cop&y + + + + + &Paste + + + + + Paste Insert + + + + + Duplicate + + + + + Delete + + + + + Ripple Delete + + + + + Split + + + + + Set In Point + + + + + Set Out Point + + + + + Reset In Point + + + + + Reset Out Point + + + + + Clear In/Out Point + + + + + Add Default Transition + + + + + Link/Unlink + + + + + Enable/Disable + + + + + Nest + + + + + Frames + + + + + Drop Frame + + + + + Non-Drop Frame + + + + + Milliseconds + + + + + Seconds + + + + + olive::MergeNode + + + Merge + + + + + Merge two textures together. + + + + + Base + + + + + Blend + + + + + olive::MosaicFilterNode + + + Texture + + + + + Horizontal + + + + + Vertical + + + + + Mosaic + + + + + Apply a pixelated mosaic filter to video. + + + + + olive::Node + + + Input + + + + + Output + + + + + General + + + + + Math + + + + + Color + + + + + Filter + + + + + Timeline + + + + + Generator + + + + + Channel + + + + + Transition + + + + + Uncategorized + + + + + olive::NodeInput + + + Input + + + + + olive::NodeOutput + + + Output + + + + + olive::NodePanel + + + Node Editor + + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + + + + + Matrix + + + + + Text + + + + + Font + + + + + File + + + + + Texture + + + + + Samples + + + + + Footage + + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + + + + + Nothing + + + + + Disconnect + + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + + + + + olive::NodeTableView + + + Type + + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + + + + + olive::NodeTreeView + + + Nodes + + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + + + + + Filter + + + + + Show All + + + + + Show Selected Blocks Only + + + + + Direction + + + + + Top to Bottom + + + + + Bottom to Top + + + + + Left to Right + + + + + Right to Left + + + + + Add + + + + + olive::PanNode + + + + Pan + + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + + + + + (none) + + + + + (multiple) + + + + + olive::PathWidget + + + Browse + + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + + + + + Node Color Scheme + + + + + olive::PreferencesAudioTab + + + Output Device: + + + + + Input Device: + + + + + Sample Rate: + + + + + Audio Recording: + + + + + Mono + Mono + + + + Stereo + Stereo + + + + Refresh Devices + + + + + Please wait... + + + + + Default + + + + + olive::PreferencesBehaviorTab + + + Behavior + + + + + General + + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + + + + + Enable audio scrubbing + + + + + Timeline + + + + + Auto-Seek to Imported Clips + + + + + Edit Tool Also Seeks + + + + + Edit Tool Selects Links + + + + + Enable Drag Files to Timeline + + + + + Invert Timeline Scroll Axes + + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + + + + + Seek to the End of Pastes + + + + + Selecting Also Seeks + + + + + Playback + + + + + Ask For Name When Setting Marker + + + + + Automatically rewind at the end of a sequence + + + + + Project + + + + + Drop Files on Media to Replace + + + + + Nodes + + + + + Add Default Effects to New Clips + + + + + Auto-Scale By Default + + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + + + + + General + + + + + Appearance + + + + + Behavior + + + + + Disk + + + + + Audio + + + + + Keyboard + + + + + olive::PreferencesDiskTab + + + Disk Management + + + + + Disk Cache Location: + + + + + Disk Cache Settings + + + + + Cache Behavior + + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + + + + + Auto-Scroll Method: + + + + + None + + + + + Page Scrolling + + + + + Smooth Scrolling + + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + + + + + Action + + + + + Shortcut + + + + + Import + + + + + Export + + + + + Reset Selected + + + + + Reset All + + + + + Confirm Reset All Shortcuts + + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + + + + + Import Keyboard Shortcuts + + + + + + Error saving shortcuts + + + + + Failed to open file for reading + + + + + Export Keyboard Shortcuts + + + + + Export Shortcuts + + + + + Shortcuts exported successfully + + + + + Failed to open file for writing + + + + + olive::ProgressDialog + + + Cancel + + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + + + + + &Import... + + + + + &Project Properties... + + + + + Open in New Tab + + + + + Open in New Window + + + + + Reveal in Explorer + + + + + Reveal in Finder + + + + + Reveal in File Manager + + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + + + + + Project + + + + + (none) + + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + + + + + OpenColorIO Configuration: + + + + + (default) + + + + + Default Input Color Space: + + + + + Browse + + + + + Color Management + + + + + Use Default Location + + + + + Store Alongside Project + + + + + Use Custom Location: + + + + + Disk Cache Settings + + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + + + + + OpenColorIO Config Error + + + + + Failed to set OpenColorIO configuration: %1 + + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + + + + + olive::ProjectSaveTask + + + Saving '%1' + + + + + Failed to write XML data + + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + + + + + Open Project + + + + + Save Project + + + + + Undo + + + + + Redo + + + + + Search media, markers, etc. + + + + + Switch to Tree View + + + + + Switch to List View + + + + + Switch to Icon View + + + + + olive::ProjectViewModel + + + Name + + + + + Duration + + + + + Rate + + + + + Move Items + + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + + + + + Bold + + + + + I + + + + + Italic + + + + + U + + + + + Underline + + + + + S + + + + + Strikethrough + + + + + Font Family + + + + + Font Size + + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + + + + + Histogram + + + + + Scope + + + + + olive::SequenceDialog + + + Name: + + + + + New Sequence + + + + + Editing "%1" + + + + + Error editing Sequence + + + + + Please enter a name for this Sequence. + + + + + olive::SequenceDialogParameterTab + + + Video + + + + + Width: + + + + + Height: + + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + + + + + Interlacing: + + + + + Audio + + + + + Sample Rate: + + + + + Channels: + + + + + Preview + + + + + Resolution: + + + + + Quality: + + + + + Save Preset + + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + + + + + My Presets + + + + + 4K UHD + + + + + 1080p + 1080p + + + + 720p + 720p + + + + NTSC + + + + + PAL + + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + + + + + olive::SequenceViewerPanel + + + Sequence Viewer + + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + + + + + Generate a solid color. + + + + + Color + + + + + olive::StringSlider + + + (none) + + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + + + + + Color + + + + + Radius + + + + + Opacity + + + + + Inner + + + + + olive::Task + + + Task + + + + + Unknown error + + + + + olive::TaskDialog + + + Task Failed + + + + + olive::TaskManagerPanel + + + Task Manager + + + + + olive::TaskViewItem + + + Error: %1 + + + + + olive::TextGenerator + + + Sample Text + + + + + + Text + + + + + Generate rich text. + + + + + Font + + + + + Font Size + + + + + Color + + + + + Vertical Align + + + + + Top + + + + + Center + + + + + Bottom + + + + + olive::TimeBasedPanel + + + (none) + + + + + olive::TimeBasedWidget + + + Set Marker + + + + + Marker name: + + + + + olive::TimeInput + + + Time + + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + + + + + olive::TimelineWidget + + + + Properties + + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + + + + + olive::Toolbar + + + Pointer Tool + + + + + Edit Tool + + + + + Ripple Tool + + + + + Rolling Tool + + + + + Razor Tool + + + + + Slip Tool + + + + + Slide Tool + + + + + Hand Tool + + + + + Zoom Tool + + + + + Transition Tool + + + + + Record Tool + + + + + Add Tool + + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + + + + + Audio %1 + + + + + Subtitle %1 + + + + + Track %1 + + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + + + + + Linear + + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + + + + + Perform a trigonometry operation on a value. + + + + + Sine + + + + + Cosine + + + + + Tangent + + + + + Inverse Sine + + + + + Inverse Cosine + + + + + Inverse Tangent + + + + + Hyperbolic Sine + + + + + Hyperbolic Cosine + + + + + Hyperbolic Tangent + + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + 1/%1 + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + + + + + Color Space: + + + + + Default (%1) + + + + + Premultiplied Alpha + + + + + Image Sequence + + + + + Start Index: + + + + + End Index: + + + + + Frame Rate: + + + + + Invalid Configuration + + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + + + + + Interface between a Viewer panel and the node system. + + + + + Texture + + + + + Samples + + + + + Video Tracks + + + + + Audio Tracks + + + + + Subtitle Tracks + + + + + olive::ViewerPanel + + + Viewer + + + + + olive::ViewerWidget + + + Error + + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + + + + + Fit + + + + + %1% + + + + + Full Screen + + + + + Screen %1: %2x%3 + + + + + Deinterlace + + + + + Scopes + + + + + Cache + + + + + Auto-Cache + + + + + Pause Auto-Cache During Playback + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Off + + + + + On + + + + + Custom Aspect + + + + + Show Audio Waveform + + + + + olive::VolumeNode + + + + Volume + + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/id_ID.ts b/app/ts/id_ID.ts new file mode 100644 index 000000000..6c9bc644e --- /dev/null +++ b/app/ts/id_ID.ts @@ -0,0 +1,4767 @@ + + + + + AudioParams + + + %1 Hz + + + + + Mono + Mono + + + + Stereo + Stereo + + + + 2.1 + + + + + 5.1 + + + + + 7.1 + + + + + Unknown (0x%1) + + + + + Config + + + Error loading settings + + + + + Failed to load application settings. This session will use defaults. + +%1 + + + + + Error saving settings + + + + + Failed to save application settings. The application may lack write permissions to this location. + + + + + Footage + + + %1 FPS + + + + + %1 Hz + + + + + Filename: %1 + + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + + + + + Automatically Detect Parameters From Footage + + + + + Set Parameters Manually + + + + + MoveItemCommand + + + Move Item + + + + + NodeCopyPasteWidget + + + Error pasting nodes + + + + + Failed to paste nodes: %1 + + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + + + + + Set preset name: + + + + + Invalid preset name + + + + + You must enter a preset name + + + + + Preset exists + + + + + A preset with this name already exists. Would you like to replace it? + + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + + + + + %1: Unknown + + + + + %1: Image - %2x%3 + + + + + %1: Video - %2x%3 + + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + + + + + Bars + + + + + Solid + + + + + Title + Judul + + + + Tone + Nada + + + + Unknown + + + + + VideoParams + + + 8-bit + + + + + 16-bit Integer + + + + + Half-Float (16-bit) + + + + + Full-Float (32-bit) + + + + + Unknown (0x%1) + + + + + %1 FPS + + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + + + + + Show application version + + + + + Start in full-screen mode + + + + + Export only (No GUI) + + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + + + + + olive::AboutDialog + + + About %1 + + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive adalah aplikasi pengedit video yang bersifat non-linier. Aplikasi ini bebas, gratis, dan terlindungi GNU GPL. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + Olive Team berkewajiban memberitahu pengguna bahwa kode sumber aplikasi ini dapat diunduh dari situs resminya. + + + + olive::ActionSearch + + + Search for action... + Cari Aksi... + + + + olive::AudioInput + + + Audio Input + + + + + Audio + + + + + Import an audio footage stream. + + + + + olive::AudioMonitorPanel + + + Audio Monitor + + + + + olive::Block + + + Length + Panjang + + + + Media In + + + + + Enabled + + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + + + + + Blurs an image. + + + + + Input + + + + + Method + + + + + Box + + + + + Gaussian + + + + + Radius + + + + + Horizontal + + + + + Vertical + + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + + + + + A time-based node that represents a media source. + + + + + Buffer + + + + + olive::ColorDialog + + + Select Color + + + + + olive::ColorSpaceChooser + + + Color Management + + + + + Input: + + + + + Color Space: + + + + + Display: + + + + + View: + + + + + Look: + + + + + (None) + + + + + olive::ColorValuesTab + + + Red + + + + + Green + + + + + Blue + + + + + olive::ColorValuesWidget + + + Preview + + + + + Input + + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + Folder Baru + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + Simpan Proyek + + + + + Error + + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + + + + + Load Project + + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + + + + + Save All + + + + + Don't Save + + + + + Don't Save All + + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + Buka Proyek + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + + + + + Send Error Report + + + + + Don't Send + + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CrossDissolveTransition + + + Cross Dissolve + + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + Linier + + + + Bezier + Kurva Bezier + + + + Hold + Tahan + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + + + + + Disk Cache Settings + + + + + Maximum Disk Cache: + + + + + %1 GB + + + + + + + Clear Disk Cache + + + + + Automatically clear disk cache on close + + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + + + + + olive::DiskManager + + + + Disk Cache Error + + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + Pengaturan Lanjut + + + + Pixel + + + + + Pixel Format: + Bentuk piksel: + + + + Performance + + + + + Threads: + Jumlah thread/utas: + + + + olive::ExportAudioTab + + + Codec: + Kodek: + + + + Sample Rate: + Laju sampel: + + + + Channel Layout: + + + + + Format: + + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + + + + + olive::ExportDialog + + + Filename: + Nama file: + + + + Browse for exported file filename + + + + + Preset: + + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + Sepanjang: + + + + Entire Sequence + Seluruh rangkaian + + + + In to Out + Masuk hingga Keluar + + + + Format: + + + + + Export Video + + + + + Export Audio + + + + + Video + + + + + Audio + + + + + + Export + Ekspor + + + + Preview + + + + + Invalid parameters + + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + + + + + olive::ExportTask + + + Exporting "%1" + + + + + Failed to create encoder + + + + + Failed to open file + + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + Lebar: + + + + Height: + Tinggi: + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + + + + + Fit + Pas + + + + Stretch + + + + + Crop + + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + Rasio aspek piksel: + + + + Interlacing: + Mode interlace: + + + + Quality: + + + + + Codec + + + + + Codec: + Kodek: + + + + Advanced + Pengaturan Lanjut + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + + + + + Name: + Nama: + + + + Tracks: + Daftar trek: + + + + olive::FootageRelinkDialog + + + Footage + + + + + Filename + + + + + Actions + + + + + Browse + Telusur + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + Semua file + + + + olive::FootageViewerPanel + + + Footage Viewer + + + + + olive::GapBlock + + + Gap + + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + + + + + Maximum Bit Rate (Mbps): + + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + Ukuran File yang Ditargetkan (MB): + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + + + + + Constant Rate Factor + + + + + Target Bit Rate + + + + + Target File Size + + + + + olive::ImageSection + + + Image Sequence: + + + + + olive::InterlacedComboBox + + + None (Progressive) + Tidak ada (Progresif) + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + + + + + In: + + + + + Out: + + + + + Linear + Linier + + + + Hold + Tahan + + + + Bezier + Kurva Bezier + + + + olive::KeyframeViewBase + + + Linear + Linier + + + + Bezier + Kurva Bezier + + + + Hold + Tahan + + + + P&roperties + + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + + + + + Save '%1' &As + + + + + Close '%1' + + + + + Close All Except '%1' + + + + + &Save Project + &Simpan Proyek + + + + Save Project &As + Simpan Proyek Seba&gai + + + + Close Project + + + + + Close All Except Current Project + + + + + (None) + + + + + &File + + + + + &New + &Buat + + + + &Open Project + Buka &Proyek + + + + Open &Recent + + + + + &Clear Recent List + + + + + Sa&ve All Projects + + + + + &Import... + &Impor... + + + + &Export + + + + + &Media... + + + + + &Project Properties... + + + + + Close All Projects + + + + + E&xit + &Keluar + + + + &Edit + + + + + Insert + + + + + Overwrite + + + + + Select &All + Seleksi &Semua + + + + Deselect All + Batalkan Semua Seleksi + + + + Ripple to In Point + Atur hingga Titik Masuk + + + + Ripple to Out Point + Atur hingga Titik Keluar + + + + Edit to In Point + Edit ke Titik Masuk + + + + Edit to Out Point + Edit ke Titik Keluar + + + + Delete In/Out Point + Hapus Titik Masuk/Keluar + + + + Ripple Delete In/Out Point + Hapus dan Sesuaikan Titik Masuk/Keluar + + + + Set/Edit Marker + Set/Edit Penanda + + + + &View + &Tampilan + + + + Zoom In + Perbesar Tampilan + + + + Zoom Out + Perkecil Tampilan + + + + Increase Track Height + Lebarkan Trek + + + + Decrease Track Height + Persempit Trek + + + + Toggle Show All + Perlihatkan Semua + + + + Full Screen + Layar Penuh + + + + Full Screen Viewer + Penampil Layar Penuh + + + + &Playback + &Pemutaran + + + + Go to Start + Lompat ke Awal + + + + Previous Frame + Frame sebelumnya + + + + Play/Pause + Mainkan/Berhenti + + + + Play In to Out + Mainkan dari Titik Masuk hingga Keluar + + + + Next Frame + Frame Berikutnya + + + + Go to End + Lompat ke Akhir + + + + Go to Previous Cut + Lompat ke Cut Sebelumnya + + + + Go to Next Cut + Lompat ke Cut Berikutnya + + + + Go to In Point + Lompat ke Titik Masuk + + + + Go to Out Point + Lompat ke Titik Keluar + + + + Shuttle Left + Jalankan ke Kiri + + + + Shuttle Stop + Hentikan jalan + + + + Shuttle Right + Jalankan ke Kanan + + + + Loop + Putar secara Berulang + + + + &Sequence + &Rangkaian Baru + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Maximize Panel + Lebarkan Panel + + + + Lock Panels + Kunci Panel + + + + Reset to Default Layout + Kembalikan Layout Semula + + + + &Tools + &Alat + + + + Pointer Tool + Alat Tunjuk + + + + Edit Tool + Alat Edit + + + + Ripple Tool + Alat Pengatur + + + + Rolling Tool + + + + + Razor Tool + Alat Potong + + + + Slip Tool + Alat Slip + + + + Slide Tool + Alat Geser Klip + + + + Hand Tool + Alat Geser Tampilan + + + + Zoom Tool + + + + + Transition Tool + Alat Transisi + + + + Enable Snapping + Nyalakan Lekatan + + + + Preferences + Preferensi + + + + &Help + &Bantuan + + + + A&ction Search + &Cari Aksi + + + + Send &Feedback... + + + + + &About... + &Tentang... + + + + olive::MainStatusBar + + + Welcome to %1 %2 + Selamat datang di %1 %2 + + + + Running %1 background tasks + + + + + olive::MainWindow + + + Driver Warning + + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + + + + + No color manager connected + + + + + Display + + + + + View + Tampilan + + + + Look + + + + + (None) + + + + + OpenColorIO Error + + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + Tambah + + + + Subtract + + + + + Multiply + + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + Posisi + + + + Rotation + Rotasi + + + + Scale + Ukuran + + + + Uniform Scale + Ukuran Merata + + + + Anchor Point + Titik Poros + + + + olive::MediaInput + + + Footage + + + + + olive::MenuShared + + + &Project + &Proyek Baru + + + + &Sequence + &Rangkaian Baru + + + + &Folder + &Folder Baru + + + + Cu&t + &Potong + + + + Cop&y + &Salin + + + + &Paste + &Tempel + + + + Paste Insert + Tempel dan Masukkan + + + + Duplicate + Gandakan + + + + Delete + Hapus + + + + Ripple Delete + Hapus dan Sesuaikan + + + + Split + Pisahkan + + + + Set In Point + Set Titik Masuk + + + + Set Out Point + Set Titik Keluar + + + + Reset In Point + Kembalikan Titik Masuk + + + + Reset Out Point + Kembalikan Titik Keluar + + + + Clear In/Out Point + Hapus Titik Masuk/Keluar + + + + Add Default Transition + Masukkan Transisi Biasa + + + + Link/Unlink + Tautkan/Lepaskan + + + + Enable/Disable + Nyalakan/Matikan + + + + Nest + Sarangkan + + + + Frames + Frame + + + + Drop Frame + + + + + Non-Drop Frame + + + + + Milliseconds + Milisekon + + + + Seconds + + + + + olive::MergeNode + + + Merge + + + + + Merge two textures together. + + + + + Base + + + + + Blend + + + + + olive::Node + + + Input + + + + + Output + + + + + General + + + + + Math + + + + + Color + Warna + + + + Filter + + + + + Timeline + Garis Waktu + + + + Generator + + + + + Channel + + + + + Transition + + + + + Uncategorized + + + + + olive::NodeInput + + + Input + + + + + olive::NodeOutput + + + Output + + + + + olive::NodePanel + + + Node Editor + + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + Warna + + + + Matrix + + + + + Text + Teks + + + + Font + Fon + + + + File + + + + + Texture + + + + + Samples + + + + + Footage + + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + + + + + Nothing + + + + + Disconnect + + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + + + + + olive::NodeTableView + + + Type + Tipe + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + (tidak diketahui) + + + + olive::NodeTreeView + + + Nodes + + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + + + + + Filter + + + + + Show All + + + + + Show Selected Blocks Only + + + + + Direction + + + + + Top to Bottom + + + + + Bottom to Top + + + + + Left to Right + + + + + Right to Left + + + + + Add + Tambah + + + + olive::PanNode + + + + Pan + Geser/Pan + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + + + + + (none) + (tidak ada) + + + + (multiple) + (beberapa) + + + + olive::PathWidget + + + Browse + Telusur + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + Warna + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + Warna + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + Tema + + + + Node Color Scheme + + + + + olive::PreferencesAudioTab + + + Output Device: + Peranti output: + + + + Input Device: + Peranti masukan: + + + + Sample Rate: + Laju sampel: + + + + Audio Recording: + Rekaman audio: + + + + Mono + Mono + + + + Stereo + Stereo + + + + Refresh Devices + + + + + Please wait... + + + + + Default + + + + + olive::PreferencesBehaviorTab + + + Behavior + Kelakuan + + + + General + + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + + + + + Enable audio scrubbing + + + + + Timeline + Garis Waktu + + + + Auto-Seek to Imported Clips + Geser hingga awal klip yang diimpor + + + + Edit Tool Also Seeks + + + + + Edit Tool Selects Links + + + + + Enable Drag Files to Timeline + + + + + Invert Timeline Scroll Axes + + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + + + + + Seek to the End of Pastes + + + + + Selecting Also Seeks + + + + + Playback + Pemutaran + + + + Ask For Name When Setting Marker + + + + + Automatically rewind at the end of a sequence + + + + + Project + Proyek + + + + Drop Files on Media to Replace + Lepas file pada media untuk menggantikan + + + + Nodes + + + + + Add Default Effects to New Clips + Tambahkan efek-efek biasa pada klip baru + + + + Auto-Scale By Default + + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + Preferensi + + + + General + + + + + Appearance + Penampilan + + + + Behavior + Kelakuan + + + + Disk + + + + + Audio + + + + + Keyboard + + + + + olive::PreferencesDiskTab + + + Disk Management + + + + + Disk Cache Location: + + + + + Disk Cache Settings + + + + + Cache Behavior + + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + Bahasa: + + + + Auto-Scroll Method: + + + + + None + + + + + Page Scrolling + + + + + Smooth Scrolling + + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + Cari aksi atau pintasan + + + + Action + Aksi + + + + Shortcut + Pintasan + + + + Import + Impor + + + + Export + Ekspor + + + + Reset Selected + Kembalikan Terseleksi + + + + Reset All + Kembalikan Semua + + + + Confirm Reset All Shortcuts + Konfirmasi + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + Anda akan mengembalikan semua pintasan keyboard seperti semula. Lanjut? + + + + Import Keyboard Shortcuts + Impor Pintasan Keyboard + + + + + Error saving shortcuts + Gagal menyimpan pintasan + + + + Failed to open file for reading + Gagal membuka file + + + + Export Keyboard Shortcuts + Ekspor Pintasan Keyboard + + + + Export Shortcuts + Ekspor Pintasan + + + + Shortcuts exported successfully + Pintasan berhasil diekspor + + + + Failed to open file for writing + Gagal membaca file + + + + olive::ProgressDialog + + + Cancel + Batalkan + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + &Buat + + + + &Import... + &Impor... + + + + &Project Properties... + + + + + Open in New Tab + + + + + Open in New Window + + + + + Reveal in Explorer + Buka di Explorer + + + + Reveal in Finder + Buka di Finder + + + + Reveal in File Manager + Buka di Manajer Berkas + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + + + + + Project + Proyek + + + + (none) + (tidak ada) + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + + + + + OpenColorIO Configuration: + + + + + (default) + + + + + Default Input Color Space: + + + + + Browse + Telusur + + + + Color Management + + + + + Use Default Location + + + + + Store Alongside Project + + + + + Use Custom Location: + + + + + Disk Cache Settings + + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + + + + + OpenColorIO Config Error + + + + + Failed to set OpenColorIO configuration: %1 + + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + + + + + olive::ProjectSaveTask + + + Saving '%1' + + + + + Failed to write XML data + + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + + + + + Open Project + Buka Proyek + + + + Save Project + Simpan Proyek + + + + Undo + Urung + + + + Redo + Ulangi + + + + Search media, markers, etc. + Cari media, penanda, dll. + + + + Switch to Tree View + + + + + Switch to List View + + + + + Switch to Icon View + + + + + olive::ProjectViewModel + + + Name + Nama + + + + Duration + Durasi + + + + Rate + Laju + + + + Move Items + + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + + + + + Bold + + + + + I + + + + + Italic + + + + + U + + + + + Underline + + + + + S + + + + + Strikethrough + + + + + Font Family + + + + + Font Size + + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + + + + + Histogram + + + + + Scope + + + + + olive::SequenceDialog + + + Name: + Nama: + + + + New Sequence + Rangkaian Baru + + + + Editing "%1" + Mengedit "%1" + + + + Error editing Sequence + + + + + Please enter a name for this Sequence. + + + + + olive::SequenceDialogParameterTab + + + Video + + + + + Width: + Lebar: + + + + Height: + Tinggi: + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + Rasio aspek piksel: + + + + Interlacing: + Mode interlace: + + + + Audio + + + + + Sample Rate: + Laju sampel: + + + + Channels: + + + + + Preview + + + + + Resolution: + + + + + Quality: + + + + + Save Preset + + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + + + + + My Presets + + + + + 4K UHD + + + + + 1080p + + + + + 720p + + + + + NTSC + + + + + PAL + + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + + + + + olive::SequenceViewerPanel + + + Sequence Viewer + + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + + + + + Generate a solid color. + + + + + Color + Warna + + + + olive::StringSlider + + + (none) + (tidak ada) + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + + + + + Color + Warna + + + + Radius + + + + + Opacity + + + + + Inner + + + + + olive::Task + + + Task + + + + + Unknown error + + + + + olive::TaskDialog + + + Task Failed + + + + + olive::TaskManagerPanel + + + Task Manager + + + + + olive::TaskViewItem + + + Error: %1 + + + + + olive::TextGenerator + + + Sample Text + Masukkan teks disini + + + + + Text + Teks + + + + Generate rich text. + + + + + Font + Fon + + + + Font Size + + + + + Color + Warna + + + + Vertical Align + + + + + Top + Atas + + + + Center + Tengah + + + + Bottom + Bawah + + + + olive::TimeBasedPanel + + + (none) + (tidak ada) + + + + olive::TimeBasedWidget + + + Set Marker + Masukkan Penanda + + + + Marker name: + + + + + olive::TimeInput + + + Time + + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + Garis Waktu + + + + olive::TimelineWidget + + + + Properties + Properti + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + + + + + olive::Toolbar + + + Pointer Tool + Alat Tunjuk + + + + Edit Tool + Alat Edit + + + + Ripple Tool + Alat Pengatur + + + + Rolling Tool + + + + + Razor Tool + Alat Potong + + + + Slip Tool + Alat Slip + + + + Slide Tool + Alat Geser Klip + + + + Hand Tool + Alat Geser Tampilan + + + + Zoom Tool + + + + + Transition Tool + Alat Transisi + + + + Record Tool + + + + + Add Tool + + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + + + + + Audio %1 + + + + + Subtitle %1 + + + + + Track %1 + + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + + + + + Linear + Linier + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + + + + + Perform a trigonometry operation on a value. + + + + + Sine + Sinus + + + + Cosine + + + + + Tangent + + + + + Inverse Sine + + + + + Inverse Cosine + + + + + Inverse Tangent + + + + + Hyperbolic Sine + + + + + Hyperbolic Cosine + + + + + Hyperbolic Tangent + + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + + + + + olive::VideoInput + + + Video Input + + + + + Video + + + + + Import a video footage stream. + + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + Mode interlace: + + + + Color Space: + + + + + Default (%1) + + + + + Premultiplied Alpha + + + + + Image Sequence + + + + + Start Index: + + + + + End Index: + + + + + Frame Rate: + + + + + Invalid Configuration + + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + + + + + Interface between a Viewer panel and the node system. + + + + + Texture + + + + + Samples + + + + + Video Tracks + + + + + Audio Tracks + + + + + Subtitle Tracks + + + + + olive::ViewerPanel + + + Viewer + + + + + olive::ViewerWidget + + + Error + + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + Pembesaran + + + + Fit + Pas + + + + %1% + + + + + Full Screen + Layar Penuh + + + + Screen %1: %2x%3 + Layar %1: %2x%3 + + + + Deinterlace + + + + + Scopes + + + + + Cache + + + + + Auto-Cache + + + + + Pause Auto-Cache During Playback + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Off + Matikan + + + + On + + + + + Custom Aspect + + + + + Show Audio Waveform + + + + + olive::VolumeNode + + + + Volume + + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/it_IT.ts b/app/ts/it_IT.ts new file mode 100644 index 000000000..5c1b92b6a --- /dev/null +++ b/app/ts/it_IT.ts @@ -0,0 +1,4767 @@ + + + + + AudioParams + + + %1 Hz + + + + + Mono + Mono + + + + Stereo + Stereo + + + + 2.1 + 144p {2.1?} + + + + 5.1 + 144p {5.1?} + + + + 7.1 + 144p {7.1?} + + + + Unknown (0x%1) + + + + + Config + + + Error loading settings + + + + + Failed to load application settings. This session will use defaults. + +%1 + + + + + Error saving settings + + + + + Failed to save application settings. The application may lack write permissions to this location. + + + + + Footage + + + %1 FPS + + + + + %1 Hz + + + + + Filename: %1 + + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + + + + + Automatically Detect Parameters From Footage + + + + + Set Parameters Manually + + + + + MoveItemCommand + + + Move Item + + + + + NodeCopyPasteWidget + + + Error pasting nodes + + + + + Failed to paste nodes: %1 + + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + + + + + Set preset name: + + + + + Invalid preset name + + + + + You must enter a preset name + + + + + Preset exists + + + + + A preset with this name already exists. Would you like to replace it? + + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + + + + + %1: Unknown + + + + + %1: Image - %2x%3 + + + + + %1: Video - %2x%3 + + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + + + + + Bars + Barre + + + + Solid + + + + + Title + Titolo + + + + Tone + Suono + + + + Unknown + + + + + VideoParams + + + 8-bit + + + + + 16-bit Integer + + + + + Half-Float (16-bit) + + + + + Full-Float (32-bit) + + + + + Unknown (0x%1) + + + + + %1 FPS + + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + + + + + Show application version + + + + + Start in full-screen mode + + + + + Export only (No GUI) + + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + + + + + olive::AboutDialog + + + About %1 + + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive è un editor video non lineare. Questo è software libero ed è protetto dalla licenza GNU GPL. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + Gli sviluppatori di Olive sono grati di informare che il codice sorgente del programma è scaricabile dal sito. + + + + olive::ActionSearch + + + Search for action... + Cerca un'azione... + + + + olive::AudioInput + + + Audio Input + + + + + Audio + Audio + + + + Import an audio footage stream. + + + + + olive::AudioMonitorPanel + + + Audio Monitor + + + + + olive::Block + + + Length + Lunghezza + + + + Media In + + + + + Enabled + + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + + + + + Blurs an image. + + + + + Input + + + + + Method + + + + + Box + + + + + Gaussian + + + + + Radius + + + + + Horizontal + + + + + Vertical + + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + + + + + A time-based node that represents a media source. + + + + + Buffer + + + + + olive::ColorDialog + + + Select Color + + + + + olive::ColorSpaceChooser + + + Color Management + + + + + Input: + + + + + Color Space: + + + + + Display: + + + + + View: + + + + + Look: + + + + + (None) + + + + + olive::ColorValuesTab + + + Red + + + + + Green + + + + + Blue + + + + + olive::ColorValuesWidget + + + Preview + + + + + Input + + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + Nuova cartella + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + Salva progetto + + + + + Error + Errore + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + + + + + Load Project + + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + + + + + Save All + + + + + Don't Save + + + + + Don't Save All + + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + Apri progetto + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + + + + + Send Error Report + + + + + Don't Send + + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CrossDissolveTransition + + + Cross Dissolve + + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + Lineare + + + + Bezier + Bézier + + + + Hold + Costante + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + + + + + Disk Cache Settings + + + + + Maximum Disk Cache: + + + + + %1 GB + + + + + + + Clear Disk Cache + + + + + Automatically clear disk cache on close + + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + + + + + olive::DiskManager + + + + Disk Cache Error + + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + Avanzate + + + + Pixel + + + + + Pixel Format: + Formato pixel: + + + + Performance + + + + + Threads: + Thread: + + + + olive::ExportAudioTab + + + Codec: + Codec: + + + + Sample Rate: + Frequenza di campionamento: + + + + Channel Layout: + + + + + Format: + Formato: + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + + + + + olive::ExportDialog + + + Filename: + Nome file: + + + + Browse for exported file filename + + + + + Preset: + Preimpostazioni: + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + Intervallo: + + + + Entire Sequence + Sequenza completa + + + + In to Out + Zona selezionata + + + + Format: + Formato: + + + + Export Video + + + + + Export Audio + + + + + Video + Video + + + + Audio + Audio + + + + + Export + Esporta + + + + Preview + + + + + Invalid parameters + + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + + + + + olive::ExportTask + + + Exporting "%1" + + + + + Failed to create encoder + + + + + Failed to open file + + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + Larghezza: + + + + Height: + Altezza: + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + + + + + Fit + Adatta + + + + Stretch + + + + + Crop + + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + Proporzioni dei pixel: + + + + Interlacing: + Interlacciamento: + + + + Quality: + + + + + Codec + + + + + Codec: + Codec: + + + + Advanced + Avanzate + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + Proprietà di "%1" + + + + Name: + Nome: + + + + Tracks: + Tracce: + + + + olive::FootageRelinkDialog + + + Footage + + + + + Filename + + + + + Actions + + + + + Browse + Sfoglia + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + Tutti i file + + + + olive::FootageViewerPanel + + + Footage Viewer + + + + + olive::GapBlock + + + Gap + + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + + + + + Maximum Bit Rate (Mbps): + + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + Grandezza file desiderata (MB): + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + + + + + Constant Rate Factor + + + + + Target Bit Rate + + + + + Target File Size + + + + + olive::ImageSection + + + Image Sequence: + + + + + olive::InterlacedComboBox + + + None (Progressive) + Nessuno (progressivo) + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + + + + + In: + + + + + Out: + + + + + Linear + Lineare + + + + Hold + Costante + + + + Bezier + Bézier + + + + olive::KeyframeViewBase + + + Linear + Lineare + + + + Bezier + Bézier + + + + Hold + Costante + + + + P&roperties + + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + + + + + Save '%1' &As + + + + + Close '%1' + + + + + Close All Except '%1' + + + + + &Save Project + &Salva progetto + + + + Save Project &As + S&alva progetto con nome + + + + Close Project + + + + + Close All Except Current Project + + + + + (None) + + + + + &File + &File + + + + &New + &Nuovo + + + + &Open Project + Apri pr&ogetto + + + + Open &Recent + + + + + &Clear Recent List + + + + + Sa&ve All Projects + + + + + &Import... + &Importa... + + + + &Export + + + + + &Media... + + + + + &Project Properties... + + + + + Close All Projects + + + + + E&xit + Es&ci + + + + &Edit + &Modifica + + + + Insert + + + + + Overwrite + + + + + Select &All + Seleziona t&utto + + + + Deselect All + Deseleziona tutto + + + + Ripple to In Point + Taglia a catena fino al punto iniziale + + + + Ripple to Out Point + Taglia a catena dal punto finale + + + + Edit to In Point + Taglia fino al punto iniziale + + + + Edit to Out Point + Taglia dal punto finale + + + + Delete In/Out Point + Elimina tra l'inizio e fine selezione + + + + Ripple Delete In/Out Point + Elimina a catena tra l'inizio e fine selezione + + + + Set/Edit Marker + Imposta/modifica marcatore + + + + &View + &Visualizza + + + + Zoom In + Ingrandisci + + + + Zoom Out + Rimpicciolisci + + + + Increase Track Height + Aumenta l'altezza delle tracce + + + + Decrease Track Height + Diminuisci altezza delle tracce + + + + Toggle Show All + Commuta mostra tutti + + + + Full Screen + Schermo intero + + + + Full Screen Viewer + Visualizzatore a schermo intero + + + + &Playback + &Riproduzione + + + + Go to Start + Vai all'inizio + + + + Previous Frame + Fotogramma precedente + + + + Play/Pause + Riproduci/pausa + + + + Play In to Out + Riproduci tra inizio e fine selezione + + + + Next Frame + Fotogramma successivo + + + + Go to End + Vai alla fine + + + + Go to Previous Cut + Vai al taglio precedente + + + + Go to Next Cut + Vai al taglio successivo + + + + Go to In Point + Vai al punto di inizio selezione + + + + Go to Out Point + Vai al punto di fine selezione + + + + Shuttle Left + Scorri riproducendo verso sinistra + + + + Shuttle Stop + Ferma scorrimento riproduzione + + + + Shuttle Right + Scorri riproducendo verso destra + + + + Loop + Ciclico + + + + &Sequence + &Sequenza + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Maximize Panel + Massimizza pannello + + + + Lock Panels + Blocca pannelli + + + + Reset to Default Layout + Torna alla disposizione predefinita + + + + &Tools + S&trumenti + + + + Pointer Tool + Strumento puntatore + + + + Edit Tool + Strumento di modifica + + + + Ripple Tool + Strumento ridimensiona a catena + + + + Rolling Tool + + + + + Razor Tool + Strumento di taglio + + + + Slip Tool + Strumento di scivolamento + + + + Slide Tool + Strumento di scorrimento + + + + Hand Tool + Strumento mano + + + + Zoom Tool + + + + + Transition Tool + Strumento transizione + + + + Enable Snapping + Attiva bordi magnetici + + + + Preferences + Impostazioni + + + + &Help + &Aiuto + + + + A&ction Search + Ri&cerca azione + + + + Send &Feedback... + + + + + &About... + Inform&azioni... + + + + olive::MainStatusBar + + + Welcome to %1 %2 + Benvenuti in %1 %2 + + + + Running %1 background tasks + + + + + olive::MainWindow + + + Driver Warning + + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + + + + + No color manager connected + + + + + Display + + + + + View + Visualizza + + + + Look + + + + + (None) + + + + + OpenColorIO Error + + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + Aggiungi + + + + Subtract + + + + + Multiply + Moltiplica + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + Posizione + + + + Rotation + Rotazione + + + + Scale + + + + + Uniform Scale + Mantieni proporzioni + + + + Anchor Point + Punto di ancoraggio + + + + olive::MediaInput + + + Footage + + + + + olive::MenuShared + + + &Project + &Progetto + + + + &Sequence + &Sequenza + + + + &Folder + C&artella + + + + Cu&t + &Taglia + + + + Cop&y + &Copia + + + + &Paste + &Incolla + + + + Paste Insert + Incolla e inserisci + + + + Duplicate + Duplica + + + + Delete + Elimina + + + + Ripple Delete + Elimina a catena + + + + Split + Dividi + + + + Set In Point + Imposta punto di inizio selezione + + + + Set Out Point + Imposta punto di fine selezione + + + + Reset In Point + Azzera punto inizio selezione + + + + Reset Out Point + Azzera punto fine selezione + + + + Clear In/Out Point + Pulisci punti di inizio/fine selezione + + + + Add Default Transition + Aggiungi transizione predefinita + + + + Link/Unlink + Collega/scollega + + + + Enable/Disable + Attiva/disattiva + + + + Nest + Annida + + + + Frames + Fotogrammi + + + + Drop Frame + Salta fotogrammi + + + + Non-Drop Frame + Non saltare fotogrammi + + + + Milliseconds + Millisecondi + + + + Seconds + + + + + olive::MergeNode + + + Merge + + + + + Merge two textures together. + + + + + Base + + + + + Blend + + + + + olive::Node + + + Input + + + + + Output + + + + + General + Generale + + + + Math + + + + + Color + Colore + + + + Filter + + + + + Timeline + Linea temporale + + + + Generator + + + + + Channel + + + + + Transition + + + + + Uncategorized + + + + + olive::NodeInput + + + Input + + + + + olive::NodeOutput + + + Output + + + + + olive::NodePanel + + + Node Editor + + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + Colore + + + + Matrix + + + + + Text + Testo + + + + Font + Carattere + + + + File + + + + + Texture + + + + + Samples + + + + + Footage + + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + + + + + Nothing + + + + + Disconnect + + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + + + + + olive::NodeTableView + + + Type + Tipo + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + (sconosciuto) + + + + olive::NodeTreeView + + + Nodes + + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + + + + + Filter + + + + + Show All + + + + + Show Selected Blocks Only + + + + + Direction + + + + + Top to Bottom + + + + + Bottom to Top + + + + + Left to Right + + + + + Right to Left + + + + + Add + Aggiungi + + + + olive::PanNode + + + + Pan + Trasla + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + + + + + (none) + (nessuno) + + + + (multiple) + (multiple) + + + + olive::PathWidget + + + Browse + Sfoglia + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + Colore + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + Colore + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + Tema + + + + Node Color Scheme + + + + + olive::PreferencesAudioTab + + + Output Device: + Dispositivo d'uscita: + + + + Input Device: + Dispositivo d'ingresso: + + + + Sample Rate: + Frequenza di campionamento: + + + + Audio Recording: + Registrazione audio: + + + + Mono + Mono + + + + Stereo + Stereo + + + + Refresh Devices + + + + + Please wait... + + + + + Default + Predefinito + + + + olive::PreferencesBehaviorTab + + + Behavior + Comportamento + + + + General + Generale + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + Audio + + + + Enable audio scrubbing + + + + + Timeline + Linea temporale + + + + Auto-Seek to Imported Clips + Sposta il cursore alle clip importate + + + + Edit Tool Also Seeks + Lo strumento di modifica sposta anche il cursore + + + + Edit Tool Selects Links + Lo strumento di modifica seleziona anche i collegamenti + + + + Enable Drag Files to Timeline + Permetti il trascinamento dei file alla linea temporale + + + + Invert Timeline Scroll Axes + Inverti assi di scorrimento della linea temporale + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + Spostare il cursore seleziona anche + + + + Seek to the End of Pastes + Sposta cursore alla fine di ciò che viene incollato + + + + Selecting Also Seeks + Selezionando si sposta anche il cursore + + + + Playback + Riproduzione + + + + Ask For Name When Setting Marker + Chiedi un nome nell'impostazione del marcatore + + + + Automatically rewind at the end of a sequence + + + + + Project + Progetto + + + + Drop Files on Media to Replace + Rilascia i file sui media per rimpiazzarli + + + + Nodes + + + + + Add Default Effects to New Clips + Aggiungi gli effetti predefiniti alle nuove clip + + + + Auto-Scale By Default + Scala automaticamente in maniera predefinita + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + Impostazioni + + + + General + Generale + + + + Appearance + Aspetto + + + + Behavior + Comportamento + + + + Disk + + + + + Audio + Audio + + + + Keyboard + Tastiera + + + + olive::PreferencesDiskTab + + + Disk Management + + + + + Disk Cache Location: + + + + + Disk Cache Settings + + + + + Cache Behavior + + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + Lingua: + + + + Auto-Scroll Method: + + + + + None + + + + + Page Scrolling + + + + + Smooth Scrolling + + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + Cerca un'azione o una scorciatoia + + + + Action + Azione + + + + Shortcut + Scorciatoia + + + + Import + Importa + + + + Export + Esporta + + + + Reset Selected + Reimposta quelle selezionate + + + + Reset All + Reimposta tutto + + + + Confirm Reset All Shortcuts + Conferma l'azzeramento di tutte le scorciatoie da tastiera + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + Sei sicuro di voler riportare tutte le scorciatoie da tastiera ai valori iniziali? + + + + Import Keyboard Shortcuts + Importa scorciatoie da tastiera + + + + + Error saving shortcuts + Errore nel salvataggio delle scorciatoie + + + + Failed to open file for reading + Errore nell'apertura del file in lettura + + + + Export Keyboard Shortcuts + Esporta scorciatoie da tastiera + + + + Export Shortcuts + Esporta scorciatoie + + + + Shortcuts exported successfully + Scorciatoie esportate con successo + + + + Failed to open file for writing + Errore nell'apertura del file in scrittura + + + + olive::ProgressDialog + + + Cancel + Annulla + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + &Nuovo + + + + &Import... + &Importa... + + + + &Project Properties... + + + + + Open in New Tab + + + + + Open in New Window + + + + + Reveal in Explorer + Mostra in Esplora risorse + + + + Reveal in Finder + Mostra in Finder + + + + Reveal in File Manager + Mostra nel gestore file + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + + + + + Project + Progetto + + + + (none) + (nessuno) + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + + + + + OpenColorIO Configuration: + + + + + (default) + + + + + Default Input Color Space: + + + + + Browse + Sfoglia + + + + Color Management + + + + + Use Default Location + + + + + Store Alongside Project + + + + + Use Custom Location: + + + + + Disk Cache Settings + + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + + + + + OpenColorIO Config Error + + + + + Failed to set OpenColorIO configuration: %1 + + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + + + + + olive::ProjectSaveTask + + + Saving '%1' + + + + + Failed to write XML data + + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + + + + + Open Project + Apri progetto + + + + Save Project + Salva progetto + + + + Undo + Annulla + + + + Redo + Rifai + + + + Search media, markers, etc. + Cerca media, marcatori, ecc. + + + + Switch to Tree View + + + + + Switch to List View + + + + + Switch to Icon View + + + + + olive::ProjectViewModel + + + Name + Nome + + + + Duration + Durata + + + + Rate + Frequenza + + + + Move Items + + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + + + + + Bold + Grassetto + + + + I + + + + + Italic + + + + + U + + + + + Underline + + + + + S + + + + + Strikethrough + + + + + Font Family + + + + + Font Size + + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + + + + + Histogram + + + + + Scope + + + + + olive::SequenceDialog + + + Name: + Nome: + + + + New Sequence + Nuova sequenza + + + + Editing "%1" + Modifica di "%1" + + + + Error editing Sequence + + + + + Please enter a name for this Sequence. + + + + + olive::SequenceDialogParameterTab + + + Video + Video + + + + Width: + Larghezza: + + + + Height: + Altezza: + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + Proporzioni dei pixel: + + + + Interlacing: + Interlacciamento: + + + + Audio + Audio + + + + Sample Rate: + Frequenza di campionamento: + + + + Channels: + + + + + Preview + + + + + Resolution: + + + + + Quality: + + + + + Save Preset + + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + + + + + My Presets + + + + + 4K UHD + + + + + 1080p + 1080p + + + + 720p + 720p + + + + NTSC + + + + + PAL + + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + + + + + olive::SequenceViewerPanel + + + Sequence Viewer + Visualizzatore sequenza + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + + + + + Generate a solid color. + + + + + Color + Colore + + + + olive::StringSlider + + + (none) + (nessuno) + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + + + + + Color + Colore + + + + Radius + + + + + Opacity + Opacità + + + + Inner + + + + + olive::Task + + + Task + + + + + Unknown error + + + + + olive::TaskDialog + + + Task Failed + + + + + olive::TaskManagerPanel + + + Task Manager + + + + + olive::TaskViewItem + + + Error: %1 + + + + + olive::TextGenerator + + + Sample Text + Testo di esempio + + + + + Text + Testo + + + + Generate rich text. + + + + + Font + Carattere + + + + Font Size + + + + + Color + Colore + + + + Vertical Align + + + + + Top + In alto + + + + Center + Al centro + + + + Bottom + In basso + + + + olive::TimeBasedPanel + + + (none) + (nessuno) + + + + olive::TimeBasedWidget + + + Set Marker + Imposta marcatore + + + + Marker name: + + + + + olive::TimeInput + + + Time + + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + Linea temporale + + + + olive::TimelineWidget + + + + Properties + Proprietà + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + + + + + olive::Toolbar + + + Pointer Tool + Strumento puntatore + + + + Edit Tool + Strumento di modifica + + + + Ripple Tool + Strumento ridimensiona a catena + + + + Rolling Tool + + + + + Razor Tool + Strumento di taglio + + + + Slip Tool + Strumento di scivolamento + + + + Slide Tool + Strumento di scorrimento + + + + Hand Tool + Strumento mano + + + + Zoom Tool + + + + + Transition Tool + Strumento transizione + + + + Record Tool + + + + + Add Tool + + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + + + + + Audio %1 + + + + + Subtitle %1 + + + + + Track %1 + + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + + + + + Linear + Lineare + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + + + + + Perform a trigonometry operation on a value. + + + + + Sine + Seno + + + + Cosine + + + + + Tangent + + + + + Inverse Sine + + + + + Inverse Cosine + + + + + Inverse Tangent + + + + + Hyperbolic Sine + + + + + Hyperbolic Cosine + + + + + Hyperbolic Tangent + + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + 144p {1/%1?} + + + + olive::VideoInput + + + Video Input + + + + + Video + Video + + + + Import a video footage stream. + + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + Interlacciamento: + + + + Color Space: + + + + + Default (%1) + + + + + Premultiplied Alpha + + + + + Image Sequence + + + + + Start Index: + + + + + End Index: + + + + + Frame Rate: + + + + + Invalid Configuration + + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + + + + + Interface between a Viewer panel and the node system. + + + + + Texture + + + + + Samples + + + + + Video Tracks + + + + + Audio Tracks + + + + + Subtitle Tracks + + + + + olive::ViewerPanel + + + Viewer + + + + + olive::ViewerWidget + + + Error + Errore + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + Ingrandimento + + + + Fit + Adatta + + + + %1% + + + + + Full Screen + Schermo intero + + + + Screen %1: %2x%3 + Schermo %1: %2x%3 + + + + Deinterlace + + + + + Scopes + + + + + Cache + + + + + Auto-Cache + + + + + Pause Auto-Cache During Playback + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Off + Disattivato + + + + On + + + + + Custom Aspect + + + + + Show Audio Waveform + + + + + olive::VolumeNode + + + + Volume + Volume + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/pt_BR.ts b/app/ts/pt_BR.ts new file mode 100644 index 000000000..9c3ab35cd --- /dev/null +++ b/app/ts/pt_BR.ts @@ -0,0 +1,4767 @@ + + + + + AudioParams + + + %1 Hz + + + + + Mono + Mono + + + + Stereo + Estéreo + + + + 2.1 + 144p {2.1?} + + + + 5.1 + 144p {5.1?} + + + + 7.1 + 144p {7.1?} + + + + Unknown (0x%1) + + + + + Config + + + Error loading settings + + + + + Failed to load application settings. This session will use defaults. + +%1 + + + + + Error saving settings + + + + + Failed to save application settings. The application may lack write permissions to this location. + + + + + Footage + + + %1 FPS + + + + + %1 Hz + + + + + Filename: %1 + + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + + + + + Automatically Detect Parameters From Footage + + + + + Set Parameters Manually + + + + + MoveItemCommand + + + Move Item + + + + + NodeCopyPasteWidget + + + Error pasting nodes + + + + + Failed to paste nodes: %1 + + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + + + + + Set preset name: + + + + + Invalid preset name + + + + + You must enter a preset name + + + + + Preset exists + + + + + A preset with this name already exists. Would you like to replace it? + + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + + + + + %1: Unknown + + + + + %1: Image - %2x%3 + + + + + %1: Video - %2x%3 + + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + + + + + Bars + Barras + + + + Solid + Sólido + + + + Title + Título + + + + Tone + Tom + + + + Unknown + + + + + VideoParams + + + 8-bit + Inteiro de 8 bits + + + + 16-bit Integer + Inteiro de 16 bits + + + + Half-Float (16-bit) + Ponto flutuante de 16 bits + + + + Full-Float (32-bit) + Ponto flutuante de 32 bits + + + + Unknown (0x%1) + + + + + %1 FPS + + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + + + + + Show application version + + + + + Start in full-screen mode + + + + + Export only (No GUI) + + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + + + + + olive::AboutDialog + + + About %1 + + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive é um editor de vídeos não-linear. Este software é livre e protegido pela licença GNU GPL. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + A equipe do Olive informa que o código-fonte está disponível no site do projeto. + + + + olive::ActionSearch + + + Search for action... + Pesquisar ação... + + + + olive::AudioInput + + + Audio Input + + + + + Audio + Áudio + + + + Import an audio footage stream. + + + + + olive::AudioMonitorPanel + + + Audio Monitor + + + + + olive::Block + + + Length + Duração + + + + Media In + + + + + Enabled + + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + + + + + Blurs an image. + + + + + Input + + + + + Method + + + + + Box + + + + + Gaussian + + + + + Radius + + + + + Horizontal + + + + + Vertical + + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + + + + + A time-based node that represents a media source. + + + + + Buffer + + + + + olive::ColorDialog + + + Select Color + + + + + olive::ColorSpaceChooser + + + Color Management + Gerenciamento de cores + + + + Input: + + + + + Color Space: + Espaço de cor: + + + + Display: + Exibição: + + + + View: + Visualizar: + + + + Look: + Aparência: + + + + (None) + (nenhum) + + + + olive::ColorValuesTab + + + Red + + + + + Green + + + + + Blue + + + + + olive::ColorValuesWidget + + + Preview + + + + + Input + + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + Nova pasta + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + Salvar projeto + + + + + Error + Erro + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + + + + + Load Project + + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + Sequência %1 + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + + + + + Save All + + + + + Don't Save + + + + + Don't Save All + + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + Abrir projeto + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + + + + + Send Error Report + + + + + Don't Send + + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CrossDissolveTransition + + + Cross Dissolve + Dissolver cruzado + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + Linear + + + + Bezier + Bézier + + + + Hold + Constante + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + + + + + Disk Cache Settings + + + + + Maximum Disk Cache: + + + + + %1 GB + + + + + + + Clear Disk Cache + + + + + Automatically clear disk cache on close + + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + + + + + olive::DiskManager + + + + Disk Cache Error + + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + Avançado + + + + Pixel + + + + + Pixel Format: + Formato de pixel: + + + + Performance + + + + + Threads: + Threads: + + + + olive::ExportAudioTab + + + Codec: + Codec: + + + + Sample Rate: + Taxa de amostragem: + + + + Channel Layout: + + + + + Format: + Formato: + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + + + + + olive::ExportDialog + + + Filename: + Nome do arquivo: + + + + Browse for exported file filename + + + + + Preset: + Predefinição: + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + Intervalo: + + + + Entire Sequence + Sequência inteira + + + + In to Out + Faixa de entrada/saída + + + + Format: + Formato: + + + + Export Video + + + + + Export Audio + + + + + Video + Vídeo + + + + Audio + Áudio + + + + + Export + Exportar + + + + Preview + + + + + Invalid parameters + + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + + + + + olive::ExportTask + + + Exporting "%1" + + + + + Failed to create encoder + + + + + Failed to open file + + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + Largura: + + + + Height: + Altura: + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + + + + + Fit + Ajustar + + + + Stretch + + + + + Crop + + + + + Frame Rate: + Taxa de quadros: + + + + Pixel Aspect Ratio: + Taxa de proporção do pixel: + + + + Interlacing: + Entrelaçamento: + + + + Quality: + + + + + Codec + + + + + Codec: + Codec: + + + + Advanced + Avançado + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + Propriedades "%1" + + + + Name: + Nome: + + + + Tracks: + Faixas: + + + + olive::FootageRelinkDialog + + + Footage + + + + + Filename + + + + + Actions + + + + + Browse + Procurar + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + Todos os arquivos + + + + olive::FootageViewerPanel + + + Footage Viewer + + + + + olive::GapBlock + + + Gap + + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + + + + + Maximum Bit Rate (Mbps): + + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + Tamanho do arquivo alvo (MB): + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + + + + + Constant Rate Factor + + + + + Target Bit Rate + + + + + Target File Size + + + + + olive::ImageSection + + + Image Sequence: + + + + + olive::InterlacedComboBox + + + None (Progressive) + Nenhum (Progressivo) + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + + + + + In: + + + + + Out: + + + + + Linear + Linear + + + + Hold + Constante + + + + Bezier + Bézier + + + + olive::KeyframeViewBase + + + Linear + Linear + + + + Bezier + Bézier + + + + Hold + Constante + + + + P&roperties + + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + + + + + Save '%1' &As + + + + + Close '%1' + + + + + Close All Except '%1' + + + + + &Save Project + &Salvar projeto + + + + Save Project &As + Salvar projeto &como + + + + Close Project + + + + + Close All Except Current Project + + + + + (None) + (nenhum) + + + + &File + &Arquivo + + + + &New + &Novo + + + + &Open Project + &Abrir projeto + + + + Open &Recent + + + + + &Clear Recent List + + + + + Sa&ve All Projects + + + + + &Import... + &Importar... + + + + &Export + + + + + &Media... + + + + + &Project Properties... + + + + + Close All Projects + + + + + E&xit + Sai&r + + + + &Edit + &Editar + + + + Insert + + + + + Overwrite + + + + + Select &All + Selecionar &tudo + + + + Deselect All + Desmarcar + + + + Ripple to In Point + Ajustar em cadeia à esquerda + + + + Ripple to Out Point + Ajustar em cadeia à direita + + + + Edit to In Point + Modificar à esquerda + + + + Edit to Out Point + Modificar à direita + + + + Delete In/Out Point + Excluir faixa de entrada/saída + + + + Ripple Delete In/Out Point + Excluir faixa de entrada/saída em cadeia + + + + Set/Edit Marker + Definir/editar marcador + + + + &View + E&xibir + + + + Zoom In + Aumentar zoom + + + + Zoom Out + Diminuir zoom + + + + Increase Track Height + Aumentar altura da faixa + + + + Decrease Track Height + Diminuir altura da faixa + + + + Toggle Show All + Mostrar toda a sequência + + + + Full Screen + Tela cheia + + + + Full Screen Viewer + Visualizador de tela cheia + + + + &Playback + &Reprodução + + + + Go to Start + Ir ao início + + + + Previous Frame + Quadro anterior + + + + Play/Pause + Reproduzir/pausar + + + + Play In to Out + Reproduzir na faixa de entrada/saída + + + + Next Frame + Próximo quadro + + + + Go to End + Ir ao final + + + + Go to Previous Cut + Ir ao corte anterior + + + + Go to Next Cut + Ir ao próximo corte + + + + Go to In Point + Ir ao ponto de entrada + + + + Go to Out Point + Ir ao ponto de saída + + + + Shuttle Left + Avançar reprodução pela esquerda + + + + Shuttle Stop + Parar reprodução + + + + Shuttle Right + Avançar reprodução pela direita + + + + Loop + Repetir + + + + &Sequence + &Sequência + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Maximize Panel + Maximizar painel + + + + Lock Panels + Travar painéis + + + + Reset to Default Layout + Restaurar leiaute padrão + + + + &Tools + &Ferramentas + + + + Pointer Tool + Ferramenta Ponteiro + + + + Edit Tool + Ferramenta Modificar + + + + Ripple Tool + Ferramenta Ajustar em cadeia + + + + Rolling Tool + + + + + Razor Tool + Ferramenta Fatiar + + + + Slip Tool + Ferramenta Escorregar + + + + Slide Tool + Ferramenta Deslizar + + + + Hand Tool + Ferramenta Mão + + + + Zoom Tool + + + + + Transition Tool + Ferramenta Transição + + + + Enable Snapping + Ativar encaixe + + + + Preferences + Preferências + + + + &Help + Aj&uda + + + + A&ction Search + &Pesquisar ação + + + + Send &Feedback... + + + + + &About... + &Sobre... + + + + olive::MainStatusBar + + + Welcome to %1 %2 + Bem-vindo ao %1 %2 + + + + Running %1 background tasks + + + + + olive::MainWindow + + + Driver Warning + + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + + + + + No color manager connected + + + + + Display + + + + + View + Exibir + + + + Look + + + + + (None) + (nenhum) + + + + OpenColorIO Error + + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + Adicionar + + + + Subtract + + + + + Multiply + + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + Posição + + + + Rotation + Rotação + + + + Scale + Escala + + + + Uniform Scale + Escala uniforme + + + + Anchor Point + Ponto de ancoragem + + + + olive::MediaInput + + + Footage + + + + + olive::MenuShared + + + &Project + &Projeto + + + + &Sequence + &Sequência + + + + &Folder + P&asta + + + + Cu&t + + + + + Cop&y + &Copiar + + + + &Paste + C&olar + + + + Paste Insert + Colar e inserir + + + + Duplicate + Duplicar + + + + Delete + Excluir + + + + Ripple Delete + Excluir em cadeia + + + + Split + Dividir + + + + Set In Point + Definir ponto de entrada + + + + Set Out Point + Definir ponto de saída + + + + Reset In Point + Redefinir ponto de entrada + + + + Reset Out Point + Redefinir ponto de saída + + + + Clear In/Out Point + Limpar pontos de entrada/saída + + + + Add Default Transition + Adicionar transição padrão + + + + Link/Unlink + Vincular/desvincular + + + + Enable/Disable + Ativar/desativar + + + + Nest + Aninhar + + + + Frames + Quadros + + + + Drop Frame + Código de tempo (com descarte de quadro) + + + + Non-Drop Frame + Código de tempo (sem descarte de quadro) + + + + Milliseconds + Milissegundos + + + + Seconds + + + + + olive::MergeNode + + + Merge + + + + + Merge two textures together. + + + + + Base + + + + + Blend + + + + + olive::Node + + + Input + + + + + Output + + + + + General + Geral + + + + Math + + + + + Color + Cor + + + + Filter + + + + + Timeline + Linha do tempo + + + + Generator + + + + + Channel + + + + + Transition + + + + + Uncategorized + + + + + olive::NodeInput + + + Input + + + + + olive::NodeOutput + + + Output + + + + + olive::NodePanel + + + Node Editor + Editor de nós + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + Cor + + + + Matrix + Matriz + + + + Text + Texto + + + + Font + Fonte + + + + File + + + + + Texture + Textura + + + + Samples + + + + + Footage + + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + + + + + Nothing + + + + + Disconnect + + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + + + + + olive::NodeTableView + + + Type + Tipo + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + (desconhecido) + + + + olive::NodeTreeView + + + Nodes + + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + + + + + Filter + + + + + Show All + + + + + Show Selected Blocks Only + + + + + Direction + + + + + Top to Bottom + + + + + Bottom to Top + + + + + Left to Right + + + + + Right to Left + + + + + Add + Adicionar + + + + olive::PanNode + + + + Pan + Balanço + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + + + + + (none) + (nenhum) + + + + (multiple) + (vários) + + + + olive::PathWidget + + + Browse + Procurar + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + Cor + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + Cor + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + Tema + + + + Node Color Scheme + + + + + olive::PreferencesAudioTab + + + Output Device: + Dispositivo de saída: + + + + Input Device: + Dispositivos de entrada: + + + + Sample Rate: + Taxa de amostragem: + + + + Audio Recording: + Gravação de áudio: + + + + Mono + Mono + + + + Stereo + Estéreo + + + + Refresh Devices + + + + + Please wait... + + + + + Default + Padrão + + + + olive::PreferencesBehaviorTab + + + Behavior + Comportamento + + + + General + Geral + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + Áudio + + + + Enable audio scrubbing + + + + + Timeline + Linha do tempo + + + + Auto-Seek to Imported Clips + Mover o cursor ao inserir um clipe na linha do tempo + + + + Edit Tool Also Seeks + Ferramenta Modificar também move o cursor + + + + Edit Tool Selects Links + Ferramenta Modificar seleciona vínculos + + + + Enable Drag Files to Timeline + Arrastar arquivos diretamente à linha do tempo + + + + Invert Timeline Scroll Axes + Inverter eixos de rolagem na linha do tempo + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + Mover o cursor também seleciona + + + + Seek to the End of Pastes + Mover o cursor para o final do trecho colado + + + + Selecting Also Seeks + Selecionar também move o cursor + + + + Playback + Reprodução + + + + Ask For Name When Setting Marker + Perguntar pelo nome quando definir o marcador + + + + Automatically rewind at the end of a sequence + + + + + Project + Projeto + + + + Drop Files on Media to Replace + Arrastar arquivo sobre a mídia para substituí-la + + + + Nodes + + + + + Add Default Effects to New Clips + Adicionar efeitos padrão para novos clipes + + + + Auto-Scale By Default + Redimensionar automaticamente por padrão + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + Preferências + + + + General + Geral + + + + Appearance + Aparência + + + + Behavior + Comportamento + + + + Disk + + + + + Audio + Áudio + + + + Keyboard + Teclado + + + + olive::PreferencesDiskTab + + + Disk Management + + + + + Disk Cache Location: + + + + + Disk Cache Settings + + + + + Cache Behavior + + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + Idioma: + + + + Auto-Scroll Method: + + + + + None + + + + + Page Scrolling + + + + + Smooth Scrolling + + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + Pesquisar ação ou atalho + + + + Action + Ação + + + + Shortcut + Atalho + + + + Import + Importar + + + + Export + Exportar + + + + Reset Selected + Redefinir selecionado + + + + Reset All + Redefinir tudo + + + + Confirm Reset All Shortcuts + Confirmar a redefinição de todos os atalhos + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + Você deseja redefinir os atalhos de teclado para seus padrões? + + + + Import Keyboard Shortcuts + Importar atalhos de teclado + + + + + Error saving shortcuts + Erro ao salvar atalhos + + + + Failed to open file for reading + Falha ao abrir arquivo para leitura + + + + Export Keyboard Shortcuts + Exportar atalhos de teclado + + + + Export Shortcuts + Exportar atalhos + + + + Shortcuts exported successfully + Atalhos exportados com sucesso + + + + Failed to open file for writing + Falha ao abrir arquivo para escrita + + + + olive::ProgressDialog + + + Cancel + Cancelar + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + &Novo + + + + &Import... + &Importar... + + + + &Project Properties... + + + + + Open in New Tab + + + + + Open in New Window + + + + + Reveal in Explorer + Mostrar no Explorador de Arquivos + + + + Reveal in Finder + Mostrar no Finder + + + + Reveal in File Manager + Mostrar no gerenciador de arquivos + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + + + + + Project + Projeto + + + + (none) + (nenhum) + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + + + + + OpenColorIO Configuration: + + + + + (default) + + + + + Default Input Color Space: + Espaço de cor de entrada padrão: + + + + Browse + Procurar + + + + Color Management + Gerenciamento de cores + + + + Use Default Location + + + + + Store Alongside Project + + + + + Use Custom Location: + + + + + Disk Cache Settings + + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + + + + + OpenColorIO Config Error + Erro na configuração do OpenColorIO + + + + Failed to set OpenColorIO configuration: %1 + + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + Localizar arquivo de configuração do OpenColorIO + + + + olive::ProjectSaveTask + + + Saving '%1' + + + + + Failed to write XML data + + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + + + + + Open Project + Abrir projeto + + + + Save Project + Salvar projeto + + + + Undo + Desfazer + + + + Redo + Refazer + + + + Search media, markers, etc. + Pesquisar mídia, marcadores, etc. + + + + Switch to Tree View + + + + + Switch to List View + + + + + Switch to Icon View + + + + + olive::ProjectViewModel + + + Name + Nome + + + + Duration + Duração + + + + Rate + Taxa + + + + Move Items + + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + + + + + Bold + Negrito + + + + I + + + + + Italic + + + + + U + + + + + Underline + + + + + S + + + + + Strikethrough + + + + + Font Family + + + + + Font Size + + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + + + + + Histogram + + + + + Scope + + + + + olive::SequenceDialog + + + Name: + Nome: + + + + New Sequence + Nova sequência + + + + Editing "%1" + Editando "%1" + + + + Error editing Sequence + + + + + Please enter a name for this Sequence. + + + + + olive::SequenceDialogParameterTab + + + Video + Vídeo + + + + Width: + Largura: + + + + Height: + Altura: + + + + Frame Rate: + Taxa de quadros: + + + + Pixel Aspect Ratio: + Taxa de proporção do pixel: + + + + Interlacing: + Entrelaçamento: + + + + Audio + Áudio + + + + Sample Rate: + Taxa de amostragem: + + + + Channels: + + + + + Preview + + + + + Resolution: + + + + + Quality: + + + + + Save Preset + + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + + + + + My Presets + + + + + 4K UHD + + + + + 1080p + 1080p + + + + 720p + 720p + + + + NTSC + + + + + PAL + + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + + + + + olive::SequenceViewerPanel + + + Sequence Viewer + Visualizador de sequência + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + Sólido + + + + Generate a solid color. + + + + + Color + Cor + + + + olive::StringSlider + + + (none) + (nenhum) + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + + + + + Color + Cor + + + + Radius + + + + + Opacity + Opacidade + + + + Inner + + + + + olive::Task + + + Task + + + + + Unknown error + + + + + olive::TaskDialog + + + Task Failed + + + + + olive::TaskManagerPanel + + + Task Manager + + + + + olive::TaskViewItem + + + Error: %1 + + + + + olive::TextGenerator + + + Sample Text + Texto de exemplo + + + + + Text + Texto + + + + Generate rich text. + + + + + Font + Fonte + + + + Font Size + + + + + Color + Cor + + + + Vertical Align + + + + + Top + Em cima + + + + Center + Centro + + + + Bottom + Embaixo + + + + olive::TimeBasedPanel + + + (none) + (nenhum) + + + + olive::TimeBasedWidget + + + Set Marker + Definir marcador + + + + Marker name: + + + + + olive::TimeInput + + + Time + + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + Linha do tempo + + + + olive::TimelineWidget + + + + Properties + Propriedades + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + + + + + olive::Toolbar + + + Pointer Tool + Ferramenta Ponteiro + + + + Edit Tool + Ferramenta Modificar + + + + Ripple Tool + Ferramenta Ajustar em cadeia + + + + Rolling Tool + + + + + Razor Tool + Ferramenta Fatiar + + + + Slip Tool + Ferramenta Escorregar + + + + Slide Tool + Ferramenta Deslizar + + + + Hand Tool + Ferramenta Mão + + + + Zoom Tool + + + + + Transition Tool + Ferramenta Transição + + + + Record Tool + + + + + Add Tool + + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + Vídeo %1 + + + + Audio %1 + Áudio %1 + + + + Subtitle %1 + Legenda %1 + + + + Track %1 + + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + + + + + Linear + Linear + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + + + + + Perform a trigonometry operation on a value. + + + + + Sine + Senoidal + + + + Cosine + + + + + Tangent + + + + + Inverse Sine + + + + + Inverse Cosine + + + + + Inverse Tangent + + + + + Hyperbolic Sine + + + + + Hyperbolic Cosine + + + + + Hyperbolic Tangent + + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + 144p {1/%1?} + + + + olive::VideoInput + + + Video Input + + + + + Video + Vídeo + + + + Import a video footage stream. + + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + Entrelaçamento: + + + + Color Space: + Espaço de cor: + + + + Default (%1) + + + + + Premultiplied Alpha + + + + + Image Sequence + + + + + Start Index: + + + + + End Index: + + + + + Frame Rate: + Taxa de quadros: + + + + Invalid Configuration + + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + + + + + Interface between a Viewer panel and the node system. + + + + + Texture + Textura + + + + Samples + + + + + Video Tracks + + + + + Audio Tracks + + + + + Subtitle Tracks + + + + + olive::ViewerPanel + + + Viewer + + + + + olive::ViewerWidget + + + Error + Erro + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + Zoom + + + + Fit + Ajustar + + + + %1% + + + + + Full Screen + Tela cheia + + + + Screen %1: %2x%3 + Tela %1: %2x%3 + + + + Deinterlace + + + + + Scopes + + + + + Cache + + + + + Auto-Cache + + + + + Pause Auto-Cache During Playback + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Off + + + + + On + + + + + Custom Aspect + + + + + Show Audio Waveform + + + + + olive::VolumeNode + + + + Volume + Volume + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/ru_RU.ts b/app/ts/ru_RU.ts new file mode 100644 index 000000000..c57675928 --- /dev/null +++ b/app/ts/ru_RU.ts @@ -0,0 +1,4881 @@ + + + + + AudioParams + + + %1 Hz + %1 Гц + + + + Mono + Моно + + + + Stereo + Стерео + + + + 2.1 + 2.1 + + + + 5.1 + 5.1 + + + + 7.1 + 7.1 + + + + Unknown (0x%1) + Неизвестно (0x%1) + + + + Config + + + Error loading settings + Ошибка при загрузке настроек + + + + Failed to load application settings. This session will use defaults. + +%1 + + + + + Error saving settings + Ошибка при сохранении настроек + + + + Failed to save application settings. The application may lack write permissions for this location. + + + + + Footage + + + %1 FPS + %1 к/с + + + + %1 Hz + %1 Гц + + + + Filename: %1 + Имя файла: %1 + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + Больше не спрашивать + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + Нет открытых последовательностей. Создать новую? + + + + Automatically Detect Parameters From Footage + Автоматически определить + + + + Set Parameters Manually + Указать вручную + + + + MoveItemCommand + + + Move Item + Переместить объект + + + + NodeCopyPasteWidget + + + Error pasting nodes + Ошибка при вставке нод + + + + Failed to paste nodes: %1 + Не удалось вставить ноды: %1 + + + + NodeFactory + + + None + Нет + + + + NodeViewItem + + + %1... + %1... + + + + PresetManager + + + Save Preset + Сохранить профиль + + + + Set preset name: + Название профиля: + + + + Invalid preset name + Некорректное название профиля + + + + You must enter a preset name + Введите название профиля + + + + Preset exists + Профиль с таким названием уже существует + + + + A preset with this name already exists. Would you like to replace it? + Уже есть профиль с таким названием. Заменить его? + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + %1 к/с + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + %1: Звук - %2 каналов, %3 Гц + + + + %1: Unknown + %1: неизвестно + + + + %1: Image - %2x%3 + %1: Изображение - %2x%3 + + + + %1: Video - %2x%3 + %1: Видео - %2x%3 + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + Пустота + + + + Bars + Испытательная таблица + + + + Solid + Заливка + + + + Title + Титры + + + + Tone + Звуковой сигнал + + + + Unknown + Неизвестно + + + + VideoParams + + + 8-bit + + + + + 16-bit Integer + + + + + Half-Float (16-bit) + + + + + Full-Float (32-bit) + + + + + Unknown (0x%1) + Неизвестно (0x%1) + + + + %1 FPS + %1 к/с + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + Показать этот справочный текст + + + + Show application version + Показать версию приложения + + + + Start in full-screen mode + Запуститься в полноэкранном режиме + + + + Export only (No GUI) + Только эксперт (без графического интерфейса) + + + + Override language with file + Запустить с локализацией из заданного файла + + + + qm-file + файл qm + + + + Project to open on startup + Какой проект открыть при запуске + + + + olive::AboutDialog + + + About %1 + О программе %1 + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive — нелинейный видеоредактор. Эта программа является свободной и защищена GNU GPL. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + Исходный код Olive доступен для скачивания на сайте программы. + + + + olive::ActionSearch + + + Search for action... + Найти действие… + + + + olive::AudioMonitorPanel + + + Audio Monitor + Монитор звука + + + + olive::Block + + + Length + Длительность + + + + Media In + + + + + Enabled + Включено + + + + Speed + Скорость + + + + olive::BlurFilterNode + + + Blur + Размытие + + + + Blurs an image. + Размывает изображение. + + + + Input + Вход + + + + Method + Способ + + + + Box + По рамке + + + + Gaussian + Гауссово + + + + Radius + Радиус + + + + Horizontal + По горизонтали + + + + Vertical + По вертикали + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + Клип + + + + A time-based node that represents a media source. + + + + + Buffer + Буфер + + + + olive::ColorDialog + + + Select Color + Выбрать цвет + + + + olive::ColorSpaceChooser + + + Color Management + Управление цветом + + + + Input: + Вход: + + + + Color Space: + Пространство: + + + + Display: + Дисплей: + + + + View: + Вид: + + + + Look: + Обработка: + + + + (None) + (нет) + + + + olive::ColorValuesTab + + + Red + Красный + + + + Green + Зеленый + + + + Blue + Синий + + + + olive::ColorValuesWidget + + + Preview + Предпросмотр + + + + Input + Вход + + + + Reference + + + + + Display + Дисплей + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + Нет активного проекта + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + Новая папка + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + Сохранить проект + + + + + Error + Ошибка + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + Сохранить проект как + + + + Load Project + Загрузка проекта + + + + Label Node + Метка ноды + + + + Set node label + Указать метку ноды + + + + Sequence %1 + Последовательность %1 + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + Несохраненные изменения + + + + The project '%1' has unsaved changes. Would you like to save them? + В проекте '%1' остались несохраненные изменения. Сохранить их? + + + + Save + Сохранить + + + + Save All + Сохранить все + + + + Don't Save + Не сохранять + + + + Don't Save All + Не сохранять все + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + Открыть проект + + + + olive::CrashHandlerDialog + + + Olive + Olive + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + Отчет о падении: + + + + Send Error Report + Отправить отчет + + + + Don't Send + Не отправлять + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CropDistortNode + + + Texture + Текстура + + + + Left + Слева + + + + Top + Сверху + + + + Right + Справа + + + + Bottom + Снизу + + + + Feather + Растушевка + + + + Crop + Обрезка + + + + Crop the edges of an image. + Обрезать края кадра + + + + olive::CrossDissolveTransition + + + Cross Dissolve + Наплыв + + + + Smoothly transition between two clips. + Плавный переход между двумя клипами. + + + + olive::CurvePanel + + + Curve Editor + Редактор кривых + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + Линейный + + + + Bezier + Безье + + + + Hold + Константа + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + Дисковый кэш: %1 + + + + Disk Cache Settings + Параметры кэша на диске + + + + Maximum Disk Cache: + Макс. кэш на диске: + + + + %1 GB + %1 Гбайт + + + + + + Clear Disk Cache + Очистить дисковый кэш + + + + Automatically clear disk cache on close + Автоматически стирать при закрытии + + + + Are you sure you want to clear the disk cache in '%1'? + Вы действительно хотите стереть дисковый кэш в '%1'? + + + + Disk Cache Cleared + Дисковый кэш очищен + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + Дисковый кэш частично очищен + + + + olive::DiskManager + + + + Disk Cache Error + Ошибка дискового кэша + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + Дисковый кэш + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + Дополнительные параметры + + + + Pixel + Пиксели + + + + Pixel Format: + Формат: + + + + Performance + Производительность + + + + Threads: + Потоков: + + + + olive::ExportAudioTab + + + Codec: + Кодек: + + + + Sample Rate: + Частота дискр.: + + + + Channel Layout: + Схема каналов: + + + + Format: + Формат: + + + + olive::ExportCodec + + + DNxHD + DNxHD + + + + H.264 + H.264 + + + + H.265 + H.265 + + + + OpenEXR + OpenEXR + + + + PNG + PNG + + + + ProRes + ProRes + + + + TIFF + TIFF + + + + MP2 + MP2 + + + + MP3 + MP3 + + + + AAC + AAC + + + + PCM (Uncompressed) + PCM (несжатый) + + + + Unknown + Неизвестно + + + + olive::ExportDialog + + + Filename: + Имя файла: + + + + Browse for exported file filename + + + + + Preset: + Профиль: + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + Диапазон: + + + + Entire Sequence + Вся последовательность + + + + In to Out + От входа от выхода + + + + Format: + Формат: + + + + Export Video + Экспорт видео + + + + Export Audio + Экспорт звука + + + + Video + Видео + + + + Audio + Звук + + + + + Export + Экспортировать + + + + Preview + Предпросмотр + + + + Invalid parameters + Некорректные параметры + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + Подтвердить перезапись + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + Некорректные параметры + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + DNxHD + + + + Matroska Video + Matroska + + + + MPEG-4 Video + MPEG-4 + + + + OpenEXR + OpenEXR + + + + PNG + PNG + + + + TIFF + TIFF + + + + QuickTime + QuickTime + + + + Unknown + Неизвестно + + + + olive::ExportTask + + + Exporting "%1" + Экспортируется "%1" + + + + Failed to create encoder + Не удалось создать кодировщик + + + + Failed to open file + Не удалось открыть файл + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + Основные + + + + Width: + Ширина: + + + + Height: + Высота: + + + + Maintain Aspect Ratio: + Сохранить пропорции: + + + + Scaling Method: + Тип масштабирования: + + + + Fit + Уместить + + + + Stretch + Растянуть + + + + Crop + Обрезать + + + + Frame Rate: + Частота кадров: + + + + Pixel Aspect Ratio: + Пропорции пикселя: + + + + Interlacing: + Чересстрочность: + + + + Quality: + Качество: + + + + Codec + Кодек + + + + Codec: + Кодек: + + + + Advanced + Дополнительно + + + + olive::FloatSlider + + + %1 dB + %1 Дб + + + + %1% + %1% + + + + olive::FootagePropertiesDialog + + + "%1" Properties + Свойства "%1" + + + + Name: + Название: + + + + Tracks: + Дорожек: + + + + olive::FootageRelinkDialog + + + Footage + Видеоматериал + + + + Filename + Имя файла + + + + Actions + Действия + + + + Browse + Просмотр + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + Все файлы + + + + olive::FootageViewerPanel + + + Footage Viewer + Просмотр видеоматериала + + + + olive::GapBlock + + + Gap + Интервал + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + Целевая скорость потока (Мбит/с): + + + + Maximum Bit Rate (Mbps): + Макс. скорость потока (Мбит/с): + + + + Two-Pass + В два прохода + + + + olive::H264FileSizeSection + + + Target File Size (MB): + Целевой размер файла (Мбайт): + + + + Two-Pass + В два прохода + + + + olive::H264Section + + + Compression Method: + Способ сжатия: + + + + Constant Rate Factor + Постоянная скорость потока + + + + Target Bit Rate + Целевая скорость потока + + + + Target File Size + Целевой размер файла + + + + olive::ImageSection + + + Image Sequence: + Последовательность изображений: + + + + olive::InterlacedComboBox + + + None (Progressive) + Нет (прогрессивно) + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + Свойства ключевого кадра + + + + In: + Вход: + + + + Out: + Выход: + + + + Linear + Линейный + + + + Hold + Константа + + + + Bezier + Безье + + + + olive::KeyframeViewBase + + + Linear + Линейный + + + + Bezier + Безье + + + + Hold + Константа + + + + P&roperties + С&войства + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + Со&хранить '%1' + + + + Save '%1' &As + Сохранить '%1' к&ак + + + + Close '%1' + Закрыть '%1' + + + + Close All Except '%1' + Закрыть все кроме '%1' + + + + &Save Project + &Сохранить проект + + + + Save Project &As + Сохранить проект &как + + + + Close Project + Закрыть проект + + + + Close All Except Current Project + Закрыть все проекты кроме текущего + + + + (None) + (нет) + + + + &File + &Файл + + + + &New + &Создать + + + + &Open Project + &Открыть проект + + + + Open &Recent + Открыть из &недавнего + + + + &Clear Recent List + О&чистить список недавних + + + + Sa&ve All Projects + Сохра&нить все проекты + + + + &Import... + &Импортировать… + + + + &Export + &Экспортировать + + + + &Media... + &Медиаданные… + + + + &Project Properties... + С&войства проекта… + + + + Close All Projects + Закрыть все проекты + + + + E&xit + В&ыход + + + + &Edit + &Правка + + + + Insert + Вставить + + + + Overwrite + Переписать + + + + Select &All + Выд&елить всё + + + + Deselect All + Снять выделение + + + + Ripple to In Point + Сдвиг до точки входа + + + + Ripple to Out Point + Сдвиг до точки выхода + + + + Edit to In Point + Правка до точки входа + + + + Edit to Out Point + Правка до точки выхода + + + + Delete In/Out Point + Удалить точку входа/выхода + + + + Ripple Delete In/Out Point + Удалить со сдвигом точку входа/выхода + + + + Set/Edit Marker + Установить/Изменить маркер + + + + &View + &Вид + + + + Zoom In + Приблизить + + + + Zoom Out + Отдалить + + + + Increase Track Height + Увеличить высоту дорожки + + + + Decrease Track Height + Уменьшить высоту дорожки + + + + Toggle Show All + Показывать весь проект + + + + Full Screen + Полноэкранный режим + + + + Full Screen Viewer + Просмотр в полноэкранном режиме + + + + &Playback + Вос&произведение + + + + Go to Start + К началу + + + + Previous Frame + К предыдущему кадру + + + + Play/Pause + Воспроизведение/Пауза + + + + Play In to Out + Проиграть от входа до выхода + + + + Next Frame + К следующему кадру + + + + Go to End + В конец + + + + Go to Previous Cut + + + + + Go to Next Cut + + + + + Go to In Point + К точке входа + + + + Go to Out Point + К точке выхода + + + + Shuttle Left + Уменьшить скорость + + + + Shuttle Stop + Пауза + + + + Shuttle Right + Увеличить скорость + + + + Loop + Петля + + + + &Sequence + П&оследовательность + + + + Cache Entire Sequence + Закэшировать всю последовательность + + + + Cache Sequence In/Out + Закэшировать вход/выход последовательности + + + + &Window + &Окно + + + + Maximize Panel + Развернуть панель + + + + Lock Panels + Закрепить панели + + + + Reset to Default Layout + Вернуть исходный вид панелей + + + + &Tools + &Инструменты + + + + Pointer Tool + Указатель + + + + Edit Tool + Выделение + + + + Ripple Tool + Монтаж со сдвигом + + + + Rolling Tool + Монтаж с совмещением + + + + Razor Tool + Подрезка + + + + Slip Tool + Прокрутка с совмещением + + + + Slide Tool + Прокрутка + + + + Hand Tool + Навигация + + + + Zoom Tool + Масштаб + + + + Transition Tool + Переход + + + + Enable Snapping + Включить прилипание + + + + Preferences + Параметры + + + + &Help + &Справка + + + + A&ction Search + &Найти команду + + + + Send &Feedback... + &Дать обратную связь… + + + + &About... + &О программе… + + + + olive::MainStatusBar + + + Welcome to %1 %2 + Приветствуем в %1 %2 + + + + Running %1 background task(s) + + + + + olive::MainWindow + + + Driver Warning + Предупреждение драйвера + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + Цветовое пространство + + + + No color manager connected + + + + + Display + Дисплей + + + + View + Вид + + + + Look + Представление + + + + (None) + (нет) + + + + OpenColorIO Error + Ошибка OpenColorIO + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + Дисплей + + + + Reference + + + + + olive::MathNode + + + Math + Математика + + + + Perform a mathematical operation between two values. + Выполнить математическую операцию с двумя значениями + + + + Method + Способ + + + + + Value + Значение + + + + Add + Сложение + + + + Subtract + Вычитание + + + + Multiply + Умножение + + + + Divide + Деление + + + + Power + Степень + + + + olive::MatrixGenerator + + + Orthographic Matrix + Прямоугольная матрица + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + Позиция + + + + Rotation + Вращение + + + + Scale + Масштаб + + + + Uniform Scale + Пропорции + + + + Anchor Point + Точка привязки + + + + olive::MediaInput + + + + Media + Медиа + + + + Import footage into the node graph. + + + + + olive::MenuShared + + + &Project + &Проект + + + + &Sequence + П&оследовательность + + + + &Folder + П&апка + + + + Cu&t + В&ырезать + + + + Cop&y + С&копировать + + + + &Paste + &Вставить + + + + Paste Insert + + + + + Duplicate + Сделать копию + + + + Delete + Удалить + + + + Ripple Delete + Удалить со сдвигом + + + + Split + Разделить + + + + Set In Point + Установить точку входа + + + + Set Out Point + Установить точку выхода + + + + Reset In Point + Сбросить точку входа + + + + Reset Out Point + Сбросить точку выхода + + + + Clear In/Out Point + Очистить точки входа/выхода + + + + Add Default Transition + Добавить переход по умолчанию + + + + Link/Unlink + Связать/Убрать связь + + + + Enable/Disable + Включить/Отключить + + + + Nest + Вложить + + + + Frames + Кадры + + + + Drop Frame + С пропуском кадров + + + + Non-Drop Frame + Без пропуска кадров + + + + Milliseconds + Миллисекунды + + + + Seconds + Секунды + + + + olive::MergeNode + + + Merge + Объединение + + + + Merge two textures together. + Объединить две текстуры. + + + + Base + Основа + + + + Blend + Совмещение + + + + olive::MosaicFilterNode + + + Texture + Текстура + + + + Horizontal + По горизонтали + + + + Vertical + По вертикали + + + + Mosaic + Мозаика + + + + Apply a pixelated mosaic filter to video. + + + + + olive::Node + + + Input + Вход + + + + Output + Выход + + + + General + Общие + + + + Distort + + + + + Math + Математика + + + + Color + Цвет + + + + Filter + Фильтр + + + + Timeline + Монтажный стол + + + + Generator + Генератор + + + + Channel + Канал + + + + Transition + Переход + + + + Uncategorized + Без категории + + + + olive::NodeInput + + + Input + Вход + + + + olive::NodeOutput + + + Output + Выход + + + + olive::NodePanel + + + Node Editor + Редактор нод + + + + olive::NodeParam + + + Value + Значение + + + + None + Нет + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + Цвет + + + + Matrix + + + + + Text + Текст + + + + Font + Шрифт + + + + File + + + + + Texture + Текстура + + + + Samples + + + + + Footage + Видеоматериал + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + Неизвестно + + + + olive::NodeParamViewArrayWidget + + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + Соединено с + + + + Nothing + ничем + + + + Disconnect + Отсоединить + + + + olive::NodeParamViewItem + + + %1 (%2) + %1 (%2) + + + + olive::NodeParamViewItemBody + + + %1: + %1: + + + + olive::NodeParamViewKeyframeControl + + + Warning + Предупреждение + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + Просмотр таблицей + + + + olive::NodeTableView + + + Type + Тип + + + + Source + Источник + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + (неизвестно) + + + + olive::NodeTreeView + + + Nodes + Ноды + + + + olive::NodeView + + + Label + Метка + + + + Auto-Position + Автопозиционирование + + + + Smooth Edges + Плавные края + + + + Filter + Фильтр + + + + Show All + Показывать все + + + + Show Selected Blocks Only + Показывать только выбранные блоки + + + + Direction + Направление + + + + Top to Bottom + Сверху вниз + + + + Bottom to Top + Снизу вверх + + + + Left to Right + Слева направо + + + + Right to Left + Справа налево + + + + Add + Добавить + + + + olive::PanNode + + + + Pan + Панорама + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + Редактор параметров + + + + (none) + (нет) + + + + (multiple) + (больше одного) + + + + olive::PathWidget + + + Browse + Просмотр + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + Цвет + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + Цвет + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + Тема + + + + Node Color Scheme + Цветовая схема нод + + + + olive::PreferencesAudioTab + + + Output Device: + Устройство выхода: + + + + Input Device: + Устройство входа: + + + + Sample Rate: + Частота дискретизации: + + + + Audio Recording: + Запись звука: + + + + Mono + Моно + + + + Stereo + Стерео + + + + Refresh Devices + Обновить список устройств + + + + Please wait... + Подождите, пожалуйста… + + + + Default + По умолчанию + + + + olive::PreferencesBehaviorTab + + + Behavior + Поведение + + + + General + Общие + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + Звук + + + + Enable audio scrubbing + + + + + Timeline + Монтажный стол + + + + Auto-Seek to Imported Clips + + + + + Edit Tool Also Seeks + Выделение с перемоткой + + + + Edit Tool Selects Links + Выделение выбирает связи + + + + Enable Drag Files to Timeline + Разрешить перетаскивание на монтажный стол извне + + + + Invert Timeline Scroll Axes + + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + Перемотка с выделением + + + + Seek to the End of Pastes + Перемотка до конца вставок + + + + Selecting Also Seeks + Выделение с перемоткой + + + + Playback + Воспроизведение + + + + Ask For Name When Setting Marker + Спрашивать имя маркера при добавлении + + + + Automatically rewind at the end of a sequence + + + + + Project + Проект + + + + Drop Files on Media to Replace + + + + + Nodes + Ноды + + + + Add Default Effects to New Clips + Добавлять эффекты по умолчанию в новые клипы + + + + Auto-Scale By Default + Автоматически масштабировать по умолчанию + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + Параметры + + + + General + Общие + + + + Appearance + Внешний вид + + + + Behavior + Поведение + + + + Disk + Диск + + + + Audio + Звук + + + + Keyboard + Клавиатурные комбинации + + + + olive::PreferencesDiskTab + + + Disk Management + Управление диском + + + + Disk Cache Location: + Размещение кэша на диске: + + + + Disk Cache Settings + Параметры кэша на диске + + + + Cache Behavior + Поведение кэша + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + Дисковый кэш + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + Язык: + + + + Auto-Scroll Method: + Способ автопрокрутки: + + + + None + Нет + + + + Page Scrolling + Целыми страницами + + + + Smooth Scrolling + Плавной прокруткой + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + %1 (%2) + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + Искать действие или комбинацию клавиш + + + + Action + Действие + + + + Shortcut + Комбинация + + + + Import + Импортировать + + + + Export + Экспортировать + + + + Reset Selected + Сбросить выбранное + + + + Reset All + Сбросить все + + + + Confirm Reset All Shortcuts + Подтвердите действие + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + Вы действительно хотите сбросить все клавиатурные комбинации к исходным значениям? + + + + Import Keyboard Shortcuts + Импортировать клавиатурные комбинации + + + + + Error saving shortcuts + Ошибка при сохранении клавиатурных комбинаций + + + + Failed to open file for reading + Не удалось открыть файл для чтения + + + + Export Keyboard Shortcuts + Экспортировать клавиатурные комбинации + + + + Export Shortcuts + Экспортировать клавиатурные комбинации + + + + Shortcuts exported successfully + Комбинации успешно экспортированы + + + + Failed to open file for writing + Не удалось открыть файл для записи + + + + olive::ProgressDialog + + + Cancel + Отмена + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + &Создать + + + + &Import... + &Импортировать… + + + + &Project Properties... + С&войства проекта… + + + + Open in New Tab + Открыть в новой вкладке + + + + Open in New Window + Открыть в новом окне + + + + Reveal in Explorer + Открыть в Проводнике + + + + Reveal in Finder + Открыть в Finder + + + + Reveal in File Manager + Открыть в файловом менеджере + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + С&войства + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + Удалить клипы + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + Импортируется %1 файлов + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + Загружается '%1' + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + Папка + + + + Project + Проект + + + + (none) + (нет) + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + Свойства проекта '%1' + + + + OpenColorIO Configuration: + Конфигурация OpenColorIO: + + + + (default) + (по умолчанию) + + + + Default Input Color Space: + Пространство входа по умолчанию: + + + + Browse + Просмотр + + + + Color Management + Управление цветом + + + + Use Default Location + Использовать обычное размещение + + + + Store Alongside Project + Хранить рядом с проектом + + + + Use Custom Location: + Размещать где-то еще: + + + + Disk Cache Settings + Параметры кэша на диске + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + Дисковый кэш + + + + OpenColorIO Config Error + Ошибка в конфгурации OpenColorIO + + + + Failed to set OpenColorIO configuration: %1 + + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + Указать файл конфигурации OpenColorIO + + + + olive::ProjectSaveTask + + + Saving '%1' + Сохраняется '%1' + + + + Failed to write XML data + Не удалось записать данные XML + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + Создать… + + + + Open Project + Открыть проект + + + + Save Project + Сохранить проект + + + + Undo + Отменить + + + + Redo + Вернуть + + + + Search media, markers, etc. + Искать файлы, маркеры и т.д. + + + + Switch to Tree View + Переключиться на древовидное представление + + + + Switch to List View + Переключиться на список + + + + Switch to Icon View + Переключиться на миниатюры + + + + olive::ProjectViewModel + + + Name + Название + + + + Duration + Длительность + + + + Rate + Частота + + + + Move Items + Переместить объекты + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + Ж + + + + Bold + Полужирный + + + + I + К + + + + Italic + Курсив + + + + U + П + + + + Underline + Подчеркивание + + + + S + В + + + + Strikethrough + Вычеркнутый + + + + Font Family + Гарнитура + + + + Font Size + Кегль шрифта + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + Волновая форма + + + + Histogram + Гистограмма + + + + Scope + Анализатор + + + + olive::SequenceDialog + + + Name: + Название: + + + + New Sequence + Новая последовательность + + + + Editing "%1" + Правка "%1" + + + + Error editing Sequence + Ошибка при редактировании последовательности + + + + Please enter a name for this Sequence. + Введите название этой последовательности + + + + olive::SequenceDialogParameterTab + + + Video + Видео + + + + Width: + Ширина: + + + + Height: + Высота: + + + + Frame Rate: + Частота кадров: + + + + Pixel Aspect Ratio: + Соотн. сторон пикселя: + + + + Interlacing: + Чересстрочность: + + + + Audio + Звук + + + + Sample Rate: + Частота дискр.: + + + + Channels: + Каналов: + + + + Preview + Предпросмотр + + + + Resolution: + Разрешение: + + + + Quality: + Качество: + + + + Save Preset + Сохранить профиль + + + + (%1x%2) + (%1x%2) + + + + olive::SequenceDialogPresetTab + + + Preset + Профиль + + + + My Presets + Мои профили + + + + 4K UHD + 4K UHD + + + + 1080p + 1080p + + + + 720p + 720p + + + + NTSC + NTSC + + + + PAL + PAL + + + + %1 23.976 FPS + %1 23,976 к/с + + + + %1 25 FPS + %1 25 к/с + + + + %1 29.97 FPS + %1 29,97 к/с + + + + %1 50 FPS + %1 50 к/с + + + + %1 59.94 FPS + %1 59,94 к/с + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + Удалить профиль + + + + olive::SequenceViewerPanel + + + Sequence Viewer + Монитор последовательностей + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + + + + + Generate a solid color. + + + + + Color + Цвет + + + + olive::StringSlider + + + (none) + (нет) + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + Вход + + + + Color + Цвет + + + + Radius + Радиус + + + + Opacity + Непрозрачность + + + + Inner + + + + + olive::Task + + + Task + Задача + + + + Unknown error + Неизвестная ошибка + + + + olive::TaskDialog + + + Task Failed + Не удалось выполнить задачу + + + + olive::TaskManagerPanel + + + Task Manager + Управление задачами + + + + olive::TaskViewItem + + + Error: %1 + Ошибка: %1 + + + + olive::TextGenerator + + + Sample Text + Образец текста + + + + + Text + Текст + + + + Generate rich text. + Создать форматированный текст. + + + + Font + Шрифт + + + + Font Size + Кегль шрифта + + + + Color + Цвет + + + + Vertical Align + Верт. выравнивание + + + + Top + Сверху + + + + Center + По центру + + + + Bottom + Снизу + + + + olive::TimeBasedPanel + + + (none) + (нет) + + + + olive::TimeBasedWidget + + + Set Marker + Установить маркер + + + + Marker name: + Название маркера: + + + + olive::TimeInput + + + Time + Время + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + Монтажный стол + + + + olive::TimelineWidget + + + + Properties + Свойства + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + Инструменты + + + + olive::Toolbar + + + Pointer Tool + Указатель + + + + Edit Tool + Выделение + + + + Ripple Tool + Монтаж со сдвигом + + + + Rolling Tool + Монтаж с совмещением + + + + Razor Tool + Подрезка + + + + Slip Tool + Прокрутка с совмещением + + + + Slide Tool + Прокрутка + + + + Hand Tool + Навигация + + + + Zoom Tool + Масштаб + + + + Transition Tool + Переход + + + + Record Tool + Запись + + + + Add Tool + + + + + Toggle Snapping + Переключить прилипание + + + + olive::TrackOutput + + + Track + Дорожка + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + Видео %1 + + + + Audio %1 + Звук %1 + + + + Subtitle %1 + Субтитры %1 + + + + Track %1 + Дорожка %1 + + + + olive::TrackViewItem + + + M + М + + + + L + Б + + + + olive::TransformDistortNode + + + Auto-Scale + Автомасштаб + + + + Texture + Текстура + + + + Interpolation + Интерполяция + + + + None + Нет + + + + Fit + Уместить + + + + Fill + Заполнить + + + + Stretch + Растянуть + + + + Nearest Neighbor + + + + + Bilinear + + + + + Mipmapped Bilinear + + + + + Transform + Трансформация + + + + Transform an image in 2D space. Equivalent to multiplying by an orthographic matrix. + + + + + olive::TransitionBlock + + + From + От + + + + To + До + + + + Curve + Кривая + + + + Linear + Линейный + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + Тригонометрия + + + + Perform a trigonometry operation on a value. + Произвести тригонометрическую операцию над значением + + + + Sine + Синус + + + + Cosine + Косинус + + + + Tangent + Тангенс + + + + Inverse Sine + Инверт. синус + + + + Inverse Cosine + Инверт. косинус + + + + Inverse Tangent + Инверт. тангенс + + + + Hyperbolic Sine + Гипербол. синус + + + + Hyperbolic Cosine + Гипербол. косинус + + + + Hyperbolic Tangent + Гипербол. тангенс + + + + Method + Способ + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + 144p {1/%1?} + + + + olive::VideoStreamProperties + + + Pixel Aspect: + Пропорции пикселей: + + + + Interlacing: + Чересстрочность: + + + + Color Space: + Пространство: + + + + Default (%1) + По умолчанию (%1) + + + + Premultiplied Alpha + + + + + Image Sequence + Последовательность изображений + + + + Start Index: + Начало индекса: + + + + End Index: + Конец индекса: + + + + Frame Rate: + Частота кадров: + + + + Invalid Configuration + Некорректная конфигурация + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + Монитор + + + + Interface between a Viewer panel and the node system. + + + + + Texture + Текстура + + + + Samples + + + + + Video Tracks + Видеодорожки + + + + Audio Tracks + Звуковые дорожки + + + + Subtitle Tracks + Дорожки субтитров + + + + olive::ViewerPanel + + + Viewer + Монитор + + + + olive::ViewerWidget + + + Error + Ошибка + + + + No in or out points are set to cache. + + + + + + Safe Margins + Безопасная область + + + + Zoom + Масштаб + + + + Fit + Уместить + + + + %1% + %1% + + + + Full Screen + Полноэкранный режим + + + + Screen %1: %2x%3 + Экран %1: %2×%3 + + + + Deinterlace + + + + + Scopes + Анализаторы + + + + Cache + Кэш + + + + Auto-Cache + Автокэширование + + + + Pause Auto-Cache During Playback + Приостанавливать автокэширование при воспроизведении + + + + Cache Entire Sequence + Закэшировать всю последовательность + + + + Cache Sequence In/Out + Закэшировать вход/выход последовательности + + + + Off + Выкл. + + + + On + Вкл + + + + Custom Aspect + Другое соотношение + + + + Show Audio Waveform + Показывать волновую форму + + + + olive::VolumeNode + + + + Volume + Громкость + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/sr_RS.ts b/app/ts/sr_RS.ts new file mode 100644 index 000000000..7aa0e4601 --- /dev/null +++ b/app/ts/sr_RS.ts @@ -0,0 +1,4773 @@ + + + + + AudioParams + + + %1 Hz + %1 Hz + + + + Mono + Моно + + + + Stereo + Стерео + + + + 2.1 + 2.1 + + + + 5.1 + 5.1 + + + + 7.1 + 7.1 + + + + Unknown (0x%1) + Непознато (0x%1) + + + + Config + + + Error loading settings + Грешка при учитавању поставки + + + + Failed to load application settings. This session will use defaults. + +%1 + “Сесија” might not be the most adequate term for “session” + Неуспешно учитавање поставки апликације. Ова сесија ће користити задане поставке. + +%1 + + + + Error saving settings + Грешка при спашавању поставки + + + + Failed to save application settings. The application may lack write permissions for this location. + Неуспешно спашавање поставки апликације. Апликацији можда недостају допуштења за писање у овој локацији. + + + + Footage + + + %1 FPS + + + + + %1 Hz + %1 Hz + + + + Filename: %1 + + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + + + + + Automatically Detect Parameters From Footage + + + + + Set Parameters Manually + + + + + MoveItemCommand + + + Move Item + + + + + NodeCopyPasteWidget + + + Error pasting nodes + + + + + Failed to paste nodes: %1 + + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + + + + + Set preset name: + + + + + Invalid preset name + + + + + You must enter a preset name + + + + + Preset exists + + + + + A preset with this name already exists. Would you like to replace it? + + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + + + + + %1: Unknown + + + + + %1: Image - %2x%3 + + + + + %1: Video - %2x%3 + + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + + + + + Bars + + + + + Solid + + + + + Title + + + + + Tone + + + + + Unknown + + + + + VideoParams + + + 8-bit + + + + + 16-bit Integer + + + + + Half-Float (16-bit) + + + + + Full-Float (32-bit) + + + + + Unknown (0x%1) + Непознато (0x%1) + + + + %1 FPS + + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + + + + + Show application version + + + + + Start in full-screen mode + + + + + Export only (No GUI) + + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + + + + + olive::AboutDialog + + + About %1 + О %1 + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive је нелинеарни видео уређивач. Овај софтвер је слободан и заштићен GNU GPL-ом. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + Olive тим је под обавезом да обавести кориснике да је Olive-ов изворни код доступан за преузимање са његове веб странице. + + + + olive::ActionSearch + + + Search for action... + Потражите радњу... + + + + olive::AudioMonitorPanel + + + Audio Monitor + + + + + olive::Block + + + Length + + + + + Media In + + + + + Enabled + + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + + + + + Blurs an image. + + + + + Input + + + + + Method + + + + + Box + + + + + Gaussian + + + + + Radius + + + + + Horizontal + + + + + Vertical + + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + + + + + A time-based node that represents a media source. + + + + + Buffer + + + + + olive::ColorDialog + + + Select Color + + + + + olive::ColorSpaceChooser + + + Color Management + + + + + Input: + + + + + Color Space: + + + + + Display: + + + + + View: + + + + + Look: + + + + + (None) + + + + + olive::ColorValuesTab + + + Red + + + + + Green + + + + + Blue + + + + + olive::ColorValuesWidget + + + Preview + + + + + Input + + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + + + + + + Error + + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + + + + + Load Project + + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + + + + + Save All + + + + + Don't Save + + + + + Don't Save All + + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + + + + + Send Error Report + + + + + Don't Send + + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CrossDissolveTransition + + + Cross Dissolve + + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + Линеарно + + + + Bezier + Bezier + + + + Hold + Држи + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + + + + + Disk Cache Settings + + + + + Maximum Disk Cache: + + + + + %1 GB + + + + + + + Clear Disk Cache + + + + + Automatically clear disk cache on close + + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + + + + + olive::DiskManager + + + + Disk Cache Error + + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + Напредно + + + + Pixel + + + + + Pixel Format: + Формат пиксела: + + + + Performance + + + + + Threads: + + + + + olive::ExportAudioTab + + + Codec: + Кодек: + + + + Sample Rate: + + + + + Channel Layout: + + + + + Format: + Формат: + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + + + + + olive::ExportDialog + + + Filename: + + + + + Browse for exported file filename + + + + + Preset: + + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + Распон: + + + + Entire Sequence + Читава секвенца + + + + In to Out + Од почетка до краја + + + + Format: + Формат: + + + + Export Video + + + + + Export Audio + + + + + Video + Видео + + + + Audio + Аудио + + + + + Export + + + + + Preview + + + + + Invalid parameters + + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + + + + + olive::ExportTask + + + Exporting "%1" + + + + + Failed to create encoder + + + + + Failed to open file + + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + Ширина: + + + + Height: + Висина: + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + + + + + Fit + + + + + Stretch + + + + + Crop + + + + + Frame Rate: + Оквирна стопа: + + + + Pixel Aspect Ratio: + + + + + Interlacing: + + + + + Quality: + + + + + Codec + + + + + Codec: + Кодек: + + + + Advanced + Напредно + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + + + + + Name: + + + + + Tracks: + + + + + olive::FootageRelinkDialog + + + Footage + + + + + Filename + + + + + Actions + + + + + Browse + + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + + + + + olive::FootageViewerPanel + + + Footage Viewer + + + + + olive::GapBlock + + + Gap + + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + + + + + Maximum Bit Rate (Mbps): + + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + Жељена величина датотеке (MB): + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + + + + + Constant Rate Factor + + + + + Target Bit Rate + + + + + Target File Size + + + + + olive::ImageSection + + + Image Sequence: + + + + + olive::InterlacedComboBox + + + None (Progressive) + Нема (прогресивно) + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + + + + + In: + + + + + Out: + + + + + Linear + Линеарно + + + + Hold + Држи + + + + Bezier + Bezier + + + + olive::KeyframeViewBase + + + Linear + Линеарно + + + + Bezier + Bezier + + + + Hold + Држи + + + + P&roperties + + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + + + + + Save '%1' &As + + + + + Close '%1' + + + + + Close All Except '%1' + + + + + &Save Project + + + + + Save Project &As + + + + + Close Project + + + + + Close All Except Current Project + + + + + (None) + + + + + &File + + + + + &New + + + + + &Open Project + + + + + Open &Recent + + + + + &Clear Recent List + + + + + Sa&ve All Projects + + + + + &Import... + + + + + &Export + + + + + &Media... + + + + + &Project Properties... + + + + + Close All Projects + + + + + E&xit + + + + + &Edit + + + + + Insert + + + + + Overwrite + + + + + Select &All + + + + + Deselect All + + + + + Ripple to In Point + + + + + Ripple to Out Point + + + + + Edit to In Point + + + + + Edit to Out Point + + + + + Delete In/Out Point + + + + + Ripple Delete In/Out Point + + + + + Set/Edit Marker + + + + + &View + + + + + Zoom In + + + + + Zoom Out + + + + + Increase Track Height + + + + + Decrease Track Height + + + + + Toggle Show All + + + + + Full Screen + + + + + Full Screen Viewer + + + + + &Playback + + + + + Go to Start + + + + + Previous Frame + + + + + Play/Pause + + + + + Play In to Out + + + + + Next Frame + + + + + Go to End + + + + + Go to Previous Cut + + + + + Go to Next Cut + + + + + Go to In Point + + + + + Go to Out Point + + + + + Shuttle Left + + + + + Shuttle Stop + + + + + Shuttle Right + + + + + Loop + + + + + &Sequence + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + &Window + + + + + Maximize Panel + + + + + Lock Panels + + + + + Reset to Default Layout + + + + + &Tools + + + + + Pointer Tool + + + + + Edit Tool + + + + + Ripple Tool + + + + + Rolling Tool + + + + + Razor Tool + + + + + Slip Tool + + + + + Slide Tool + + + + + Hand Tool + + + + + Zoom Tool + + + + + Transition Tool + + + + + Enable Snapping + + + + + Preferences + + + + + &Help + + + + + A&ction Search + + + + + Send &Feedback... + + + + + &About... + + + + + olive::MainStatusBar + + + Welcome to %1 %2 + + + + + Running %1 background tasks + + + + + olive::MainWindow + + + Driver Warning + + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + + + + + No color manager connected + + + + + Display + + + + + View + + + + + Look + + + + + (None) + + + + + OpenColorIO Error + + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + + + + + Subtract + + + + + Multiply + + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + + + + + Rotation + + + + + Scale + + + + + Uniform Scale + + + + + Anchor Point + + + + + olive::MediaInput + + + + Media + + + + + Import footage into the node graph. + + + + + olive::MenuShared + + + &Project + + + + + &Sequence + + + + + &Folder + + + + + Cu&t + &Режи + + + + Cop&y + + + + + &Paste + &Залепи + + + + Paste Insert + + + + + Duplicate + + + + + Delete + + + + + Ripple Delete + + + + + Split + + + + + Set In Point + + + + + Set Out Point + + + + + Reset In Point + + + + + Reset Out Point + + + + + Clear In/Out Point + + + + + Add Default Transition + + + + + Link/Unlink + + + + + Enable/Disable + + + + + Nest + + + + + Frames + + + + + Drop Frame + + + + + Non-Drop Frame + + + + + Milliseconds + + + + + Seconds + + + + + olive::MergeNode + + + Merge + + + + + Merge two textures together. + + + + + Base + + + + + Blend + + + + + olive::MosaicFilterNode + + + Texture + + + + + Horizontal + + + + + Vertical + + + + + Mosaic + + + + + Apply a pixelated mosaic filter to video. + + + + + olive::Node + + + Input + + + + + Output + + + + + General + + + + + Math + + + + + Color + + + + + Filter + + + + + Timeline + + + + + Generator + + + + + Channel + + + + + Transition + + + + + Uncategorized + + + + + olive::NodeInput + + + Input + + + + + olive::NodeOutput + + + Output + + + + + olive::NodePanel + + + Node Editor + + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + + + + + Matrix + + + + + Text + + + + + Font + + + + + File + + + + + Texture + + + + + Samples + + + + + Footage + + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + + + + + Nothing + + + + + Disconnect + + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + + + + + olive::NodeTableView + + + Type + Тип + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + + + + + olive::NodeTreeView + + + Nodes + + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + + + + + Filter + + + + + Show All + + + + + Show Selected Blocks Only + + + + + Direction + + + + + Top to Bottom + + + + + Bottom to Top + + + + + Left to Right + + + + + Right to Left + + + + + Add + + + + + olive::PanNode + + + + Pan + + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + + + + + (none) + (нема) + + + + (multiple) + + + + + olive::PathWidget + + + Browse + + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + + + + + Node Color Scheme + + + + + olive::PreferencesAudioTab + + + Output Device: + + + + + Input Device: + + + + + Sample Rate: + + + + + Audio Recording: + + + + + Mono + Моно + + + + Stereo + Стерео + + + + Refresh Devices + + + + + Please wait... + + + + + Default + + + + + olive::PreferencesBehaviorTab + + + Behavior + + + + + General + + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + Аудио + + + + Enable audio scrubbing + + + + + Timeline + + + + + Auto-Seek to Imported Clips + + + + + Edit Tool Also Seeks + + + + + Edit Tool Selects Links + + + + + Enable Drag Files to Timeline + + + + + Invert Timeline Scroll Axes + + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + + + + + Seek to the End of Pastes + + + + + Selecting Also Seeks + + + + + Playback + + + + + Ask For Name When Setting Marker + + + + + Automatically rewind at the end of a sequence + + + + + Project + + + + + Drop Files on Media to Replace + + + + + Nodes + + + + + Add Default Effects to New Clips + + + + + Auto-Scale By Default + + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + + + + + General + + + + + Appearance + + + + + Behavior + + + + + Disk + + + + + Audio + Аудио + + + + Keyboard + + + + + olive::PreferencesDiskTab + + + Disk Management + + + + + Disk Cache Location: + + + + + Disk Cache Settings + + + + + Cache Behavior + + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + + + + + Auto-Scroll Method: + + + + + None + + + + + Page Scrolling + + + + + Smooth Scrolling + + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + + + + + Action + + + + + Shortcut + + + + + Import + + + + + Export + + + + + Reset Selected + + + + + Reset All + + + + + Confirm Reset All Shortcuts + + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + + + + + Import Keyboard Shortcuts + + + + + + Error saving shortcuts + + + + + Failed to open file for reading + + + + + Export Keyboard Shortcuts + + + + + Export Shortcuts + + + + + Shortcuts exported successfully + + + + + Failed to open file for writing + + + + + olive::ProgressDialog + + + Cancel + Прекини + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + + + + + &Import... + + + + + &Project Properties... + + + + + Open in New Tab + + + + + Open in New Window + + + + + Reveal in Explorer + + + + + Reveal in Finder + + + + + Reveal in File Manager + + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + + + + + Project + + + + + (none) + (нема) + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + + + + + OpenColorIO Configuration: + + + + + (default) + + + + + Default Input Color Space: + + + + + Browse + + + + + Color Management + + + + + Use Default Location + + + + + Store Alongside Project + + + + + Use Custom Location: + + + + + Disk Cache Settings + + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + + + + + OpenColorIO Config Error + + + + + Failed to set OpenColorIO configuration: %1 + + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + + + + + olive::ProjectSaveTask + + + Saving '%1' + + + + + Failed to write XML data + + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + + + + + Open Project + + + + + Save Project + + + + + Undo + + + + + Redo + + + + + Search media, markers, etc. + + + + + Switch to Tree View + + + + + Switch to List View + + + + + Switch to Icon View + + + + + olive::ProjectViewModel + + + Name + + + + + Duration + + + + + Rate + + + + + Move Items + + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + + + + + Bold + + + + + I + + + + + Italic + + + + + U + + + + + Underline + + + + + S + + + + + Strikethrough + + + + + Font Family + + + + + Font Size + + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + + + + + Histogram + + + + + Scope + + + + + olive::SequenceDialog + + + Name: + + + + + New Sequence + + + + + Editing "%1" + + + + + Error editing Sequence + + + + + Please enter a name for this Sequence. + + + + + olive::SequenceDialogParameterTab + + + Video + Видео + + + + Width: + Ширина: + + + + Height: + Висина: + + + + Frame Rate: + Оквирна стопа: + + + + Pixel Aspect Ratio: + + + + + Interlacing: + + + + + Audio + Аудио + + + + Sample Rate: + + + + + Channels: + + + + + Preview + + + + + Resolution: + + + + + Quality: + + + + + Save Preset + + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + + + + + My Presets + + + + + 4K UHD + + + + + 1080p + 1080p + + + + 720p + 720p + + + + NTSC + + + + + PAL + + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + + + + + olive::SequenceViewerPanel + + + Sequence Viewer + + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + + + + + Generate a solid color. + + + + + Color + + + + + olive::StringSlider + + + (none) + (нема) + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + + + + + Color + + + + + Radius + + + + + Opacity + + + + + Inner + + + + + olive::Task + + + Task + + + + + Unknown error + + + + + olive::TaskDialog + + + Task Failed + + + + + olive::TaskManagerPanel + + + Task Manager + + + + + olive::TaskViewItem + + + Error: %1 + + + + + olive::TextGenerator + + + Sample Text + + + + + + Text + + + + + Generate rich text. + + + + + Font + + + + + Font Size + + + + + Color + + + + + Vertical Align + + + + + Top + + + + + Center + + + + + Bottom + + + + + olive::TimeBasedPanel + + + (none) + (нема) + + + + olive::TimeBasedWidget + + + Set Marker + + + + + Marker name: + + + + + olive::TimeInput + + + Time + + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + + + + + olive::TimelineWidget + + + + Properties + + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + + + + + olive::Toolbar + + + Pointer Tool + + + + + Edit Tool + + + + + Ripple Tool + + + + + Rolling Tool + + + + + Razor Tool + + + + + Slip Tool + + + + + Slide Tool + + + + + Hand Tool + + + + + Zoom Tool + + + + + Transition Tool + + + + + Record Tool + + + + + Add Tool + + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + + + + + Audio %1 + + + + + Subtitle %1 + + + + + Track %1 + + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + + + + + Linear + Линеарно + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + + + + + Perform a trigonometry operation on a value. + + + + + Sine + + + + + Cosine + + + + + Tangent + + + + + Inverse Sine + + + + + Inverse Cosine + + + + + Inverse Tangent + + + + + Hyperbolic Sine + + + + + Hyperbolic Cosine + + + + + Hyperbolic Tangent + + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + 1/%1 + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + + + + + Color Space: + + + + + Default (%1) + + + + + Premultiplied Alpha + + + + + Image Sequence + + + + + Start Index: + + + + + End Index: + + + + + Frame Rate: + Оквирна стопа: + + + + Invalid Configuration + + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + + + + + Interface between a Viewer panel and the node system. + + + + + Texture + + + + + Samples + + + + + Video Tracks + + + + + Audio Tracks + + + + + Subtitle Tracks + + + + + olive::ViewerPanel + + + Viewer + + + + + olive::ViewerWidget + + + Error + + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + + + + + Fit + + + + + %1% + + + + + Full Screen + + + + + Screen %1: %2x%3 + + + + + Deinterlace + + + + + Scopes + + + + + Cache + + + + + Auto-Cache + + + + + Pause Auto-Cache During Playback + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Off + + + + + On + + + + + Custom Aspect + + + + + Show Audio Waveform + + + + + olive::VolumeNode + + + + Volume + + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/tr_TR.ts b/app/ts/tr_TR.ts new file mode 100644 index 000000000..6d2be9f9d --- /dev/null +++ b/app/ts/tr_TR.ts @@ -0,0 +1,4767 @@ + + + + + AudioParams + + + %1 Hz + + + + + Mono + + + + + Stereo + Stereo + + + + 2.1 + 144p {2.1?} + + + + 5.1 + 144p {5.1?} + + + + 7.1 + 144p {7.1?} + + + + Unknown (0x%1) + + + + + Config + + + Error loading settings + + + + + Failed to load application settings. This session will use defaults. + +%1 + + + + + Error saving settings + + + + + Failed to save application settings. The application may lack write permissions to this location. + + + + + Footage + + + %1 FPS + + + + + %1 Hz + + + + + Filename: %1 + + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + + + + + Automatically Detect Parameters From Footage + + + + + Set Parameters Manually + + + + + MoveItemCommand + + + Move Item + + + + + NodeCopyPasteWidget + + + Error pasting nodes + + + + + Failed to paste nodes: %1 + + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + + + + + Set preset name: + + + + + Invalid preset name + + + + + You must enter a preset name + + + + + Preset exists + + + + + A preset with this name already exists. Would you like to replace it? + + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + + + + + %1: Unknown + + + + + %1: Image - %2x%3 + + + + + %1: Video - %2x%3 + + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + + + + + Bars + Test Çubuğu + + + + Solid + + + + + Title + Başlık + + + + Tone + Ton + + + + Unknown + + + + + VideoParams + + + 8-bit + + + + + 16-bit Integer + + + + + Half-Float (16-bit) + + + + + Full-Float (32-bit) + + + + + Unknown (0x%1) + + + + + %1 FPS + + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + + + + + Show application version + + + + + Start in full-screen mode + + + + + Export only (No GUI) + + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + + + + + olive::AboutDialog + + + About %1 + + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive doğrusal olmayan bir video editörüdür. Bu yazılım GNU GPL tarafından ücretsiz ve korunmaktadır. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + Olive Takımı, kullanıcılara Olive kaynak kodunun web sitesinden indirilmek üzere kullanılabilir olduğunu bildirmek zorundadır. + + + + olive::ActionSearch + + + Search for action... + İşlem Ara... + + + + olive::AudioInput + + + Audio Input + + + + + Audio + Ses + + + + Import an audio footage stream. + + + + + olive::AudioMonitorPanel + + + Audio Monitor + + + + + olive::Block + + + Length + Süre + + + + Media In + + + + + Enabled + + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + + + + + Blurs an image. + + + + + Input + + + + + Method + + + + + Box + + + + + Gaussian + + + + + Radius + + + + + Horizontal + + + + + Vertical + + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + + + + + A time-based node that represents a media source. + + + + + Buffer + + + + + olive::ColorDialog + + + Select Color + + + + + olive::ColorSpaceChooser + + + Color Management + + + + + Input: + + + + + Color Space: + + + + + Display: + + + + + View: + + + + + Look: + + + + + (None) + + + + + olive::ColorValuesTab + + + Red + + + + + Green + + + + + Blue + + + + + olive::ColorValuesWidget + + + Preview + + + + + Input + + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + Yeni Dosya + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + Projeyi Kaydet + + + + + Error + Hata + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + + + + + Load Project + + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + + + + + Save All + + + + + Don't Save + + + + + Don't Save All + + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + Proje Aç + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + + + + + Send Error Report + + + + + Don't Send + + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CrossDissolveTransition + + + Cross Dissolve + + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + Doğrusal + + + + Bezier + Bezier + + + + Hold + Oldu + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + + + + + Disk Cache Settings + + + + + Maximum Disk Cache: + + + + + %1 GB + + + + + + + Clear Disk Cache + + + + + Automatically clear disk cache on close + + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + + + + + olive::DiskManager + + + + Disk Cache Error + + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + Gelişmiş + + + + Pixel + + + + + Pixel Format: + Piksel Biçimi: + + + + Performance + + + + + Threads: + İş Parçacığı: + + + + olive::ExportAudioTab + + + Codec: + Kodek: + + + + Sample Rate: + Aynı oran: + + + + Channel Layout: + + + + + Format: + Biçim: + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + + + + + olive::ExportDialog + + + Filename: + Dosyaadı: + + + + Browse for exported file filename + + + + + Preset: + Önayar: + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + Menzil: + + + + Entire Sequence + Tam Sıra + + + + In to Out + Girişten Çıkışa + + + + Format: + Biçim: + + + + Export Video + + + + + Export Audio + + + + + Video + Video + + + + Audio + Ses + + + + + Export + İhraç + + + + Preview + + + + + Invalid parameters + + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + + + + + olive::ExportTask + + + Exporting "%1" + + + + + Failed to create encoder + + + + + Failed to open file + + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + Genişlik: + + + + Height: + Yükseklik: + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + + + + + Fit + Sığdır + + + + Stretch + + + + + Crop + + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + Piksel en boy oranı: + + + + Interlacing: + + + + + Quality: + + + + + Codec + + + + + Codec: + Kodek: + + + + Advanced + Gelişmiş + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + + + + + Name: + Ad: + + + + Tracks: + İzler: + + + + olive::FootageRelinkDialog + + + Footage + + + + + Filename + + + + + Actions + + + + + Browse + Göz at + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + Tüm Dosyalar + + + + olive::FootageViewerPanel + + + Footage Viewer + + + + + olive::GapBlock + + + Gap + + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + + + + + Maximum Bit Rate (Mbps): + + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + Hedef Dosya Boyutu (MB): + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + + + + + Constant Rate Factor + + + + + Target Bit Rate + + + + + Target File Size + + + + + olive::ImageSection + + + Image Sequence: + + + + + olive::InterlacedComboBox + + + None (Progressive) + + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + + + + + In: + + + + + Out: + + + + + Linear + Doğrusal + + + + Hold + Oldu + + + + Bezier + Bezier + + + + olive::KeyframeViewBase + + + Linear + Doğrusal + + + + Bezier + Bezier + + + + Hold + Oldu + + + + P&roperties + + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + + + + + Save '%1' &As + + + + + Close '%1' + + + + + Close All Except '%1' + + + + + &Save Project + &Projeyi Kaydet + + + + Save Project &As + Projeyi Farklı &Kaydet + + + + Close Project + + + + + Close All Except Current Project + + + + + (None) + + + + + &File + &Dosya + + + + &New + &Yeni + + + + &Open Project + &Proje Aç + + + + Open &Recent + + + + + &Clear Recent List + + + + + Sa&ve All Projects + + + + + &Import... + &Dışa aktar... + + + + &Export + + + + + &Media... + + + + + &Project Properties... + + + + + Close All Projects + + + + + E&xit + Çı&kış + + + + &Edit + &Düzenle + + + + Insert + + + + + Overwrite + + + + + Select &All + Tümünü &Seç + + + + Deselect All + Hiçbirini seçme + + + + Ripple to In Point + Giriş noktasına taşı + + + + Ripple to Out Point + Çıkış noktasına taşı + + + + Edit to In Point + Giriş noktasına Düzenle + + + + Edit to Out Point + Çıkış Noktasına göre Düzenle + + + + Delete In/Out Point + Giriş/Çıkış Noktasını Silin + + + + Ripple Delete In/Out Point + Dalgalanma Silme Giriş/Çıkış Noktası + + + + Set/Edit Marker + İşaretleyiciyi Kur/Düzenle + + + + &View + &Görünüm + + + + Zoom In + Yakınlaştır + + + + Zoom Out + + + + + Increase Track Height + İz Yüksekliğini Artır + + + + Decrease Track Height + Parça Yüksekliğini Azalt + + + + Toggle Show All + Tümünü Göster'e Geçiş Yap + + + + Full Screen + Tam Ekran Modu + + + + Full Screen Viewer + Tam Ekran Görüntüleyici Modunda + + + + &Playback + Yeniden&Oynat + + + + Go to Start + Başlaş Git + + + + Previous Frame + Önceki Çerçeve + + + + Play/Pause + Oynat/Durdur + + + + Play In to Out + Dışarıda Oynat + + + + Next Frame + Sonraki Çerçeve + + + + Go to End + Sona Git + + + + Go to Previous Cut + Önceki bölüme git + + + + Go to Next Cut + Snraki bölüme git + + + + Go to In Point + Giriş noktasına git + + + + Go to Out Point + Çıkış noktasına git + + + + Shuttle Left + Hız Azaltma + + + + Shuttle Stop + Durma + + + + Shuttle Right + Hızını arttır + + + + Loop + Döngü tekrarlayın + + + + &Sequence + &Sıra + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Maximize Panel + Paneli Büyüt + + + + Lock Panels + Paneli Kilitle + + + + Reset to Default Layout + Panel'i Varsayılan Düzen'e Sıfırla + + + + &Tools + &Araçlar + + + + Pointer Tool + İşaretçi Aracı + + + + Edit Tool + Düzenleme Aracı + + + + Ripple Tool + + + + + Rolling Tool + + + + + Razor Tool + + + + + Slip Tool + + + + + Slide Tool + + + + + Hand Tool + + + + + Zoom Tool + + + + + Transition Tool + Geçiş + + + + Enable Snapping + Yapıştırmayı Etkinleştir + + + + Preferences + Ayarlar + + + + &Help + &Yardım + + + + A&ction Search + Et&kin Arama + + + + Send &Feedback... + + + + + &About... + &Program Hakkında... + + + + olive::MainStatusBar + + + Welcome to %1 %2 + Hoşgeldiniz %1 %2 + + + + Running %1 background tasks + + + + + olive::MainWindow + + + Driver Warning + + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + + + + + No color manager connected + + + + + Display + + + + + View + Gör + + + + Look + + + + + (None) + + + + + OpenColorIO Error + + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + Ekle + + + + Subtract + + + + + Multiply + + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + Pozisyon + + + + Rotation + + + + + Scale + + + + + Uniform Scale + Tek tip ölçek + + + + Anchor Point + Dayanak noktası + + + + olive::MediaInput + + + Footage + + + + + olive::MenuShared + + + &Project + &Proje + + + + &Sequence + &Sıra + + + + &Folder + &Dosya + + + + Cu&t + + + + + Cop&y + K&opya + + + + &Paste + &Yapıştır + + + + Paste Insert + Yapıştır Ekle + + + + Duplicate + + + + + Delete + Sil + + + + Ripple Delete + Dalgacığı Sil + + + + Split + Böl + + + + Set In Point + Giriş Noktasını Ayarla + + + + Set Out Point + Çıkış Noktasını Ayarla + + + + Reset In Point + Giriş noktasını sıfırla + + + + Reset Out Point + Çıkış Noktasını Sıfırla + + + + Clear In/Out Point + Giriş/Çıkış Noktasını Temizle + + + + Add Default Transition + Varsayılan Geçiş Ekle + + + + Link/Unlink + Bağlantı/Bağlantıyı Kes + + + + Enable/Disable + Etkin/Devredışı + + + + Nest + Yuvarla + + + + Frames + Çerçeve + + + + Drop Frame + Başlangıç Çerçevesi + + + + Non-Drop Frame + Alt Düşmeyen Çerçeve + + + + Milliseconds + Milisaniyeler + + + + Seconds + + + + + olive::MergeNode + + + Merge + + + + + Merge two textures together. + + + + + Base + + + + + Blend + + + + + olive::Node + + + Input + + + + + Output + + + + + General + Genel + + + + Math + + + + + Color + Renk + + + + Filter + + + + + Timeline + Montaj Masası + + + + Generator + + + + + Channel + + + + + Transition + + + + + Uncategorized + + + + + olive::NodeInput + + + Input + + + + + olive::NodeOutput + + + Output + + + + + olive::NodePanel + + + Node Editor + + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + Renk + + + + Matrix + + + + + Text + Metin + + + + Font + Yazıtipi + + + + File + + + + + Texture + + + + + Samples + + + + + Footage + + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + + + + + Nothing + + + + + Disconnect + + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + + + + + olive::NodeTableView + + + Type + + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + (bilinmiyor) + + + + olive::NodeTreeView + + + Nodes + + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + + + + + Filter + + + + + Show All + + + + + Show Selected Blocks Only + + + + + Direction + + + + + Top to Bottom + + + + + Bottom to Top + + + + + Left to Right + + + + + Right to Left + + + + + Add + Ekle + + + + olive::PanNode + + + + Pan + Panorama + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + + + + + (none) + + + + + (multiple) + (çoklu) + + + + olive::PathWidget + + + Browse + Göz at + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + Renk + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + Renk + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + Tema + + + + Node Color Scheme + + + + + olive::PreferencesAudioTab + + + Output Device: + Çıkış Cihazı: + + + + Input Device: + Giriş aygıtı: + + + + Sample Rate: + Aynı oran: + + + + Audio Recording: + Ses Kayıt: + + + + Mono + + + + + Stereo + Stereo + + + + Refresh Devices + + + + + Please wait... + + + + + Default + Varsayılan + + + + olive::PreferencesBehaviorTab + + + Behavior + Davranış + + + + General + Genel + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + Ses + + + + Enable audio scrubbing + + + + + Timeline + Montaj Masası + + + + Auto-Seek to Imported Clips + Alınan Kliplere Otomatik Arama + + + + Edit Tool Also Seeks + + + + + Edit Tool Selects Links + + + + + Enable Drag Files to Timeline + + + + + Invert Timeline Scroll Axes + Zaman Çizelgesi Kaydırma Eksenlerini Ters Çevir + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + + + + + Seek to the End of Pastes + + + + + Selecting Also Seeks + + + + + Playback + Yeniden Oynat + + + + Ask For Name When Setting Marker + İşaretleyiciyi Ayarlarken Ad İste + + + + Automatically rewind at the end of a sequence + + + + + Project + Proje + + + + Drop Files on Media to Replace + Medyada Değiştirilecek Dosyaları Bırak + + + + Nodes + + + + + Add Default Effects to New Clips + Yeni Kliplere Varsayılan Efektler Ekleme + + + + Auto-Scale By Default + + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + Ayarlar + + + + General + Genel + + + + Appearance + Görünüm + + + + Behavior + Davranış + + + + Disk + + + + + Audio + Ses + + + + Keyboard + Klavye Kısayolları + + + + olive::PreferencesDiskTab + + + Disk Management + + + + + Disk Cache Location: + + + + + Disk Cache Settings + + + + + Cache Behavior + + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + Dil: + + + + Auto-Scroll Method: + + + + + None + + + + + Page Scrolling + + + + + Smooth Scrolling + + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + İşlem veya kısayol ara + + + + Action + Faaliyet + + + + Shortcut + Klavye Kısayol + + + + Import + Dışa Aktar + + + + Export + İhraç + + + + Reset Selected + Seçileni Sıfırla + + + + Reset All + Tümünü Sıfırla + + + + Confirm Reset All Shortcuts + Tüm Kısayolları Sıfırlamayı Onayla + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + Tüm klavye kısayollarını varsayılan ayarlarına sıfırlamak istediğinizden emin misiniz? + + + + Import Keyboard Shortcuts + Klavye Kısayollarını İçe Aktar + + + + + Error saving shortcuts + Kısayollar kaydedilirken hata oluştu + + + + Failed to open file for reading + Dosya okumak için açılamadı + + + + Export Keyboard Shortcuts + Klavye Kısayollarını Dışa Aktar + + + + Export Shortcuts + Kısayolları Dışa Aktar + + + + Shortcuts exported successfully + Kısayollar başarıyla verildi + + + + Failed to open file for writing + Dosya yazma için açılamadı + + + + olive::ProgressDialog + + + Cancel + İptal + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + &Yeni + + + + &Import... + &Dışa aktar... + + + + &Project Properties... + + + + + Open in New Tab + + + + + Open in New Window + + + + + Reveal in Explorer + Gezgin içinde Göster + + + + Reveal in Finder + Bul içinde Göster + + + + Reveal in File Manager + Dosya Yöneticisinde Göster + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + + + + + Project + Proje + + + + (none) + + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + + + + + OpenColorIO Configuration: + + + + + (default) + + + + + Default Input Color Space: + + + + + Browse + Göz at + + + + Color Management + + + + + Use Default Location + + + + + Store Alongside Project + + + + + Use Custom Location: + + + + + Disk Cache Settings + + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + + + + + OpenColorIO Config Error + + + + + Failed to set OpenColorIO configuration: %1 + + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + + + + + olive::ProjectSaveTask + + + Saving '%1' + + + + + Failed to write XML data + + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + + + + + Open Project + Proje Aç + + + + Save Project + Projeyi Kaydet + + + + Undo + Geri Al + + + + Redo + Yinele + + + + Search media, markers, etc. + Medya, işaretleyiciler vb. + + + + Switch to Tree View + + + + + Switch to List View + + + + + Switch to Icon View + + + + + olive::ProjectViewModel + + + Name + Ad + + + + Duration + Süre + + + + Rate + Oran + + + + Move Items + + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + + + + + Bold + Kalın + + + + I + + + + + Italic + + + + + U + + + + + Underline + + + + + S + + + + + Strikethrough + + + + + Font Family + + + + + Font Size + + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + + + + + Histogram + + + + + Scope + + + + + olive::SequenceDialog + + + Name: + Ad: + + + + New Sequence + Yeni Sıra + + + + Editing "%1" + Kurgu "%1" + + + + Error editing Sequence + + + + + Please enter a name for this Sequence. + + + + + olive::SequenceDialogParameterTab + + + Video + Video + + + + Width: + Genişlik: + + + + Height: + Yükseklik: + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + Piksel en boy oranı: + + + + Interlacing: + + + + + Audio + Ses + + + + Sample Rate: + Aynı oran: + + + + Channels: + + + + + Preview + + + + + Resolution: + + + + + Quality: + + + + + Save Preset + + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + + + + + My Presets + + + + + 4K UHD + + + + + 1080p + 1080p + + + + 720p + 720p + + + + NTSC + + + + + PAL + + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + + + + + olive::SequenceViewerPanel + + + Sequence Viewer + Sıra Görüntüleyici + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + + + + + Generate a solid color. + + + + + Color + Renk + + + + olive::StringSlider + + + (none) + + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + + + + + Color + Renk + + + + Radius + + + + + Opacity + Opaklık + + + + Inner + + + + + olive::Task + + + Task + + + + + Unknown error + + + + + olive::TaskDialog + + + Task Failed + + + + + olive::TaskManagerPanel + + + Task Manager + + + + + olive::TaskViewItem + + + Error: %1 + + + + + olive::TextGenerator + + + Sample Text + Örnek yazı + + + + + Text + Metin + + + + Generate rich text. + + + + + Font + Yazıtipi + + + + Font Size + + + + + Color + Renk + + + + Vertical Align + + + + + Top + + + + + Center + Merkez + + + + Bottom + Alt + + + + olive::TimeBasedPanel + + + (none) + + + + + olive::TimeBasedWidget + + + Set Marker + İşaretçiyi ayarla + + + + Marker name: + + + + + olive::TimeInput + + + Time + + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + Montaj Masası + + + + olive::TimelineWidget + + + + Properties + Sahne Özellikleri + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + + + + + olive::Toolbar + + + Pointer Tool + İşaretçi Aracı + + + + Edit Tool + Düzenleme Aracı + + + + Ripple Tool + + + + + Rolling Tool + + + + + Razor Tool + + + + + Slip Tool + + + + + Slide Tool + + + + + Hand Tool + + + + + Zoom Tool + + + + + Transition Tool + Geçiş + + + + Record Tool + + + + + Add Tool + + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + + + + + Audio %1 + + + + + Subtitle %1 + + + + + Track %1 + + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + + + + + Linear + Doğrusal + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + + + + + Perform a trigonometry operation on a value. + + + + + Sine + Sinüs + + + + Cosine + + + + + Tangent + + + + + Inverse Sine + + + + + Inverse Cosine + + + + + Inverse Tangent + + + + + Hyperbolic Sine + + + + + Hyperbolic Cosine + + + + + Hyperbolic Tangent + + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + 144p {1/%1?} + + + + olive::VideoInput + + + Video Input + + + + + Video + Video + + + + Import a video footage stream. + + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + + + + + Color Space: + + + + + Default (%1) + + + + + Premultiplied Alpha + + + + + Image Sequence + + + + + Start Index: + + + + + End Index: + + + + + Frame Rate: + + + + + Invalid Configuration + + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + + + + + Interface between a Viewer panel and the node system. + + + + + Texture + + + + + Samples + + + + + Video Tracks + + + + + Audio Tracks + + + + + Subtitle Tracks + + + + + olive::ViewerPanel + + + Viewer + + + + + olive::ViewerWidget + + + Error + Hata + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + Yakınlaştır + + + + Fit + Sığdır + + + + %1% + + + + + Full Screen + Tam Ekran Modu + + + + Screen %1: %2x%3 + Ekran %1: %2x%3 + + + + Deinterlace + + + + + Scopes + + + + + Cache + + + + + Auto-Cache + + + + + Pause Auto-Cache During Playback + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Off + Kapalı + + + + On + + + + + Custom Aspect + + + + + Show Audio Waveform + + + + + olive::VolumeNode + + + + Volume + Ses Seviyesi + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/translations.qrc.in b/app/ts/translations.qrc.in new file mode 100644 index 000000000..c86dc346d --- /dev/null +++ b/app/ts/translations.qrc.in @@ -0,0 +1,5 @@ + + + @QRC_BODY@ + + diff --git a/app/ts/uk_UK.ts b/app/ts/uk_UK.ts new file mode 100644 index 000000000..4123719ad --- /dev/null +++ b/app/ts/uk_UK.ts @@ -0,0 +1,4767 @@ + + + + + AudioParams + + + %1 Hz + + + + + Mono + Моно + + + + Stereo + Стерео + + + + 2.1 + 144p {2.1?} + + + + 5.1 + 144p {5.1?} + + + + 7.1 + 144p {7.1?} + + + + Unknown (0x%1) + + + + + Config + + + Error loading settings + + + + + Failed to load application settings. This session will use defaults. + +%1 + + + + + Error saving settings + + + + + Failed to save application settings. The application may lack write permissions to this location. + + + + + Footage + + + %1 FPS + + + + + %1 Hz + + + + + Filename: %1 + + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + + + + + Automatically Detect Parameters From Footage + + + + + Set Parameters Manually + + + + + MoveItemCommand + + + Move Item + + + + + NodeCopyPasteWidget + + + Error pasting nodes + + + + + Failed to paste nodes: %1 + + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + + + + + Set preset name: + + + + + Invalid preset name + + + + + You must enter a preset name + + + + + Preset exists + + + + + A preset with this name already exists. Would you like to replace it? + + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + + + + + %1: Unknown + + + + + %1: Image - %2x%3 + + + + + %1: Video - %2x%3 + + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + + + + + Bars + Тестова таблиця + + + + Solid + + + + + Title + Титри + + + + Tone + Звуковой сигнал + + + + Unknown + + + + + VideoParams + + + 8-bit + + + + + 16-bit Integer + + + + + Half-Float (16-bit) + + + + + Full-Float (32-bit) + + + + + Unknown (0x%1) + + + + + %1 FPS + + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + + + + + Show application version + + + + + Start in full-screen mode + + + + + Export only (No GUI) + + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + + + + + olive::AboutDialog + + + About %1 + + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive є нелінійним редактором відео. Це програмне забезпечення є вільним і захищено ліцензією GNU GPL. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + Olive Team інформує користувачів про те що джерельний код Olive є доступним для завантаження на сайті проекту. + + + + olive::ActionSearch + + + Search for action... + Знайти дію... + + + + olive::AudioInput + + + Audio Input + + + + + Audio + Аудіо + + + + Import an audio footage stream. + + + + + olive::AudioMonitorPanel + + + Audio Monitor + + + + + olive::Block + + + Length + Тривалість + + + + Media In + + + + + Enabled + + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + + + + + Blurs an image. + + + + + Input + + + + + Method + + + + + Box + + + + + Gaussian + + + + + Radius + + + + + Horizontal + + + + + Vertical + + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + + + + + A time-based node that represents a media source. + + + + + Buffer + + + + + olive::ColorDialog + + + Select Color + + + + + olive::ColorSpaceChooser + + + Color Management + + + + + Input: + + + + + Color Space: + + + + + Display: + + + + + View: + + + + + Look: + + + + + (None) + + + + + olive::ColorValuesTab + + + Red + + + + + Green + + + + + Blue + + + + + olive::ColorValuesWidget + + + Preview + + + + + Input + + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + Нова тека + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + Зберегти проект + + + + + Error + Помилка + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + + + + + Load Project + + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + + + + + Save All + + + + + Don't Save + + + + + Don't Save All + + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + Відкрити проект + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + + + + + Send Error Report + + + + + Don't Send + + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CrossDissolveTransition + + + Cross Dissolve + + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + Лінійний + + + + Bezier + Безьє + + + + Hold + Стала + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + + + + + Disk Cache Settings + + + + + Maximum Disk Cache: + + + + + %1 GB + + + + + + + Clear Disk Cache + + + + + Automatically clear disk cache on close + + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + + + + + olive::DiskManager + + + + Disk Cache Error + + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + Додатково + + + + Pixel + + + + + Pixel Format: + Формат пікселів: + + + + Performance + + + + + Threads: + Потоки: + + + + olive::ExportAudioTab + + + Codec: + Кодек: + + + + Sample Rate: + Частота дискретизації: + + + + Channel Layout: + + + + + Format: + Формат: + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + + + + + olive::ExportDialog + + + Filename: + Ім'я файла: + + + + Browse for exported file filename + + + + + Preset: + Профіль: + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + Діапазон: + + + + Entire Sequence + Уся послідовність + + + + In to Out + Від входу до виходу + + + + Format: + Формат: + + + + Export Video + + + + + Export Audio + + + + + Video + Відео + + + + Audio + Аудіо + + + + + Export + Експортувати + + + + Preview + + + + + Invalid parameters + + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + + + + + olive::ExportTask + + + Exporting "%1" + + + + + Failed to create encoder + + + + + Failed to open file + + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + Ширина: + + + + Height: + Висота: + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + + + + + Fit + Підігнати + + + + Stretch + + + + + Crop + + + + + Frame Rate: + Частота кадрів: + + + + Pixel Aspect Ratio: + Пропорції сторін пікселів: + + + + Interlacing: + Черезрядковість: + + + + Quality: + + + + + Codec + + + + + Codec: + Кодек: + + + + Advanced + Додатково + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + + + + + Name: + Назва: + + + + Tracks: + Доріжок: + + + + olive::FootageRelinkDialog + + + Footage + + + + + Filename + + + + + Actions + + + + + Browse + Обрати + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + Усі файли + + + + olive::FootageViewerPanel + + + Footage Viewer + + + + + olive::GapBlock + + + Gap + + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + + + + + Maximum Bit Rate (Mbps): + + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + Кінцевий розмір файла (Мб): + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + + + + + Constant Rate Factor + + + + + Target Bit Rate + + + + + Target File Size + + + + + olive::ImageSection + + + Image Sequence: + + + + + olive::InterlacedComboBox + + + None (Progressive) + Ні (прогресивно) + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + + + + + In: + + + + + Out: + + + + + Linear + Лінійний + + + + Hold + Стала + + + + Bezier + Безьє + + + + olive::KeyframeViewBase + + + Linear + Лінійний + + + + Bezier + Безьє + + + + Hold + Стала + + + + P&roperties + + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + + + + + Save '%1' &As + + + + + Close '%1' + + + + + Close All Except '%1' + + + + + &Save Project + &Зберегти проект + + + + Save Project &As + Зберегти проект &як + + + + Close Project + + + + + Close All Except Current Project + + + + + (None) + + + + + &File + &Файл + + + + &New + &Новий + + + + &Open Project + &Відкрити проект + + + + Open &Recent + + + + + &Clear Recent List + + + + + Sa&ve All Projects + + + + + &Import... + &Імпортувати... + + + + &Export + + + + + &Media... + + + + + &Project Properties... + + + + + Close All Projects + + + + + E&xit + Ви&хід + + + + &Edit + + + + + Insert + + + + + Overwrite + + + + + Select &All + Виділити &усе + + + + Deselect All + Скасувати виділення + + + + Ripple to In Point + Зсунути до точки входу + + + + Ripple to Out Point + Зсунути до точки виходу + + + + Edit to In Point + Редагування до точки входу + + + + Edit to Out Point + Редагування до точки виходу + + + + Delete In/Out Point + Видалити точку входу/виходу + + + + Ripple Delete In/Out Point + Видалити зі зміщенням точку входу/виходу + + + + Set/Edit Marker + Встановити/Редагувати маркер + + + + &View + &Вигляд + + + + Zoom In + Наблизити + + + + Zoom Out + Віддалити + + + + Increase Track Height + Збільшити висоту доріжки + + + + Decrease Track Height + Зменшити висоту доріжки + + + + Toggle Show All + Показувати увесь проект + + + + Full Screen + Повноекранний режим + + + + Full Screen Viewer + Перегляд в повноекранному режимі + + + + &Playback + Від&творення + + + + Go to Start + На початок + + + + Previous Frame + Попередній кадр + + + + Play/Pause + Відтворення/Пауза + + + + Play In to Out + Відтворити від входу до виходу + + + + Next Frame + Наступний кадр + + + + Go to End + У кінець + + + + Go to Previous Cut + До попереднього розрізу + + + + Go to Next Cut + До наступного розрізу + + + + Go to In Point + До точки входу + + + + Go to Out Point + До точки виходу + + + + Shuttle Left + Зменшити швидкість + + + + Shuttle Stop + Пауза + + + + Shuttle Right + Збільшити швидкість + + + + Loop + Повторення петлі + + + + &Sequence + П&ослідовність + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Maximize Panel + Розгорнути панель + + + + Lock Panels + Зафіксувати панель + + + + Reset to Default Layout + Повернути початкове розташування панелей + + + + &Tools + &Інструменти + + + + Pointer Tool + Вказівник + + + + Edit Tool + Виділення + + + + Ripple Tool + + + + + Rolling Tool + + + + + Razor Tool + + + + + Slip Tool + Прокручування зі зміщенням + + + + Slide Tool + Прокручування + + + + Hand Tool + Навігація + + + + Zoom Tool + + + + + Transition Tool + Перехід + + + + Enable Snapping + Увімкнути прилипання + + + + Preferences + Параметри + + + + &Help + &Довідка + + + + A&ction Search + По&шук дії + + + + Send &Feedback... + + + + + &About... + &Про програму... + + + + olive::MainStatusBar + + + Welcome to %1 %2 + Вітаємо в %1 %2 + + + + Running %1 background tasks + + + + + olive::MainWindow + + + Driver Warning + + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + + + + + No color manager connected + + + + + Display + + + + + View + Вигляд + + + + Look + + + + + (None) + + + + + OpenColorIO Error + + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + Додати + + + + Subtract + + + + + Multiply + + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + Позиція + + + + Rotation + Обертання + + + + Scale + Масштаб + + + + Uniform Scale + Пропорційний масштаб + + + + Anchor Point + Якірна точка + + + + olive::MediaInput + + + Footage + + + + + olive::MenuShared + + + &Project + &Проект + + + + &Sequence + П&ослідовність + + + + &Folder + Т&ека + + + + Cu&t + Ви&різати + + + + Cop&y + С&копіювати + + + + &Paste + В&ставити + + + + Paste Insert + Вставити з заміною + + + + Duplicate + + + + + Delete + Видалити + + + + Ripple Delete + Видалити зі зміщенням + + + + Split + Розділити + + + + Set In Point + Встановити точку входа + + + + Set Out Point + Встановити точку вихода + + + + Reset In Point + Скинути точку входа + + + + Reset Out Point + Скинути точку вихода + + + + Clear In/Out Point + Очистити точку входа/вихода + + + + Add Default Transition + Додати типовий перехід + + + + Link/Unlink + Зв'язати/Прибрати зв'язок + + + + Enable/Disable + Увімкнути/Вимкнути + + + + Nest + Вкласти + + + + Frames + Кадри + + + + Drop Frame + З пропусканням кадрів + + + + Non-Drop Frame + Без пропускання кадрів + + + + Milliseconds + Мілісекунди + + + + Seconds + + + + + olive::MergeNode + + + Merge + + + + + Merge two textures together. + + + + + Base + + + + + Blend + + + + + olive::Node + + + Input + + + + + Output + + + + + General + Загальні + + + + Math + + + + + Color + Колір + + + + Filter + + + + + Timeline + Монтажний стіл + + + + Generator + + + + + Channel + + + + + Transition + + + + + Uncategorized + + + + + olive::NodeInput + + + Input + + + + + olive::NodeOutput + + + Output + + + + + olive::NodePanel + + + Node Editor + + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + Колір + + + + Matrix + + + + + Text + Текст + + + + Font + Шрифт + + + + File + + + + + Texture + + + + + Samples + + + + + Footage + + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + + + + + Nothing + + + + + Disconnect + + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + + + + + olive::NodeTableView + + + Type + Тип + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + (невідомо) + + + + olive::NodeTreeView + + + Nodes + + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + + + + + Filter + + + + + Show All + + + + + Show Selected Blocks Only + + + + + Direction + + + + + Top to Bottom + + + + + Bottom to Top + + + + + Left to Right + + + + + Right to Left + + + + + Add + Додати + + + + olive::PanNode + + + + Pan + Панорама + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + + + + + (none) + (пусто) + + + + (multiple) + (множинний) + + + + olive::PathWidget + + + Browse + Обрати + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + Колір + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + Колір + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + Тема + + + + Node Color Scheme + + + + + olive::PreferencesAudioTab + + + Output Device: + Пристрій виводу: + + + + Input Device: + Пристрій вводу: + + + + Sample Rate: + Частота дискретизації: + + + + Audio Recording: + Запис звука: + + + + Mono + Моно + + + + Stereo + Стерео + + + + Refresh Devices + + + + + Please wait... + + + + + Default + Типово + + + + olive::PreferencesBehaviorTab + + + Behavior + Поведінка + + + + General + Загальні + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + Аудіо + + + + Enable audio scrubbing + + + + + Timeline + Монтажний стіл + + + + Auto-Seek to Imported Clips + Автопрокручувати до імпортованих кліпів + + + + Edit Tool Also Seeks + Виділення з прокручуванням + + + + Edit Tool Selects Links + Виділення обирає зв'язки + + + + Enable Drag Files to Timeline + Увімкнути перетягування файлів на монтажний стіл + + + + Invert Timeline Scroll Axes + Інвертувати напрямки прокручування монтажного столу + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + Прокручування з виділенням + + + + Seek to the End of Pastes + Прокручування до кінця вставок + + + + Selecting Also Seeks + Виділення з прокручуванням + + + + Playback + Відтворення + + + + Ask For Name When Setting Marker + Запитувати назву маркера при додаванні + + + + Automatically rewind at the end of a sequence + + + + + Project + Проект + + + + Drop Files on Media to Replace + Перетягування файлів на медіа для заміни + + + + Nodes + + + + + Add Default Effects to New Clips + Додавати типові ефекти для нових кліпів + + + + Auto-Scale By Default + Автомасштабування за умовчанням + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + Параметри + + + + General + Загальні + + + + Appearance + Вигляд + + + + Behavior + Поведінка + + + + Disk + + + + + Audio + Аудіо + + + + Keyboard + Комбінації клавіш + + + + olive::PreferencesDiskTab + + + Disk Management + + + + + Disk Cache Location: + + + + + Disk Cache Settings + + + + + Cache Behavior + + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + Мова: + + + + Auto-Scroll Method: + + + + + None + + + + + Page Scrolling + + + + + Smooth Scrolling + + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + Знайти дію або комбінацію клавіш + + + + Action + Дія + + + + Shortcut + Комбінація клавіш + + + + Import + Імпортувати + + + + Export + Експортувати + + + + Reset Selected + Скинути виділення + + + + Reset All + Скинути все + + + + Confirm Reset All Shortcuts + Підтвердіть скидання всіх комбінацій клавіш + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + Ви дійсно хочете скинути всі комбінації клавіш до типових значень? + + + + Import Keyboard Shortcuts + Імпортувати комбінації клавіш + + + + + Error saving shortcuts + Помилка при збереженні комбінацій клавіш + + + + Failed to open file for reading + Не вдалося відкрити файл для читання + + + + Export Keyboard Shortcuts + Експортувати комбінації клавіш + + + + Export Shortcuts + Експортувати комбінації клавіш + + + + Shortcuts exported successfully + Комбінації клавіш експортовано + + + + Failed to open file for writing + Не вдалося відкрити файл для запису + + + + olive::ProgressDialog + + + Cancel + + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + &Новий + + + + &Import... + &Імпортувати... + + + + &Project Properties... + + + + + Open in New Tab + + + + + Open in New Window + + + + + Reveal in Explorer + Відкрити у Explorer + + + + Reveal in Finder + Відкрити у Finder + + + + Reveal in File Manager + Відкрити у менеджері файлів + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + + + + + Project + Проект + + + + (none) + (пусто) + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + + + + + OpenColorIO Configuration: + + + + + (default) + + + + + Default Input Color Space: + + + + + Browse + Обрати + + + + Color Management + + + + + Use Default Location + + + + + Store Alongside Project + + + + + Use Custom Location: + + + + + Disk Cache Settings + + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + + + + + OpenColorIO Config Error + + + + + Failed to set OpenColorIO configuration: %1 + + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + + + + + olive::ProjectSaveTask + + + Saving '%1' + + + + + Failed to write XML data + + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + + + + + Open Project + Відкрити проект + + + + Save Project + Зберегти проект + + + + Undo + Відмінити + + + + Redo + Повернути + + + + Search media, markers, etc. + Шукати файли, маркери, і т.п. + + + + Switch to Tree View + + + + + Switch to List View + + + + + Switch to Icon View + + + + + olive::ProjectViewModel + + + Name + Назва + + + + Duration + Тривалість + + + + Rate + Частота + + + + Move Items + + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + + + + + Bold + Bold + + + + I + + + + + Italic + + + + + U + + + + + Underline + + + + + S + + + + + Strikethrough + + + + + Font Family + + + + + Font Size + + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + + + + + Histogram + + + + + Scope + + + + + olive::SequenceDialog + + + Name: + Назва: + + + + New Sequence + Нова послідовність + + + + Editing "%1" + Редагування "%1" + + + + Error editing Sequence + + + + + Please enter a name for this Sequence. + + + + + olive::SequenceDialogParameterTab + + + Video + Відео + + + + Width: + Ширина: + + + + Height: + Висота: + + + + Frame Rate: + Частота кадрів: + + + + Pixel Aspect Ratio: + Пропорції сторін пікселів: + + + + Interlacing: + Черезрядковість: + + + + Audio + Аудіо + + + + Sample Rate: + Частота дискретизації: + + + + Channels: + + + + + Preview + + + + + Resolution: + + + + + Quality: + + + + + Save Preset + + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + + + + + My Presets + + + + + 4K UHD + + + + + 1080p + 1080p + + + + 720p + 720p + + + + NTSC + + + + + PAL + + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + + + + + olive::SequenceViewerPanel + + + Sequence Viewer + Переглядач послідовності + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + + + + + Generate a solid color. + + + + + Color + Колір + + + + olive::StringSlider + + + (none) + (пусто) + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + + + + + Color + Колір + + + + Radius + + + + + Opacity + Непрозорість + + + + Inner + + + + + olive::Task + + + Task + + + + + Unknown error + + + + + olive::TaskDialog + + + Task Failed + + + + + olive::TaskManagerPanel + + + Task Manager + + + + + olive::TaskViewItem + + + Error: %1 + + + + + olive::TextGenerator + + + Sample Text + Зразок тексту + + + + + Text + Текст + + + + Generate rich text. + + + + + Font + Шрифт + + + + Font Size + + + + + Color + Колір + + + + Vertical Align + + + + + Top + Вгорі + + + + Center + По центру + + + + Bottom + Внизу + + + + olive::TimeBasedPanel + + + (none) + (пусто) + + + + olive::TimeBasedWidget + + + Set Marker + Встановити маркер + + + + Marker name: + + + + + olive::TimeInput + + + Time + + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + Монтажний стіл + + + + olive::TimelineWidget + + + + Properties + Властивості + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + + + + + olive::Toolbar + + + Pointer Tool + Вказівник + + + + Edit Tool + Виділення + + + + Ripple Tool + + + + + Rolling Tool + + + + + Razor Tool + + + + + Slip Tool + Прокручування зі зміщенням + + + + Slide Tool + Прокручування + + + + Hand Tool + Навігація + + + + Zoom Tool + + + + + Transition Tool + Перехід + + + + Record Tool + + + + + Add Tool + + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + + + + + Audio %1 + + + + + Subtitle %1 + + + + + Track %1 + + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + + + + + Linear + Лінійний + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + + + + + Perform a trigonometry operation on a value. + + + + + Sine + Синусоїда + + + + Cosine + + + + + Tangent + + + + + Inverse Sine + + + + + Inverse Cosine + + + + + Inverse Tangent + + + + + Hyperbolic Sine + + + + + Hyperbolic Cosine + + + + + Hyperbolic Tangent + + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + 144p {1/%1?} + + + + olive::VideoInput + + + Video Input + + + + + Video + Відео + + + + Import a video footage stream. + + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + Черезрядковість: + + + + Color Space: + + + + + Default (%1) + + + + + Premultiplied Alpha + + + + + Image Sequence + + + + + Start Index: + + + + + End Index: + + + + + Frame Rate: + Частота кадрів: + + + + Invalid Configuration + + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + + + + + Interface between a Viewer panel and the node system. + + + + + Texture + + + + + Samples + + + + + Video Tracks + + + + + Audio Tracks + + + + + Subtitle Tracks + + + + + olive::ViewerPanel + + + Viewer + + + + + olive::ViewerWidget + + + Error + Помилка + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + Масштаб + + + + Fit + Підігнати + + + + %1% + + + + + Full Screen + Повноекранний режим + + + + Screen %1: %2x%3 + Екран %1: %2x%3 + + + + Deinterlace + + + + + Scopes + + + + + Cache + + + + + Auto-Cache + + + + + Pause Auto-Cache During Playback + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Off + Вимкнено + + + + On + + + + + Custom Aspect + + + + + Show Audio Waveform + + + + + olive::VolumeNode + + + + Volume + Гучність + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/zh_CN.ts b/app/ts/zh_CN.ts new file mode 100755 index 000000000..8c7aa3d7a --- /dev/null +++ b/app/ts/zh_CN.ts @@ -0,0 +1,4776 @@ + + + + + AudioParams + + + %1 Hz + + + + + Mono + 单声道 + + + + Stereo + 立体声 + + + + 2.1 + 144p {2.1?} + + + + 5.1 + 144p {5.1?} + + + + 7.1 + 144p {7.1?} + + + + Unknown (0x%1) + 未知 (0x%1) + + + + Config + + + Error loading settings + 加载设置时出错 + + + + Failed to load application settings. This session will use defaults. + +%1 + 无法加载应用程序设置,此会话将使用默认设置。 + +%1 + + + + Error saving settings + 保存设置时出错 + + + + Failed to save application settings. The application may lack write permissions to this location. + 无法保存应用程序设置。应用程序可能没有对此位置的写入权限。 + + + + Footage + + + %1 FPS + + + + + %1 Hz + + + + + Filename: %1 + 文件名:%1 + + + + This footage is not valid for use + 此素材不能用 + + + + ImportTool + + + Don't ask me again + 不再询问 + + + + No Active Sequence + 没有活动序列 + + + + No sequence is currently open. Would you like to create one? + 没有打开的序列。您要创建一个序列吗? + + + + Automatically Detect Parameters From Footage + 自动检测素材参数 + + + + Set Parameters Manually + 手动设置参数 + + + + MoveItemCommand + + + Move Item + 移动项 + + + + NodeCopyPasteWidget + + + Error pasting nodes + 粘贴节点时出错 + + + + Failed to paste nodes: %1 + 无法粘贴节点:%1 + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + 保存预设 + + + + Set preset name: + 设置预设名称: + + + + Invalid preset name + 无效的预设名称 + + + + You must enter a preset name + 您必须输入预设名称 + + + + Preset exists + 预设存在 + + + + A preset with this name already exists. Would you like to replace it? + 存在具有此名称的预设。您要替换它吗? + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + 输入自定义比率 (例如“4:3”、“16/9”,等): + + + + Invalid custom ratio + 无效的自定义比率 + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + 重命名项 + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + %1:音频 - %2 通道,%3Hz + + + + %1: Unknown + %1:未知 + + + + %1: Image - %2x%3 + %1:图像 - %2x%3 + + + + %1: Video - %2x%3 + %1:视频 - %2x%3 + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + 空白 + + + + Bars + 彩条 + + + + + Solid + 单色 + + + + Title + 标题 + + + + Tone + 音调 + + + + + Unknown + 未知 + + + + VideoParams + + + 8-bit + + + + + 16-bit Integer + + + + + Half-Float (16-bit) + + + + + Full-Float (32-bit) + + + + + Unknown (0x%1) + 未知 (0x%1) + + + + %1 FPS + + + + + Square Pixels (%1) + 正方形像素 (%1) + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + 显示此帮助文本 + + + + Show application version + 显示应用程序版本 + + + + Start in full-screen mode + 以全屏模式启动 + + + + Export only (No GUI) + 仅导出 (无 GUI) + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + 在启动时打开的项目 + + + + olive::AboutDialog + + + About %1 + 关于 %1 + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive 是免费的非线性视频编辑器。此应用程序基于 GNU 通用公共许可证(GNU GPL)条款发布。 + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + Olive 团队有义务告知用户可以从官网下载 Olive 的源码。翻译者已尝试用通俗易明的方式进行翻译,希望大家使用愉快。请支持自由开源软件,谢谢。 + + + + olive::ActionSearch + + + Search for action... + 操作搜索... + + + + olive::AudioInput + + + Audio Input + 音频输入 + + + + Audio + 音频 + + + + Import an audio footage stream. + + + + + olive::AudioMonitorPanel + + + Audio Monitor + 音频监视器 + + + + olive::Block + + + Length + 长度 + + + + Media In + + + + + Enabled + 已启用 + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + 模糊 + + + + Blurs an image. + 使图像变模糊。 + + + + Input + 输入 + + + + Method + + + + + Box + + + + + Gaussian + 高斯 + + + + Radius + 半径 + + + + Horizontal + 水平 + + + + Vertical + 垂直 + + + + Repeat Edge Pixels + 重复边缘像素 + + + + olive::ClipBlock + + + Clip + 剪辑 + + + + A time-based node that represents a media source. + + + + + Buffer + 缓冲区 + + + + olive::ColorDialog + + + Select Color + 选择颜色 + + + + olive::ColorSpaceChooser + + + Color Management + 色彩管理 + + + + Input: + 输入: + + + + Color Space: + 色彩空间: + + + + Display: + + + + + View: + + + + + Look: + + + + + (None) + (无) + + + + olive::ColorValuesTab + + + Red + 红色 + + + + Green + 绿色 + + + + Blue + 蓝色 + + + + olive::ColorValuesWidget + + + Preview + 预览 + + + + Input + 输入 + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + 导入出错 + + + + Nothing to import + 没有可导出的内容 + + + + Importing... + 正在导入... + + + + Import footage... + 导入素材... + + + + Failed to import footage + 无法导入素材 + + + + Failed to find active Project panel + 找不到活动项目面板 + + + + No Active Project + 没有活动项目 + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + 无法创建新文件夹 + + + + + Failed to find active project + 找不到活动项目 + + + + New Folder + 新建文件夹 + + + + Failed to create new sequence + 无法创建新序列 + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + 指定的项目不存在 + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + 此项目有多个序列。您要导出哪一个? + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + 导出成功 + + + + Export failed: %1 + 导出失败:%1 + + + + Project failed to load: %1 + 项目无法加载:%1 + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + 保存项目 + + + + + Error + 错误 + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + Olive 项目 + + + + OpenTimelineIO + + + + + Save Project As + 另存项目为 + + + + Load Project + 加载项目 + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + 序列 %1 + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + 未保存的更改 + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + 保存 + + + + Save All + 全部保存 + + + + Don't Save + 不保存 + + + + Don't Save All + 全部不保存 + + + + Failed to cache sequence + 无法缓存序列 + + + + No active viewer found with this sequence. + + + + + Open Project + 打开项目 + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + 抱歉,Olive 崩溃了。请发送错误报告帮助我们修复它。 + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + 尽可能详细地描述您正在进行地操作。 如果可以,请您提供能重现此崩溃的步骤。 + + + + Crash Report: + 崩溃报告: + + + + Send Error Report + 发送错误报告 + + + + Don't Send + 不发送 + + + + Waiting for crash report to be generated... + 正在等待崩溃报告生成... + + + + Upload Failed + 上传失败 + + + + Failed to send error report. Please try again later. + 无法发送错误报告。请稍后重试。 + + + + No Crash Summary + 没有崩溃摘要 + + + + Are you sure you want to send an error report with no crash summary? + 确定要发送没有崩溃摘要的错误报告? + + + + olive::CrossDissolveTransition + + + Cross Dissolve + 淡入淡出 + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + 缩放到合适大小 + + + + olive::CurveWidget + + + Linear + 线性 + + + + Bezier + 贝塞尔曲线 + + + + Hold + 保留 + + + + olive::DipToColorTransition + + + Dip To Color + 颜色拾取 + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + 磁盘缓存:%1 + + + + Disk Cache Settings + 磁盘缓存设置 + + + + Maximum Disk Cache: + 最大磁盘缓存: + + + + %1 GB + + + + + + + Clear Disk Cache + 清除磁盘缓存 + + + + Automatically clear disk cache on close + 关闭时自动清除磁盘缓存 + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + 磁盘缓存已清除 + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + 磁盘缓存无法完全清除。您可能需要手动删除缓存文件。 + + + + Disk Cache Partially Cleared + 磁盘缓存已部分清除 + + + + olive::DiskManager + + + + Disk Cache Error + 磁盘缓存错误 + + + + Unable to set custom application disk cache. Using default instead. + 无法设置自定义应用程序磁盘缓存。使用默认设置。 + + + + Disk Cache + 磁盘缓存 + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + 您已选择更改默认的磁盘缓存位置。这将使当前缓存无效。您要继续吗? + + + + Failed to open disk cache at "%1". Try a different folder. + 无法打开位于 "%1" 的磁盘缓存。请尝试其他文件夹。 + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + 经过:%1 + + + + Remaining: %1 + 剩余:%1 + + + + olive::ExportAdvancedVideoDialog + + + Advanced + 高级 + + + + Pixel + 像素 + + + + Pixel Format: + 像素格式: + + + + Performance + 性能 + + + + Threads: + 线程: + + + + olive::ExportAudioTab + + + Codec: + 编解码器: + + + + Sample Rate: + 采样率: + + + + Channel Layout: + 通道布局: + + + + Format: + 格式: + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + 未知 + + + + olive::ExportDialog + + + Filename: + 文件名: + + + + Browse for exported file filename + 浏览已导出的文件名 + + + + Preset: + 预设: + + + + Same As Source - High Quality + 与源相同 - 高质量 + + + + Same As Source - Medium Quality + 与源相同 - 中等质量 + + + + Same As Source - Low Quality + 与源相同 - 低质量 + + + + Range: + 范围: + + + + Entire Sequence + 整个序列 + + + + In to Out + 已选择的时间段 + + + + Format: + 格式: + + + + Export Video + 导出视频 + + + + Export Audio + 导出音频 + + + + Video + 视频 + + + + Audio + 音频 + + + + + Export + 导出 + + + + Preview + 预览 + + + + Invalid parameters + 无效的参数 + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + 预览 + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + 无法创建输出目录 + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + 确认覆盖 + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + 无效的参数 + + + + Width and height must be multiples of 2. + 宽度和高度必须是2的倍数。 + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + 未知 + + + + olive::ExportTask + + + Exporting "%1" + 正在导出 "%1" + + + + Failed to create encoder + + + + + Failed to open file + 无法打开文件 + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + 宽度: + + + + Height: + 高度: + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + 缩放方式: + + + + Fit + 适合 + + + + Stretch + 拉伸 + + + + Crop + 裁剪 + + + + Frame Rate: + 帧率: + + + + Pixel Aspect Ratio: + 像素长宽比: + + + + Interlacing: + 交错: + + + + Quality: + 质量: + + + + Codec + 编解码器 + + + + Codec: + 编解码器: + + + + Advanced + 高级 + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + "%1" 属性 + + + + Name: + 名称: + + + + Tracks: + 轨道: + + + + olive::FootageRelinkDialog + + + Footage + 素材 + + + + Filename + 文件名 + + + + Actions + 操作 + + + + Browse + 浏览 + + + + Relink Footage + 重新链接素材 + + + + Relink "%1" + 重新链接 "%1" + + + + All Files + 全部文件 + + + + olive::FootageViewerPanel + + + Footage Viewer + 素材查看器 + + + + olive::GapBlock + + + Gap + 空隙 + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + 目标码率 (Mbps): + + + + Maximum Bit Rate (Mbps): + 最大码率 (Mbps): + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + 目标文件大小 (MB): + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + 压缩方式: + + + + Constant Rate Factor + + + + + Target Bit Rate + 目标码率 + + + + Target File Size + 目标文件大小 + + + + olive::ImageSection + + + Image Sequence: + 图像序列: + + + + olive::InterlacedComboBox + + + None (Progressive) + 无 (渐进) + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + 关键帧属性 + + + + In: + + + + + Out: + + + + + Linear + 线性 + + + + Hold + 保留 + + + + Bezier + 贝塞尔曲线 + + + + olive::KeyframeViewBase + + + Linear + 线性 + + + + Bezier + 贝塞尔曲线 + + + + Hold + 保留 + + + + P&roperties + 属性(&R) + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + 无法从文件 "%1" 加载 OpenTimelineIO + + + + Unknown OpenTimelineIO root element + 未知的 OpenTimelineIO 根元素 + + + + Failed to load clip + 无法加载剪辑 + + + + olive::MainMenu + + + &Save '%1' + 保存 '%1'(&S) + + + + Save '%1' &As + 另存 '%1' 为(&A) + + + + Close '%1' + 关闭 '%1' + + + + Close All Except '%1' + + + + + &Save Project + 保存项目(&S) + + + + Save Project &As + 另存项目为(&A) + + + + Close Project + 关闭项目 + + + + Close All Except Current Project + + + + + (None) + (无) + + + + &File + 文件(&F) + + + + &New + 新建(&N) + + + + &Open Project + 打开项目(&O) + + + + Open &Recent + 打开最近(&R) + + + + &Clear Recent List + 清除最近列表(&C) + + + + Sa&ve All Projects + 保存所有项目(&V) + + + + &Import... + 导入(&I)... + + + + &Export + 导出(&E) + + + + &Media... + 媒体(&M)... + + + + &Project Properties... + 项目属性(&P)... + + + + Close All Projects + 关闭所有项目 + + + + E&xit + 退出(&X) + + + + &Edit + 编辑(&E) + + + + Insert + 插入 + + + + Overwrite + 覆盖 + + + + Select &All + 全选(&A) + + + + Deselect All + 取消全选 + + + + Ripple to In Point + + + + + Ripple to Out Point + + + + + Edit to In Point + + + + + Edit to Out Point + + + + + Delete In/Out Point + 删除入点/出点 + + + + Ripple Delete In/Out Point + 波纹删除入点/出点 + + + + Set/Edit Marker + 设置/编辑标记 + + + + &View + 视图(&V) + + + + Zoom In + 放大 + + + + Zoom Out + 缩小 + + + + Increase Track Height + 增加轨道高度 + + + + Decrease Track Height + 降低轨道高度 + + + + Toggle Show All + 轨道全部显示 + + + + Full Screen + 全屏 + + + + Full Screen Viewer + 全屏预览 + + + + &Playback + 回放(&P) + + + + Go to Start + 回到起始帧 + + + + Previous Frame + 前一帧 + + + + Play/Pause + 播放/暂停 + + + + Play In to Out + 播放已标记的区域 + + + + Next Frame + 后一帧 + + + + Go to End + 转到结束帧 + + + + Go to Previous Cut + 转到前一切点 + + + + Go to Next Cut + 转到后一切点 + + + + Go to In Point + 转到入点 + + + + Go to Out Point + 转到出点 + + + + Shuttle Left + 向左播放 + + + + Shuttle Stop + 停止播放 + + + + Shuttle Right + 向右播放 + + + + Loop + 循环 + + + + &Sequence + 序列(&S) + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Maximize Panel + 最大化面板 + + + + Lock Panels + 锁定面板 + + + + Reset to Default Layout + 重置为默认布局 + + + + &Tools + 工具(&T) + + + + Pointer Tool + 选择/移动/默认 + + + + Edit Tool + 编辑工具 + + + + Ripple Tool + 波纹工具 + + + + Rolling Tool + 滚动工具 + + + + Razor Tool + 刀片工具 + + + + Slip Tool + 滑移工具 + + + + Slide Tool + 滑动工具 + + + + Hand Tool + + + + + Zoom Tool + 缩放工具 + + + + Transition Tool + 转场工具 + + + + Enable Snapping + 开启边缘吸合/自动对齐 + + + + Preferences + 首选项 + + + + &Help + 帮助(&H) + + + + A&ction Search + 操作搜索(&C) + + + + Send &Feedback... + 发送反馈(&F)... + + + + &About... + 关于(&A)... + + + + olive::MainStatusBar + + + Welcome to %1 %2 + 欢迎使用 %1 %2 + + + + Running %1 background tasks + 正在运行 %1 后台任务 + + + + olive::MainWindow + + + Driver Warning + 驱动程序警告 + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + Olive 检测到您的系统正在使用 Nouveau 图形驱动程序。 + +此驱动程序用于 Olive 会有稳定性和性能问题。强烈建议您在继续使用 Olive 之前安装 NVIDIA 专有驱动程序。 + + + + olive::ManagedDisplayWidget + + + Color Space + 颜色空间 + + + + No color manager connected + + + + + Display + + + + + View + 视图 + + + + Look + + + + + (None) + (无) + + + + OpenColorIO Error + OpenColorIO 错误 + + + + Failed to set color configuration: %1 + 无法设置颜色配置:%1 + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + + + + + Subtract + + + + + Multiply + + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + 正交矩阵 + + + + Ortho + 正交 + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + 位置 + + + + Rotation + 旋转 + + + + Scale + 缩放 + + + + Uniform Scale + 统一缩放的大小 + + + + Anchor Point + 锚点 + + + + olive::MediaInput + + + Footage + 素材 + + + + olive::MenuShared + + + &Project + 项目(&P) + + + + &Sequence + 序列(&S) + + + + &Folder + 文件夹(&F) + + + + Cu&t + 剪切(&T) + + + + Cop&y + 复制(&Y) + + + + &Paste + 粘帖(&P) + + + + Paste Insert + 粘贴插入 + + + + Duplicate + 复制 + + + + Delete + 删除 + + + + Ripple Delete + 波纹删除 + + + + Split + 切断 + + + + Set In Point + 设置时间的起始标记 + + + + Set Out Point + 设置时间的结束标记 + + + + Reset In Point + 重置时间的起始标记 + + + + Reset Out Point + 重置时间的结束标记 + + + + Clear In/Out Point + 清除时间标记 + + + + Add Default Transition + 添加默认的转场效果 + + + + Link/Unlink + 链接/取消链接 + + + + Enable/Disable + 启用/禁用 + + + + Nest + 嵌套 + + + + Frames + + + + + Drop Frame + 丢帧 + + + + Non-Drop Frame + 不丢帧 + + + + Milliseconds + 毫秒 + + + + Seconds + + + + + olive::MergeNode + + + Merge + 合并 + + + + Merge two textures together. + 合并两个纹理到一起。 + + + + Base + + + + + Blend + 混合 + + + + olive::Node + + + Input + 输入 + + + + Output + 输出 + + + + General + 常规 + + + + Math + + + + + Color + 颜色 + + + + Filter + + + + + Timeline + 时间线 + + + + Generator + + + + + Channel + 通道 + + + + Transition + 转场 + + + + Uncategorized + 未分类 + + + + olive::NodeInput + + + Input + 输入 + + + + olive::NodeOutput + + + Output + 输出 + + + + olive::NodePanel + + + Node Editor + 节点编辑器 + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + 整数 + + + + Float + 浮点数 + + + + Rational + 有理数 + + + + Boolean + 布尔值 + + + + Color + 颜色 + + + + Matrix + 矩阵 + + + + Text + 文字 + + + + Font + 字体 + + + + File + 文件 + + + + Texture + 纹理 + + + + Samples + + + + + Footage + 素材 + + + + Vector 2D + 矢量 2D + + + + Vector 3D + 矢量 3D + + + + Vector 4D + 矢量 4D + + + + Unknown + 未知 + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + 已连接到 + + + + Nothing + + + + + Disconnect + 断开连接 + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + 警告 + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + 表格视图 + + + + olive::NodeTableView + + + Type + 类型 + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + (未知) + + + + olive::NodeTreeView + + + Nodes + 节点 + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + 平滑边缘 + + + + Filter + + + + + Show All + 全部显示 + + + + Show Selected Blocks Only + + + + + Direction + 方向 + + + + Top to Bottom + 从上到下 + + + + Bottom to Top + 从下到上 + + + + Left to Right + 从左到右 + + + + Right to Left + 从右到左 + + + + Add + 添加 + + + + olive::PanNode + + + + Pan + 左右平衡/平移 + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + 参数编辑器 + + + + (none) + (无) + + + + (multiple) + (多个) + + + + olive::PathWidget + + + Browse + 浏览 + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + 设置自定义像素长宽比 + + + + Custom... + 自定义... + + + + Custom (%1) + 自定义 (%1) + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + 颜色 + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + 多边形 + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + 颜色 + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + 正在预缓存 %1:%2 + + + + olive::PreferencesAppearanceTab + + + Theme + 主题 + + + + Node Color Scheme + 节点配色方案 + + + + olive::PreferencesAudioTab + + + Output Device: + 输出设备: + + + + Input Device: + 输入设备: + + + + Sample Rate: + 采样率: + + + + Audio Recording: + 音频录制: + + + + Mono + 单声道 + + + + Stereo + 立体声 + + + + Refresh Devices + 刷新设备 + + + + Please wait... + 请等待... + + + + Default + 默认 + + + + olive::PreferencesBehaviorTab + + + Behavior + 行为 + + + + General + 常规 + + + + Enable hover focus + 启用悬停聚焦 + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + 滚轮默认缩放而不是滚动 + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + 音频 + + + + Enable audio scrubbing + + + + + Timeline + 时间线 + + + + Auto-Seek to Imported Clips + 自动寻找并导入剪辑 + + + + Edit Tool Also Seeks + + + + + Edit Tool Selects Links + + + + + Enable Drag Files to Timeline + 启用拖放文件到时间线 + + + + Invert Timeline Scroll Axes + 反转时间线滚动轴 + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + + + + + Seek to the End of Pastes + + + + + Selecting Also Seeks + 选择并查找 + + + + Playback + 回放 + + + + Ask For Name When Setting Marker + 设置标记时询问名称 + + + + Automatically rewind at the end of a sequence + + + + + Project + 项目 + + + + Drop Files on Media to Replace + 拖放文件到媒体进行替换 + + + + Nodes + 节点 + + + + Add Default Effects to New Clips + 添加默认效果到新的剪辑 + + + + Auto-Scale By Default + 默认情况下自动缩放 + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + 首选项 + + + + General + 常规 + + + + Appearance + 外观 + + + + Behavior + 行为 + + + + Disk + 磁盘 + + + + Audio + 音频 + + + + Keyboard + 键盘 + + + + olive::PreferencesDiskTab + + + Disk Management + 磁盘管理 + + + + Disk Cache Location: + 磁盘缓存位置: + + + + Disk Cache Settings + 磁盘缓存设置 + + + + Cache Behavior + 缓存行为 + + + + Cache Ahead: + 向前缓存: + + + + + %1 seconds + %1 秒 + + + + Cache Behind: + 向后缓存: + + + + Disk Cache + 磁盘缓存 + + + + Failed to set disk cache location. Access was denied. + 无法设置磁盘缓存位置。访问被拒绝。 + + + + olive::PreferencesGeneralTab + + + Language: + 语言: + + + + Auto-Scroll Method: + 自动滚动模式: + + + + None + + + + + Page Scrolling + 页面滚动 + + + + Smooth Scrolling + 平滑滚动 + + + + Rectified Waveforms: + + + + + Default Still Image Length: + 默认的静态图像长度: + + + + %1 seconds + %1 秒 + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + 搜索操作或者快捷键 + + + + Action + 操作 + + + + Shortcut + 快捷键 + + + + Import + 输入 + + + + Export + 导出 + + + + Reset Selected + 重新选择 + + + + Reset All + 全部重设 + + + + Confirm Reset All Shortcuts + 确认重置所有快捷键 + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + 您确定要将所有键盘快捷键重置为默认值吗? + + + + Import Keyboard Shortcuts + 导入键盘快捷键配置 + + + + + Error saving shortcuts + 保存键盘快捷键是发生错误 + + + + Failed to open file for reading + 无法读取文件 + + + + Export Keyboard Shortcuts + 导出键盘快捷键 + + + + Export Shortcuts + 导出快捷键 + + + + Shortcuts exported successfully + 快捷键导出成功 + + + + Failed to open file for writing + 无法打开文件进行写入 + + + + olive::ProgressDialog + + + Cancel + 取消 + + + + olive::Project + + + + (untitled) + (未命名) + + + + olive::ProjectExplorer + + + &New + 新建(&N) + + + + &Import... + 输入(&I)... + + + + &Project Properties... + 项目属性(&P)... + + + + Open in New Tab + + + + + Open in New Window + 在新窗口中打开 + + + + Reveal in Explorer + 在资源管理器中显示 + + + + Reveal in Finder + 在 Finder 中显示 + + + + Reveal in File Manager + 在文件管理器中显示 + + + + Pre-Cache + 预缓存 + + + + No sequences exist in project + 项目中不存在序列 + + + + For "%1" + + + + + P&roperties + 属性(&R) + + + + Confirm Footage Deletion + 确认删除素材 + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + 离线素材 + + + + Delete Clips + 删除剪辑 + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + 转到上级文件夹 + + + + olive::ProjectImportErrorDialog + + + Import Error + 导入出错 + + + + The following files failed to import. Olive likely does not support their formats. + 下列文件无法导入。Olive 可能不支持这些文件格式。 + + + + olive::ProjectImportTask + + + Importing %1 files + 正在导入 %1 文件 + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + 正在加载 '%1' + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + 无法读取文件 "%1"。 + + + + olive::ProjectPanel + + + Folder + 文件夹 + + + + Project + 项目 + + + + (none) + (无) + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + '%1' 的项目属性 + + + + OpenColorIO Configuration: + OpenColorIO 配置: + + + + (default) + (默认) + + + + Default Input Color Space: + 默认的输入颜色空间: + + + + Browse + 浏览 + + + + Color Management + 色彩管理 + 颜色管理 + + + + Use Default Location + 使用默认位置 + + + + Store Alongside Project + + + + + Use Custom Location: + 使用默认位置: + + + + Disk Cache Settings + 磁盘缓存设置 + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + 磁盘缓存 + + + + OpenColorIO Config Error + OpenColorIO 配置错误 + + + + Failed to set OpenColorIO configuration: %1 + 无法设置 OpenColorIO 配置: %1 + + + + Invalid path + 无效的路径 + + + + The cache path is invalid. Please check it and try again. + 缓存路径无效。请检查后重试。 + + + + Browse for OpenColorIO configuration + + + + + olive::ProjectSaveTask + + + Saving '%1' + 正在保存 '%1' + + + + Failed to write XML data + 无法写入 XML 数据 + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + 无法覆盖 "%1"。项目已保存为 "%2"。 + + + + Failed to open temporary file "%1" for writing. + 无法打开临时文件 "%1" 进行写入。 + + + + olive::ProjectToolbar + + + New... + 新建... + + + + Open Project + 打开项目 + + + + Save Project + 保存项目 + + + + Undo + 撤销 + + + + Redo + 重做 + + + + Search media, markers, etc. + 搜索媒体、标记,等。 + + + + Switch to Tree View + 切换到树视图 + + + + Switch to List View + 切换到列表视图 + + + + Switch to Icon View + 切换到图标视图 + + + + olive::ProjectViewModel + + + Name + 名称 + + + + Duration + 持续时间 + + + + Rate + 速率 + + + + Move Items + 移动项 + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + 渲染器 + + + + + olive::RichTextDialog + + + B + + + + + Bold + 粗体 + + + + I + + + + + Italic + 斜体 + + + + U + + + + + Underline + 下划线 + + + + S + + + + + Strikethrough + 删除线 + + + + Font Family + 字体系列 + + + + Font Size + 字体大小 + + + + L + + + + + Left Align + 左对齐 + + + + C + + + + + Center Align + 居中对齐 + + + + R + + + + + Right Align + 右对齐 + + + + J + + + + + Justify Align + 两端对齐 + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + 正在导出项目到 OpenTimelineIO + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + 波形 + + + + Histogram + 直方图 + + + + Scope + 范围 + + + + olive::SequenceDialog + + + Name: + 名称: + + + + New Sequence + 新建序列 + + + + Editing "%1" + 编辑中 "%1" + + + + Error editing Sequence + 编辑序列时出错 + + + + Please enter a name for this Sequence. + 请输入此序列名称. + + + + olive::SequenceDialogParameterTab + + + Video + 视频 + + + + Width: + 宽度: + + + + Height: + 高度: + + + + Frame Rate: + 帧率: + + + + Pixel Aspect Ratio: + 像素长宽比: + + + + Interlacing: + 交错: + + + + Audio + 音频 + + + + Sample Rate: + 采样率: + + + + Channels: + 通道: + + + + Preview + 预览 + + + + Resolution: + 分辨率: + + + + Quality: + 质量: + + + + Save Preset + 保存预设 + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + 预设 + + + + My Presets + 我的预设 + + + + 4K UHD + 4K UHD + + + + 1080p + 1080p + + + + 720p + 720p + + + + NTSC + NTSC + + + + PAL + PAL + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + 删除预设 + + + + olive::SequenceViewerPanel + + + Sequence Viewer + 序列查看器 + + + + olive::SliderBase + + + Invalid Value + 无效的值 + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + 纯色 + + + + Generate a solid color. + 生成纯色。 + + + + Color + 颜色 + + + + olive::StringSlider + + + (none) + (无) + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + 输入 + + + + Color + 颜色 + + + + Radius + 半径 + + + + Opacity + 不透明度 + + + + Inner + + + + + olive::Task + + + Task + 任务 + + + + Unknown error + 未知错误 + + + + olive::TaskDialog + + + Task Failed + 任务失败 + + + + olive::TaskManagerPanel + + + Task Manager + 任务管理器 + + + + olive::TaskViewItem + + + Error: %1 + 错误:%1 + + + + olive::TextGenerator + + + Sample Text + 文字样本 + + + + + Text + 文字 + + + + Generate rich text. + + + + + Font + 字体 + + + + Font Size + 字体大小 + + + + Color + 颜色 + + + + Vertical Align + 垂直对齐 + + + + Top + 顶部 + + + + Center + 居中 + + + + Bottom + 底下 + + + + olive::TimeBasedPanel + + + (none) + (无) + + + + olive::TimeBasedWidget + + + Set Marker + 设置标记 + + + + Marker name: + 标记名称: + + + + olive::TimeInput + + + Time + 时间 + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + 时间线 + + + + olive::TimelineWidget + + + + Properties + 属性 + + + + Use Audio Time Units + 使用音频时间单位 + + + + olive::ToolPanel + + + Tools + 工具 + + + + olive::Toolbar + + + Pointer Tool + 选择/移动/默认 + + + + Edit Tool + 编辑工具 + + + + Ripple Tool + 波纹工具 + + + + Rolling Tool + 滚动工具 + + + + Razor Tool + 刀片工具 + + + + Slip Tool + 滑移工具 + + + + Slide Tool + 滑动工具 + + + + Hand Tool + + + + + Zoom Tool + 缩放工具 + + + + Transition Tool + 转场工具 + + + + Record Tool + + + + + Add Tool + 添加工具 + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + 轨道 + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + 已静音 + + + + Video %1 + 视频 %1 + + + + Audio %1 + 音频 %1 + + + + Subtitle %1 + 字幕 %1 + + + + Track %1 + 轨道 %1 + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + 曲线 + + + + Linear + 线性 + + + + Exponential + 指数 + + + + Logarithmic + 对数 + + + + olive::TrigonometryNode + + + Trigonometry + 三角函数 + + + + Perform a trigonometry operation on a value. + 对一个值进行三角函数运算。 + + + + Sine + 正弦 + + + + Cosine + 余弦 + + + + Tangent + 正切 + + + + Inverse Sine + 反正弦 + + + + Inverse Cosine + 反余弦 + + + + Inverse Tangent + 反正切 + + + + Hyperbolic Sine + 双曲正弦 + + + + Hyperbolic Cosine + 双曲余弦 + + + + Hyperbolic Tangent + 双曲正切 + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + 144p {1/%1?} + + + + olive::VideoInput + + + Video Input + 视频输入 + + + + Video + 视频 + + + + Import a video footage stream. + + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + 交错: + + + + Color Space: + 色彩空间: + + + + Default (%1) + 默认 (%1) + + + + Premultiplied Alpha + + + + + Image Sequence + 图像序列 + + + + Start Index: + 起始索引: + + + + End Index: + 结束索引: + + + + Frame Rate: + 帧率: + + + + Invalid Configuration + 无效的配置 + + + + Image sequence end index must be a value higher than the start index. + 图像序列结束索引必须是比起始索引大的值。 + + + + olive::ViewerOutput + + + Viewer + 查看器 + + + + Interface between a Viewer panel and the node system. + + + + + Texture + 纹理 + + + + Samples + + + + + Video Tracks + 视频轨道 + + + + Audio Tracks + 音频轨道 + + + + Subtitle Tracks + 字幕轨道 + + + + olive::ViewerPanel + + + Viewer + 查看器 + + + + olive::ViewerWidget + + + Error + 错误 + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + 缩放 + + + + Fit + 适合 + + + + %1% + + + + + Full Screen + 全屏 + + + + Screen %1: %2x%3 + 放映 %1: %2x%3 + + + + Deinterlace + 取消隔行扫描 + + + + Scopes + 范围 + + + + Cache + 缓存 + + + + Auto-Cache + 自动缓存 + + + + Pause Auto-Cache During Playback + 在回放过程中暂停自动缓存 + + + + Cache Entire Sequence + 缓存整个序列 + + + + Cache Sequence In/Out + + + + + Off + 关闭 + + + + On + 开启 + + + + Custom Aspect + + + + + Show Audio Waveform + 显示音频波形 + + + + olive::VolumeNode + + + + Volume + 音量 + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ts/zh_TW.ts b/app/ts/zh_TW.ts new file mode 100755 index 000000000..bf22b0f39 --- /dev/null +++ b/app/ts/zh_TW.ts @@ -0,0 +1,4767 @@ + + + + + AudioParams + + + %1 Hz + + + + + Mono + 單聲道 + + + + Stereo + 立體聲 + + + + 2.1 + 144p {2.1?} + + + + 5.1 + 144p {5.1?} + + + + 7.1 + 144p {7.1?} + + + + Unknown (0x%1) + + + + + Config + + + Error loading settings + + + + + Failed to load application settings. This session will use defaults. + +%1 + + + + + Error saving settings + + + + + Failed to save application settings. The application may lack write permissions to this location. + + + + + Footage + + + %1 FPS + + + + + %1 Hz + + + + + Filename: %1 + + + + + This footage is not valid for use + + + + + ImportTool + + + Don't ask me again + + + + + No Active Sequence + + + + + No sequence is currently open. Would you like to create one? + + + + + Automatically Detect Parameters From Footage + + + + + Set Parameters Manually + + + + + MoveItemCommand + + + Move Item + + + + + NodeCopyPasteWidget + + + Error pasting nodes + + + + + Failed to paste nodes: %1 + + + + + NodeFactory + + + None + + + + + NodeViewItem + + + %1... + + + + + PresetManager + + + Save Preset + + + + + Set preset name: + + + + + Invalid preset name + + + + + You must enter a preset name + + + + + Preset exists + + + + + A preset with this name already exists. Would you like to replace it? + + + + + RatioDialog + + + Enter custom ratio (e.g. "4:3", "16/9", etc.): + + + + + Invalid custom ratio + + + + + Failed to parse "%1" into an aspect ratio. Please format a rational fraction with a ':' or a '/' separator. + + + + + RenameItemCommand + + + Rename Item + + + + + Sequence + + + %1 FPS + + + + + Stream + + + %1: Audio - %2 Channels, %3Hz + + + + + %1: Unknown + + + + + %1: Image - %2x%3 + + + + + %1: Video - %2x%3 + + + + + TimelineViewBlockItem + + + %1 + +In: %2 +Out: %3 +Length: %4 + + + + + Tool + + + Empty + + + + + Bars + + + + + Solid + + + + + Title + 字幕 + + + + Tone + + + + + Unknown + + + + + VideoParams + + + 8-bit + + + + + 16-bit Integer + + + + + Half-Float (16-bit) + + + + + Full-Float (32-bit) + + + + + Unknown (0x%1) + + + + + %1 FPS + + + + + Square Pixels (%1) + + + + + NTSC Standard (%1) + + + + + NTSC Widescreen (%1) + + + + + PAL Standard (%1) + + + + + PAL Widescreen (%1) + + + + + HD Anamorphic 1080 (%1) + + + + + main + + + Show this help text + + + + + Show application version + + + + + Start in full-screen mode + + + + + Export only (No GUI) + + + + + Override language with file + + + + + qm-file + + + + + Project to open on startup + + + + + olive::AboutDialog + + + About %1 + + + + + Olive is a non-linear video editor. This software is free and protected by the GNU GPL. + Olive是免費的非線性視頻編輯器.基于GNU通用公共許可證(GNU GPL)條款發佈. + + + + Olive Team is obliged to inform users that Olive source code is available for download from its website. + Olive團隊有義務告知用戶可以從官網下載olive的源碼.翻譯者已嘗試用通俗易明的方式進行翻譯,希望大家使用愉快.請支持自由開源軟件謝謝. + + + + olive::ActionSearch + + + Search for action... + 功能搜索... + + + + olive::AudioInput + + + Audio Input + + + + + Audio + 音頻 + + + + Import an audio footage stream. + + + + + olive::AudioMonitorPanel + + + Audio Monitor + + + + + olive::Block + + + Length + 長度 + + + + Media In + + + + + Enabled + + + + + Speed + + + + + olive::BlurFilterNode + + + Blur + + + + + Blurs an image. + + + + + Input + + + + + Method + + + + + Box + + + + + Gaussian + + + + + Radius + + + + + Horizontal + + + + + Vertical + + + + + Repeat Edge Pixels + + + + + olive::ClipBlock + + + Clip + + + + + A time-based node that represents a media source. + + + + + Buffer + + + + + olive::ColorDialog + + + Select Color + + + + + olive::ColorSpaceChooser + + + Color Management + + + + + Input: + + + + + Color Space: + + + + + Display: + + + + + View: + + + + + Look: + + + + + (None) + + + + + olive::ColorValuesTab + + + Red + + + + + Green + + + + + Blue + + + + + olive::ColorValuesWidget + + + Preview + + + + + Input + + + + + Reference + + + + + Display + + + + + olive::ConformTask + + + Conforming Audio %1:%2 + + + + + olive::Core + + + Import error + + + + + Nothing to import + + + + + Importing... + + + + + Import footage... + + + + + Failed to import footage + + + + + Failed to find active Project panel + + + + + No Active Project + + + + + No project is currently open to set the properties for + + + + + Failed to create new folder + + + + + + Failed to find active project + + + + + New Folder + 新建檔案夾 + + + + Failed to create new sequence + + + + + Possible image sequence detected + + + + + The file '%1' looks like it might be part of an image sequence. Would you like to import it as such? + + + + + You must specify a project file to export + + + + + Specified project does not exist + + + + + Project contains no sequences, nothing to export + + + + + This project has multiple sequences. Which do you wish to export? + + + + + Enter number (or %1 to cancel): + + + + + Invalid sequence number + + + + + Export succeeded + + + + + Export failed: %1 + + + + + Project failed to load: %1 + + + + + Failed to open startup file + + + + + The project "%1" doesn't exist. A new project will be started instead. + + + + + + Missing OpenTimelineIO Libraries + + + + + + This build was compiled without OpenTimelineIO and therefore cannot open OpenTimelineIO files. + + + + + Save Project + 保存項目 + + + + + Error + 錯誤 + + + + This Sequence is empty. There is nothing to export. + + + + + No valid sequence detected. + +Make sure a sequence is loaded and it has a connected Viewer node. + + + + + Olive Project + + + + + OpenTimelineIO + + + + + Save Project As + + + + + Load Project + + + + + Label Node + + + + + Set node label + + + + + Sequence %1 + + + + + Cannot open recent project + + + + + The project "%1" doesn't exist. Would you like to remove this file from the recent list? + + + + + Unsaved Changes + + + + + The project '%1' has unsaved changes. Would you like to save them? + + + + + Save + + + + + Save All + + + + + Don't Save + + + + + Don't Save All + + + + + Failed to cache sequence + + + + + No active viewer found with this sequence. + + + + + Open Project + 打開項目 + + + + olive::CrashHandlerDialog + + + Olive + + + + + We're sorry, Olive has crashed. Please help us fix it by sending an error report. + + + + + Describe what you were doing in as much detail as possible. If you can, provide steps to reproduce this crash. + + + + + Crash Report: + + + + + Send Error Report + + + + + Don't Send + + + + + Waiting for crash report to be generated... + + + + + Upload Failed + + + + + Failed to send error report. Please try again later. + + + + + No Crash Summary + + + + + Are you sure you want to send an error report with no crash summary? + + + + + olive::CrossDissolveTransition + + + Cross Dissolve + + + + + Smoothly transition between two clips. + + + + + olive::CurvePanel + + + Curve Editor + + + + + olive::CurveView + + + Zoom to Fit + + + + + olive::CurveWidget + + + Linear + 線性 + + + + Bezier + 貝塞爾曲綫 + + + + Hold + 保留 + + + + olive::DipToColorTransition + + + Dip To Color + + + + + Transition between clips by dipping to a color. + + + + + olive::DiskCacheDialog + + + Disk Cache: %1 + + + + + Disk Cache Settings + + + + + Maximum Disk Cache: + + + + + %1 GB + + + + + + + Clear Disk Cache + + + + + Automatically clear disk cache on close + + + + + Are you sure you want to clear the disk cache in '%1'? + + + + + Disk Cache Cleared + + + + + Disk cache failed to fully clear. You may have to delete the cache files manually. + + + + + Disk Cache Partially Cleared + + + + + olive::DiskManager + + + + Disk Cache Error + + + + + Unable to set custom application disk cache. Using default instead. + + + + + Disk Cache + + + + + You've chosen to change the default disk cache location. This will invalidate your current cache. Would you like to continue? + + + + + Failed to open disk cache at "%1". Try a different folder. + + + + + olive::ElapsedCounterWidget + + + Elapsed: %1 + + + + + Remaining: %1 + + + + + olive::ExportAdvancedVideoDialog + + + Advanced + 高級 + + + + Pixel + + + + + Pixel Format: + 視頻格式: + + + + Performance + + + + + Threads: + 綫程數量: + + + + olive::ExportAudioTab + + + Codec: + 編解碼器: + + + + Sample Rate: + 採樣率: + + + + Channel Layout: + + + + + Format: + + + + + olive::ExportCodec + + + DNxHD + + + + + H.264 + + + + + H.265 + + + + + OpenEXR + + + + + PNG + + + + + ProRes + + + + + TIFF + + + + + MP2 + + + + + MP3 + + + + + AAC + + + + + PCM (Uncompressed) + + + + + Unknown + + + + + olive::ExportDialog + + + Filename: + 檔案名: + + + + Browse for exported file filename + + + + + Preset: + 預置: + + + + Same As Source - High Quality + + + + + Same As Source - Medium Quality + + + + + Same As Source - Low Quality + + + + + Range: + 範圍: + + + + Entire Sequence + 整個片段 + + + + In to Out + 已選擇的時間段 + + + + Format: + + + + + Export Video + + + + + Export Audio + + + + + Video + 視頻 + + + + Audio + 音頻 + + + + + Export + 匯出 + + + + Preview + + + + + Invalid parameters + + + + + Both video and audio are disabled. There's nothing to export. + + + + + Invalid filename + + + + + The filename must contain the extension "%1". Would you like to append it automatically? + + + + + Failed to create output directory + + + + + The intended output directory doesn't exist and Olive couldn't create it. Please choose a different filename. + + + + + Confirm Overwrite + + + + + The file "%1" already exists. Do you want to overwrite it? + + + + + Invalid Parameters + + + + + Width and height must be multiples of 2. + + + + + olive::ExportFormat + + + DNxHD + + + + + Matroska Video + + + + + MPEG-4 Video + + + + + OpenEXR + + + + + PNG + + + + + TIFF + + + + + QuickTime + + + + + Unknown + + + + + olive::ExportTask + + + Exporting "%1" + + + + + Failed to create encoder + + + + + Failed to open file + + + + + Failed to overwrite "%1". Export has been saved as "%2" instead. + + + + + olive::ExportVideoTab + + + Basic + + + + + Width: + 寬度: + + + + Height: + 高度: + + + + Maintain Aspect Ratio: + + + + + Scaling Method: + + + + + Fit + 適合 + + + + Stretch + + + + + Crop + + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + 像素長寬比 + + + + Interlacing: + + + + + Quality: + + + + + Codec + + + + + Codec: + 編解碼器: + + + + Advanced + 高級 + + + + olive::FloatSlider + + + %1 dB + + + + + %1% + + + + + olive::FootagePropertiesDialog + + + "%1" Properties + + + + + Name: + 名稱: + + + + Tracks: + 軌道: + + + + olive::FootageRelinkDialog + + + Footage + + + + + Filename + + + + + Actions + + + + + Browse + 瀏覽 + + + + Relink Footage + + + + + Relink "%1" + + + + + All Files + 全部檔案 + + + + olive::FootageViewerPanel + + + Footage Viewer + + + + + olive::GapBlock + + + Gap + + + + + A time-based node that represents an empty space. + + + + + olive::H264BitRateSection + + + Target Bit Rate (Mbps): + + + + + Maximum Bit Rate (Mbps): + + + + + Two-Pass + + + + + olive::H264FileSizeSection + + + Target File Size (MB): + 輸出檔案大小 (MB): + + + + Two-Pass + + + + + olive::H264Section + + + Compression Method: + + + + + Constant Rate Factor + + + + + Target Bit Rate + + + + + Target File Size + + + + + olive::ImageSection + + + Image Sequence: + + + + + olive::InterlacedComboBox + + + None (Progressive) + 無 (進度) + + + + Top-Field First + + + + + Bottom-Field First + + + + + olive::KeyframePropertiesDialog + + + Keyframe Properties + + + + + In: + + + + + Out: + + + + + Linear + 線性 + + + + Hold + 保留 + + + + Bezier + 貝塞爾曲綫 + + + + olive::KeyframeViewBase + + + Linear + 線性 + + + + Bezier + 貝塞爾曲綫 + + + + Hold + 保留 + + + + P&roperties + + + + + olive::LoadOTIOTask + + + Failed to load OpenTimelineIO from file "%1" + + + + + Unknown OpenTimelineIO root element + + + + + Failed to load clip + + + + + olive::MainMenu + + + &Save '%1' + + + + + Save '%1' &As + + + + + Close '%1' + + + + + Close All Except '%1' + + + + + &Save Project + 保存項目(&S) + + + + Save Project &As + 保存項目為(&A) + + + + Close Project + + + + + Close All Except Current Project + + + + + (None) + + + + + &File + 檔案(&F) + + + + &New + 新建(&N) + + + + &Open Project + 打開項目(&O) + + + + Open &Recent + + + + + &Clear Recent List + + + + + Sa&ve All Projects + + + + + &Import... + 匯入(&I) + + + + &Export + + + + + &Media... + + + + + &Project Properties... + + + + + Close All Projects + + + + + E&xit + 退出(&I) + + + + &Edit + + + + + Insert + + + + + Overwrite + + + + + Select &All + 選擇全部(&A) + + + + Deselect All + 取消選擇所有 + + + + Ripple to In Point + + + + + Ripple to Out Point + + + + + Edit to In Point + + + + + Edit to Out Point + + + + + Delete In/Out Point + 刪除標記的區域 + + + + Ripple Delete In/Out Point + + + + + Set/Edit Marker + 設置/編輯標記 + + + + &View + 視圖(&V) + + + + Zoom In + 放大 + + + + Zoom Out + 縮小 + + + + Increase Track Height + 增加軌道高度 + + + + Decrease Track Height + 降低軌道高度 + + + + Toggle Show All + 軌道全部顯示 + + + + Full Screen + 全屏 + + + + Full Screen Viewer + 全屏預覽 + + + + &Playback + 回放(&P) + + + + Go to Start + 回到起始幀 + + + + Previous Frame + 前一幀 + + + + Play/Pause + 播放/暫停 + + + + Play In to Out + 播放已標記的區域 + + + + Next Frame + 下一幀 + + + + Go to End + 轉到結束幀 + + + + Go to Previous Cut + 切換到之前的位置 + + + + Go to Next Cut + 轉到下一個位置 + + + + Go to In Point + 轉到時間的起始標記處 + + + + Go to Out Point + 轉到時間的結束標記處 + + + + Shuttle Left + 向左播放 + + + + Shuttle Stop + 停止播放 + + + + Shuttle Right + 向右播放 + + + + Loop + 循環播放 + + + + &Sequence + 片段(&S) + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Maximize Panel + 最大化面板 + + + + Lock Panels + 鎖定面板 + + + + Reset to Default Layout + 重置為預設佈局 + + + + &Tools + 工具(&T) + + + + Pointer Tool + 選擇/移動/預設 + + + + Edit Tool + 選擇部分 + + + + Ripple Tool + 漣漪的工具 + + + + Rolling Tool + + + + + Razor Tool + 剪刀 + + + + Slip Tool + 滑動工具 + + + + Slide Tool + 幻燈片工具 + + + + Hand Tool + + + + + Zoom Tool + + + + + Transition Tool + + + + + Enable Snapping + 開啟邊緣吸合/自動對齊 + + + + Preferences + 首選項 + + + + &Help + 幫助(&H) + + + + A&ction Search + 功能查找(&C) + + + + Send &Feedback... + + + + + &About... + 關於(&A) + + + + olive::MainStatusBar + + + Welcome to %1 %2 + 歡迎來到 %1 %2 + + + + Running %1 background tasks + + + + + olive::MainWindow + + + Driver Warning + + + + + Olive has detected your system is using the Nouveau graphics driver. + +This driver is known to have stability and performance issues with Olive. It is highly recommended you install the proprietary NVIDIA driver before continuing to use Olive. + + + + + olive::ManagedDisplayWidget + + + Color Space + + + + + No color manager connected + + + + + Display + + + + + View + 視圖 + + + + Look + + + + + (None) + + + + + OpenColorIO Error + + + + + Failed to set color configuration: %1 + + + + + olive::ManagedPixelSamplerWidget + + + Display + + + + + Reference + + + + + olive::MathNode + + + Math + + + + + Perform a mathematical operation between two values. + + + + + Method + + + + + + Value + + + + + Add + 添加 + + + + Subtract + + + + + Multiply + + + + + Divide + + + + + Power + + + + + olive::MatrixGenerator + + + Orthographic Matrix + + + + + Ortho + + + + + Generate an orthographic matrix using position, rotation, and scale. + + + + + Position + 位置 + + + + Rotation + 旋轉 + + + + Scale + 縮放 + + + + Uniform Scale + 統一縮放的大小 + + + + Anchor Point + 錨點 + + + + olive::MediaInput + + + Footage + + + + + olive::MenuShared + + + &Project + 項目(&P) + + + + &Sequence + 片段(&S) + + + + &Folder + 目錄(&F) + + + + Cu&t + 剪切(&T) + + + + Cop&y + 複製(&Y) + + + + &Paste + 粘帖(&P) + + + + Paste Insert + 插入式粘貼 + + + + Duplicate + 複製 + + + + Delete + 刪除 + + + + Ripple Delete + 抽出片段並刪除 + + + + Split + 切斷 + + + + Set In Point + 設置時間的起始標記 + + + + Set Out Point + 設置時間的結束標記 + + + + Reset In Point + 重置時間的起始標記 + + + + Reset Out Point + 重置時間的結束標記 + + + + Clear In/Out Point + 清除時間標記 + + + + Add Default Transition + 添加預設的轉場效果 + + + + Link/Unlink + 連結/取消連結音頻和視頻 + + + + Enable/Disable + 啟用/禁用 + + + + Nest + 嵌套 + + + + Frames + + + + + Drop Frame + + + + + Non-Drop Frame + + + + + Milliseconds + 毫秒 + + + + Seconds + + + + + olive::MergeNode + + + Merge + + + + + Merge two textures together. + + + + + Base + + + + + Blend + + + + + olive::Node + + + Input + + + + + Output + + + + + General + 一般 + + + + Math + + + + + Color + 顏色 + + + + Filter + + + + + Timeline + 時間軸 + + + + Generator + + + + + Channel + + + + + Transition + + + + + Uncategorized + + + + + olive::NodeInput + + + Input + + + + + olive::NodeOutput + + + Output + + + + + olive::NodePanel + + + Node Editor + + + + + olive::NodeParam + + + Value + + + + + None + + + + + Integer + + + + + Float + + + + + Rational + + + + + Boolean + + + + + Color + 顏色 + + + + Matrix + + + + + Text + + + + + Font + 字型 + + + + File + + + + + Texture + + + + + Samples + + + + + Footage + + + + + Vector 2D + + + + + Vector 3D + + + + + Vector 4D + + + + + Unknown + + + + + olive::NodeParamViewArrayWidget + + + + + + + + + %1 elements + + + + + olive::NodeParamViewConnectedLabel + + + Connected to + + + + + Nothing + + + + + Disconnect + + + + + olive::NodeParamViewItem + + + %1 (%2) + + + + + olive::NodeParamViewItemBody + + + %1: + + + + + olive::NodeParamViewKeyframeControl + + + Warning + + + + + Are you sure you want to disable keyframing on this value? This will clear all existing keyframes. + + + + + olive::NodeTablePanel + + + Table View + + + + + olive::NodeTableView + + + Type + 類型 + + + + Source + + + + + R/X + + + + + G/Y + + + + + B/Z + + + + + A/W + + + + + (unknown) + (未知) + + + + olive::NodeTreeView + + + Nodes + + + + + olive::NodeView + + + Label + + + + + Auto-Position + + + + + Smooth Edges + + + + + Filter + + + + + Show All + + + + + Show Selected Blocks Only + + + + + Direction + + + + + Top to Bottom + + + + + Bottom to Top + + + + + Left to Right + + + + + Right to Left + + + + + Add + 添加 + + + + olive::PanNode + + + + Pan + 左右平衡/平移 + + + + Adjust the stereo panning of an audio source. + + + + + Samples + + + + + olive::PanelWidget + + + %1: %2 + + + + + olive::ParamPanel + + + Parameter Editor + + + + + (none) + (無) + + + + (multiple) + (多個) + + + + olive::PathWidget + + + Browse + 瀏覽 + + + + Browse for path + + + + + olive::PixelAspectRatioComboBox + + + Set Custom Pixel Aspect Ratio + + + + + Custom... + + + + + Custom (%1) + + + + + olive::PixelSamplerPanel + + + Pixel Sampler + + + + + olive::PixelSamplerWidget + + + Color + 顏色 + + + + <html><font color='#FF8080'>R: %1</font><br><font color='#80FF80'>G: %2</font><br><font color='#8080FF'>B: %3</font><br>A: %4</html> + + + + + olive::PolygonGenerator + + + Polygon + + + + + Generate a 2D polygon of any amount of points. + + + + + Points + + + + + Color + 顏色 + + + + olive::PreCacheTask + + + Pre-caching %1:%2 + + + + + olive::PreferencesAppearanceTab + + + Theme + 主題 + + + + Node Color Scheme + + + + + olive::PreferencesAudioTab + + + Output Device: + 輸出設備: + + + + Input Device: + 輸入設備: + + + + Sample Rate: + 採樣率: + + + + Audio Recording: + 音頻錄製: + + + + Mono + 單聲道 + + + + Stereo + 立體聲 + + + + Refresh Devices + + + + + Please wait... + + + + + Default + 預設 + + + + olive::PreferencesBehaviorTab + + + Behavior + 行為 + + + + General + 一般 + + + + Enable hover focus + + + + + Panels will be considered focused when the mouse cursor is over them without having to click them. + + + + + Scroll wheel zooms by default instead of scrolling + + + + + Holding CTRL while using Olive toggles this setting + + + + + Audio + 音頻 + + + + Enable audio scrubbing + + + + + Timeline + 時間軸 + + + + Auto-Seek to Imported Clips + 自動尋找並導入剪輯 + + + + Edit Tool Also Seeks + + + + + Edit Tool Selects Links + + + + + Enable Drag Files to Timeline + + + + + Invert Timeline Scroll Axes + 反轉時間軸滾動軸 + + + + Hold ALT on any UI element to switch scrolling axes + + + + + Seek Also Selects + + + + + Seek to the End of Pastes + + + + + Selecting Also Seeks + 選擇並查找 + + + + Playback + 回放 + + + + Ask For Name When Setting Marker + 設置標記時詢問名稱 + + + + Automatically rewind at the end of a sequence + + + + + Project + 項目 + + + + Drop Files on Media to Replace + 拖放檔案以代替媒體 + + + + Nodes + + + + + Add Default Effects to New Clips + 添加預設效果到新的剪輯 + + + + Auto-Scale By Default + 預設情況下自動縮放 + + + + Splitting Clips Copies Dependencies + + + + + Multiple clips can share the same nodes. Disable this to automatically share node dependencies among clips when copying or splitting them. + + + + + olive::PreferencesDialog + + + Preferences + 首選項 + + + + General + 一般 + + + + Appearance + 外觀 + + + + Behavior + 行為 + + + + Disk + + + + + Audio + 音頻 + + + + Keyboard + 鍵盤 + + + + olive::PreferencesDiskTab + + + Disk Management + + + + + Disk Cache Location: + + + + + Disk Cache Settings + + + + + Cache Behavior + + + + + Cache Ahead: + + + + + + %1 seconds + + + + + Cache Behind: + + + + + Disk Cache + + + + + Failed to set disk cache location. Access was denied. + + + + + olive::PreferencesGeneralTab + + + Language: + 語言: + + + + Auto-Scroll Method: + + + + + None + + + + + Page Scrolling + + + + + Smooth Scrolling + + + + + Rectified Waveforms: + + + + + Default Still Image Length: + + + + + %1 seconds + + + + + %1 (%2) + + + + + olive::PreferencesKeyboardTab + + + Search for action or shortcut + 搜索功能或者快捷鍵 + + + + Action + 功能 + + + + Shortcut + 快捷鍵 + + + + Import + 匯入 + + + + Export + 匯出 + + + + Reset Selected + 重新選擇 + + + + Reset All + 全部重設 + + + + Confirm Reset All Shortcuts + 確認重置所有快捷鍵 + + + + Are you sure you wish to reset all keyboard shortcuts to their defaults? + 您確定要將所有鍵盤快捷鍵重置為預設值嗎? + + + + Import Keyboard Shortcuts + 導入鍵盤快捷鍵配置 + + + + + Error saving shortcuts + 保存鍵盤快捷鍵是發生錯誤 + + + + Failed to open file for reading + 無法讀取檔案 + + + + Export Keyboard Shortcuts + 匯出鍵盤快捷鍵配置 + + + + Export Shortcuts + 匯出快捷鍵 + + + + Shortcuts exported successfully + 快捷鍵成功匯出 + + + + Failed to open file for writing + 無法寫入檔案 + + + + olive::ProgressDialog + + + Cancel + 取消 + + + + olive::Project + + + + (untitled) + + + + + olive::ProjectExplorer + + + &New + 新建(&N) + + + + &Import... + 匯入(&I) + + + + &Project Properties... + + + + + Open in New Tab + + + + + Open in New Window + + + + + Reveal in Explorer + 在瀏覽器中預覽 + + + + Reveal in Finder + 在查找當中預覽 + + + + Reveal in File Manager + 在檔案管理器中預覽 + + + + Pre-Cache + + + + + No sequences exist in project + + + + + For "%1" + + + + + P&roperties + + + + + Confirm Footage Deletion + + + + + The footage "%1" is currently used in the following sequence(s): + +%2 +What would you like to do with these clips? + + + + + Offline Footage + + + + + Delete Clips + + + + + olive::ProjectExplorerNavigation + + + Go to parent folder + + + + + olive::ProjectImportErrorDialog + + + Import Error + + + + + The following files failed to import. Olive likely does not support their formats. + + + + + olive::ProjectImportTask + + + Importing %1 files + + + + + olive::ProjectLoadBaseTask + + + Loading '%1' + + + + + olive::ProjectLoadTask + + + This project is newer than this version of Olive and cannot be opened. + + + + + + This project is from a version of Olive that is no longer supported in this version. + + + + + Failed to read file "%1" for reading. + + + + + olive::ProjectPanel + + + Folder + + + + + Project + 項目 + + + + (none) + (無) + + + + olive::ProjectPropertiesDialog + + + Project Properties for '%1' + + + + + OpenColorIO Configuration: + + + + + (default) + + + + + Default Input Color Space: + + + + + Browse + 瀏覽 + + + + Color Management + + + + + Use Default Location + + + + + Store Alongside Project + + + + + Use Custom Location: + + + + + Disk Cache Settings + + + + + + "Store alignside project" functionality not implemented yet + + + + + Disk Cache + + + + + OpenColorIO Config Error + + + + + Failed to set OpenColorIO configuration: %1 + + + + + Invalid path + + + + + The cache path is invalid. Please check it and try again. + + + + + Browse for OpenColorIO configuration + + + + + olive::ProjectSaveTask + + + Saving '%1' + + + + + Failed to write XML data + + + + + Failed to overwrite "%1". Project has been saved as "%2" instead. + + + + + Failed to open temporary file "%1" for writing. + + + + + olive::ProjectToolbar + + + New... + + + + + Open Project + 打開項目 + + + + Save Project + 保存項目 + + + + Undo + 撤銷 + + + + Redo + 重做 + + + + Search media, markers, etc. + 搜索媒體,標記等. + + + + Switch to Tree View + + + + + Switch to List View + + + + + Switch to Icon View + + + + + olive::ProjectViewModel + + + Name + 名稱 + + + + Duration + 持續時間 + + + + Rate + 速率 + + + + Move Items + + + + + olive::RenderCancelDialog + + + Waiting for workers to finish... + + + + + Renderer + + + + + olive::RichTextDialog + + + B + + + + + Bold + 粗體 + + + + I + + + + + Italic + + + + + U + + + + + Underline + + + + + S + + + + + Strikethrough + + + + + Font Family + + + + + Font Size + + + + + L + + + + + Left Align + + + + + C + + + + + Center Align + + + + + R + + + + + Right Align + + + + + J + + + + + Justify Align + + + + + olive::SaveOTIOTask + + + Exporting project to OpenTimelineIO + + + + + Project contains no sequences to export. + + + + + Failed to serialize sequence "%1" + + + + + olive::ScopePanel + + + Waveform + + + + + Histogram + + + + + Scope + + + + + olive::SequenceDialog + + + Name: + 名稱: + + + + New Sequence + 新片段 + + + + Editing "%1" + 編輯中 "%1" + + + + Error editing Sequence + + + + + Please enter a name for this Sequence. + + + + + olive::SequenceDialogParameterTab + + + Video + 視頻 + + + + Width: + 寬度: + + + + Height: + 高度: + + + + Frame Rate: + + + + + Pixel Aspect Ratio: + 像素長寬比 + + + + Interlacing: + + + + + Audio + 音頻 + + + + Sample Rate: + 採樣率: + + + + Channels: + + + + + Preview + + + + + Resolution: + + + + + Quality: + + + + + Save Preset + + + + + (%1x%2) + + + + + olive::SequenceDialogPresetTab + + + Preset + + + + + My Presets + + + + + 4K UHD + + + + + 1080p + 1080p + + + + 720p + 720p + + + + NTSC + + + + + PAL + + + + + %1 23.976 FPS + + + + + %1 25 FPS + + + + + %1 29.97 FPS + + + + + %1 50 FPS + + + + + %1 59.94 FPS + + + + + %1 Standard + + + + + %1 Widescreen + + + + + Delete Preset + + + + + olive::SequenceViewerPanel + + + Sequence Viewer + + + + + olive::SliderBase + + + Invalid Value + + + + + The entered value is not valid for this field. + + + + + olive::SolidGenerator + + + Solid + + + + + Generate a solid color. + + + + + Color + 顏色 + + + + olive::StringSlider + + + (none) + (無) + + + + olive::StrokeFilterNode + + + Stroke + + + + + Creates a stroke outline around an image. + + + + + Input + + + + + Color + 顏色 + + + + Radius + + + + + Opacity + 透明度 + + + + Inner + + + + + olive::Task + + + Task + + + + + Unknown error + + + + + olive::TaskDialog + + + Task Failed + + + + + olive::TaskManagerPanel + + + Task Manager + + + + + olive::TaskViewItem + + + Error: %1 + + + + + olive::TextGenerator + + + Sample Text + 文字樣本 + + + + + Text + + + + + Generate rich text. + + + + + Font + 字型 + + + + Font Size + + + + + Color + 顏色 + + + + Vertical Align + + + + + Top + 頂部 + + + + Center + + + + + Bottom + 底下 + + + + olive::TimeBasedPanel + + + (none) + (無) + + + + olive::TimeBasedWidget + + + Set Marker + 設置標記 + + + + Marker name: + + + + + olive::TimeInput + + + Time + + + + + Generates the time (in seconds) at this frame + + + + + olive::TimelinePanel + + + Timeline + 時間軸 + + + + olive::TimelineWidget + + + + Properties + 屬性 + + + + Use Audio Time Units + + + + + olive::ToolPanel + + + Tools + + + + + olive::Toolbar + + + Pointer Tool + 選擇/移動/預設 + + + + Edit Tool + 選擇部分 + + + + Ripple Tool + 漣漪的工具 + + + + Rolling Tool + + + + + Razor Tool + 剪刀 + + + + Slip Tool + 滑動工具 + + + + Slide Tool + 幻燈片工具 + + + + Hand Tool + + + + + Zoom Tool + + + + + Transition Tool + + + + + Record Tool + + + + + Add Tool + + + + + Toggle Snapping + + + + + olive::TrackOutput + + + Track + + + + + Node for representing and processing a single array of Blocks sorted by time. Also represents the end of a Sequence. + + + + + Blocks + + + + + Muted + + + + + Video %1 + + + + + Audio %1 + + + + + Subtitle %1 + + + + + Track %1 + + + + + olive::TrackViewItem + + + M + + + + + L + + + + + olive::TransitionBlock + + + From + + + + + To + + + + + Curve + + + + + Linear + 線性 + + + + Exponential + + + + + Logarithmic + + + + + olive::TrigonometryNode + + + Trigonometry + + + + + Perform a trigonometry operation on a value. + + + + + Sine + 正弦 + + + + Cosine + + + + + Tangent + + + + + Inverse Sine + + + + + Inverse Cosine + + + + + Inverse Tangent + + + + + Hyperbolic Sine + + + + + Hyperbolic Cosine + + + + + Hyperbolic Tangent + + + + + Method + + + + + olive::VideoDividerComboBox + + + Full + + + + + 1/%1 + 144p {1/%1?} + + + + olive::VideoInput + + + Video Input + + + + + Video + 視頻 + + + + Import a video footage stream. + + + + + olive::VideoStreamProperties + + + Pixel Aspect: + + + + + Interlacing: + + + + + Color Space: + + + + + Default (%1) + + + + + Premultiplied Alpha + + + + + Image Sequence + + + + + Start Index: + + + + + End Index: + + + + + Frame Rate: + + + + + Invalid Configuration + + + + + Image sequence end index must be a value higher than the start index. + + + + + olive::ViewerOutput + + + Viewer + + + + + Interface between a Viewer panel and the node system. + + + + + Texture + + + + + Samples + + + + + Video Tracks + + + + + Audio Tracks + + + + + Subtitle Tracks + + + + + olive::ViewerPanel + + + Viewer + + + + + olive::ViewerWidget + + + Error + 錯誤 + + + + No in or out points are set to cache. + + + + + + Safe Margins + + + + + Zoom + 縮放 + + + + Fit + 適合 + + + + %1% + + + + + Full Screen + 全屏 + + + + Screen %1: %2x%3 + 放映 %1: %2x%3 + + + + Deinterlace + + + + + Scopes + + + + + Cache + + + + + Auto-Cache + + + + + Pause Auto-Cache During Playback + + + + + Cache Entire Sequence + + + + + Cache Sequence In/Out + + + + + Off + 關閉 + + + + On + + + + + Custom Aspect + + + + + Show Audio Waveform + + + + + olive::VolumeNode + + + + Volume + 音量 + + + + Adjusts the volume of an audio source. + + + + + Samples + + + + diff --git a/app/ui/CMakeLists.txt b/app/ui/CMakeLists.txt index 55ba82947..793f616e7 100644 --- a/app/ui/CMakeLists.txt +++ b/app/ui/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/ui/cursors/CMakeLists.txt b/app/ui/cursors/CMakeLists.txt index 2f77372f9..5ef1fd183 100644 --- a/app/ui/cursors/CMakeLists.txt +++ b/app/ui/cursors/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/ui/graphics/CMakeLists.txt b/app/ui/graphics/CMakeLists.txt index c1cde3598..6a4c39a84 100644 --- a/app/ui/graphics/CMakeLists.txt +++ b/app/ui/graphics/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/ui/icons/CMakeLists.txt b/app/ui/icons/CMakeLists.txt index 83cb55606..ab5b9c0bd 100644 --- a/app/ui/icons/CMakeLists.txt +++ b/app/ui/icons/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/ui/icons/icons.cpp b/app/ui/icons/icons.cpp index a7e655373..f5ccd421d 100644 --- a/app/ui/icons/icons.cpp +++ b/app/ui/icons/icons.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /// Works in conjunction with `genicons.sh` to generate and utilize icons of specific sizes const int ICON_SIZE_COUNT = 4; @@ -140,4 +140,4 @@ QIcon icon::Create(const QString& theme, const QString &name) return icon; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/ui/icons/icons.h b/app/ui/icons/icons.h index 51bffe5eb..ea8bc4e6d 100644 --- a/app/ui/icons/icons.h +++ b/app/ui/icons/icons.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { namespace icon { @@ -125,6 +125,6 @@ void LoadAll(const QString &theme); } -OLIVE_NAMESPACE_EXIT +} #endif // ICONS_H diff --git a/app/ui/style/CMakeLists.txt b/app/ui/style/CMakeLists.txt index 179a50687..2b6f18ee3 100644 --- a/app/ui/style/CMakeLists.txt +++ b/app/ui/style/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/ui/style/generate-style.sh b/app/ui/style/generate-style.sh index 327ae81c5..878c7504f 100755 --- a/app/ui/style/generate-style.sh +++ b/app/ui/style/generate-style.sh @@ -1,7 +1,7 @@ #!/bin/sh # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/ui/style/olive-dark/png/new.128.png b/app/ui/style/olive-dark/png/new.128.png index 68cf53297..7b8c6b8e8 100644 Binary files a/app/ui/style/olive-dark/png/new.128.png and b/app/ui/style/olive-dark/png/new.128.png differ diff --git a/app/ui/style/olive-dark/png/new.16.png b/app/ui/style/olive-dark/png/new.16.png index 08465e682..d69c1e387 100644 Binary files a/app/ui/style/olive-dark/png/new.16.png and b/app/ui/style/olive-dark/png/new.16.png differ diff --git a/app/ui/style/olive-dark/png/new.32.png b/app/ui/style/olive-dark/png/new.32.png index da2c2927d..314977971 100644 Binary files a/app/ui/style/olive-dark/png/new.32.png and b/app/ui/style/olive-dark/png/new.32.png differ diff --git a/app/ui/style/olive-dark/png/new.64.png b/app/ui/style/olive-dark/png/new.64.png index ddb69f86f..9c3e97453 100644 Binary files a/app/ui/style/olive-dark/png/new.64.png and b/app/ui/style/olive-dark/png/new.64.png differ diff --git a/app/ui/style/olive-dark/style.css b/app/ui/style/olive-dark/style.css index 96be8d2ef..34e26d7f5 100644 --- a/app/ui/style/olive-dark/style.css +++ b/app/ui/style/olive-dark/style.css @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 diff --git a/app/ui/style/olive-dark/svg/new.svg b/app/ui/style/olive-dark/svg/new.svg index 82429f30b..933cf4cab 100644 --- a/app/ui/style/olive-dark/svg/new.svg +++ b/app/ui/style/olive-dark/svg/new.svg @@ -1,6 +1,4 @@ - - + inkscape:snap-smooth-nodes="true" + inkscape:document-rotation="0"> + diff --git a/app/ui/style/olive-light/png/new.128.png b/app/ui/style/olive-light/png/new.128.png index 867ee4520..3f20d71e5 100644 Binary files a/app/ui/style/olive-light/png/new.128.png and b/app/ui/style/olive-light/png/new.128.png differ diff --git a/app/ui/style/olive-light/png/new.16.png b/app/ui/style/olive-light/png/new.16.png index 1d478fe4c..dbdf400b2 100644 Binary files a/app/ui/style/olive-light/png/new.16.png and b/app/ui/style/olive-light/png/new.16.png differ diff --git a/app/ui/style/olive-light/png/new.32.png b/app/ui/style/olive-light/png/new.32.png index c63d512f7..d02612005 100644 Binary files a/app/ui/style/olive-light/png/new.32.png and b/app/ui/style/olive-light/png/new.32.png differ diff --git a/app/ui/style/olive-light/png/new.64.png b/app/ui/style/olive-light/png/new.64.png index 7f6461164..02178dbe3 100644 Binary files a/app/ui/style/olive-light/png/new.64.png and b/app/ui/style/olive-light/png/new.64.png differ diff --git a/app/ui/style/olive-light/style.css b/app/ui/style/olive-light/style.css index bab366ba1..ff3a1135b 100644 --- a/app/ui/style/olive-light/style.css +++ b/app/ui/style/olive-light/style.css @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 diff --git a/app/ui/style/olive-light/svg/convert-to-dark.sh b/app/ui/style/olive-light/svg/convert-to-dark.sh index 4babf86b7..16aa5a1df 100755 --- a/app/ui/style/olive-light/svg/convert-to-dark.sh +++ b/app/ui/style/olive-light/svg/convert-to-dark.sh @@ -1,7 +1,7 @@ #!/bin/sh # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/ui/style/olive-light/svg/new.svg b/app/ui/style/olive-light/svg/new.svg index 482ad42da..f600b7e82 100644 --- a/app/ui/style/olive-light/svg/new.svg +++ b/app/ui/style/olive-light/svg/new.svg @@ -1,6 +1,4 @@ - - + inkscape:snap-smooth-nodes="true" + inkscape:document-rotation="0"> + diff --git a/app/ui/style/style.cpp b/app/ui/style/style.cpp index 26ee7d86f..7866ce7a9 100644 --- a/app/ui/style/style.cpp +++ b/app/ui/style/style.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -31,7 +31,7 @@ #include "config/config.h" #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { const char* StyleManager::kDefaultStyle = "olive-dark"; QString StyleManager::current_style_; @@ -39,7 +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 QT_VERSION < QT_VERSION_CHECK(5, 15, 0) || QT_VERSION > QT_VERSION_CHECK(5, 15, 2) #if defined(Q_OS_WINDOWS) QStyle* s = QStyleFactory::create(QStringLiteral("windowsvista")); widget->setStyle(s); @@ -192,4 +192,4 @@ void StyleManager::SetStyle(const QString &style_path) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/ui/style/style.h b/app/ui/style/style.h index dbf385db0..be77dce06 100644 --- a/app/ui/style/style.h +++ b/app/ui/style/style.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class StyleManager : public QObject { public: @@ -58,6 +58,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // STYLEMANAGER_H diff --git a/app/undo/CMakeLists.txt b/app/undo/CMakeLists.txt index da2588690..aeedc4336 100644 --- a/app/undo/CMakeLists.txt +++ b/app/undo/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/undo/undocommand.cpp b/app/undo/undocommand.cpp index 38c81a851..db8318c3e 100644 --- a/app/undo/undocommand.cpp +++ b/app/undo/undocommand.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "core.h" -OLIVE_NAMESPACE_ENTER +namespace olive { UndoCommand::UndoCommand(QUndoCommand *parent) : QUndoCommand(parent) @@ -54,4 +54,4 @@ void UndoCommand::undo_internal() QUndoCommand::undo(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/undo/undocommand.h b/app/undo/undocommand.h index 2da3b0c4f..ff71174d1 100644 --- a/app/undo/undocommand.h +++ b/app/undo/undocommand.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/define.h" #include "project/project.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class UndoCommand : public QUndoCommand { @@ -47,6 +47,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // UNDOCOMMAND_H diff --git a/app/undo/undostack.cpp b/app/undo/undostack.cpp index eec3097d7..299f6f695 100644 --- a/app/undo/undostack.cpp +++ b/app/undo/undostack.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "undostack.h" -OLIVE_NAMESPACE_ENTER +namespace olive { void UndoStack::pushIfHasChildren(QUndoCommand *command) { @@ -31,4 +31,4 @@ void UndoStack::pushIfHasChildren(QUndoCommand *command) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/undo/undostack.h b/app/undo/undostack.h index 980a6875c..f19e98969 100644 --- a/app/undo/undostack.h +++ b/app/undo/undostack.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class UndoStack : public QUndoStack { public: @@ -37,6 +37,6 @@ public: void pushIfHasChildren(QUndoCommand* command); }; -OLIVE_NAMESPACE_EXIT +} #endif // UNDOSTACK_H diff --git a/app/widget/CMakeLists.txt b/app/widget/CMakeLists.txt index 17b954970..32c4c88cd 100644 --- a/app/widget/CMakeLists.txt +++ b/app/widget/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/audiomonitor/CMakeLists.txt b/app/widget/audiomonitor/CMakeLists.txt index 6bc5833fb..4e2e98efa 100644 --- a/app/widget/audiomonitor/CMakeLists.txt +++ b/app/widget/audiomonitor/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/audiomonitor/audiomonitor.cpp b/app/widget/audiomonitor/audiomonitor.cpp index 2ce1f50a5..22ba0eb58 100644 --- a/app/widget/audiomonitor/audiomonitor.cpp +++ b/app/widget/audiomonitor/audiomonitor.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "audio/audiomanager.h" #include "common/qtutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { const int kDecibelStep = 6; const int kDecibelMinimum = -200; @@ -124,7 +124,7 @@ void AudioMonitor::paintGL() // Create rect where decibel markings will go on the side QRect db_labels_rect = rect(); - db_labels_rect.setWidth(QFontMetricsWidth(p.fontMetrics(), "-00")); + db_labels_rect.setWidth(QtUtils::QFontMetricsWidth(p.fontMetrics(), "-00")); db_labels_rect.adjust(0, font_height, 0, 0); // Determine rect where the main meter will go @@ -357,4 +357,4 @@ QVector AudioMonitor::GetAverages() const return v; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/audiomonitor/audiomonitor.h b/app/widget/audiomonitor/audiomonitor.h index 9a0331301..e9189b3d8 100644 --- a/app/widget/audiomonitor/audiomonitor.h +++ b/app/widget/audiomonitor/audiomonitor.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,7 +29,7 @@ #include "render/audioparams.h" #include "render/audioplaybackcache.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class AudioMonitor : public QOpenGLWidget { @@ -78,6 +78,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // AUDIOMONITORWIDGET_H diff --git a/app/widget/clickablelabel/CMakeLists.txt b/app/widget/clickablelabel/CMakeLists.txt index 95a0c9d19..733f11d8c 100644 --- a/app/widget/clickablelabel/CMakeLists.txt +++ b/app/widget/clickablelabel/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/clickablelabel/clickablelabel.cpp b/app/widget/clickablelabel/clickablelabel.cpp index a267a1019..a55837dbd 100644 --- a/app/widget/clickablelabel/clickablelabel.cpp +++ b/app/widget/clickablelabel/clickablelabel.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { ClickableLabel::ClickableLabel(const QString &text, QWidget *parent) : QLabel(text, parent) @@ -48,4 +48,4 @@ void ClickableLabel::mouseDoubleClickEvent(QMouseEvent *event) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/clickablelabel/clickablelabel.h b/app/widget/clickablelabel/clickablelabel.h index 32d5a55db..3897097ce 100644 --- a/app/widget/clickablelabel/clickablelabel.h +++ b/app/widget/clickablelabel/clickablelabel.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ClickableLabel : public QLabel { @@ -44,6 +44,6 @@ signals: }; -OLIVE_NAMESPACE_EXIT +} #endif // CLICKABLELABEL_H diff --git a/app/widget/collapsebutton/CMakeLists.txt b/app/widget/collapsebutton/CMakeLists.txt index fd4f051ad..9a38da33f 100644 --- a/app/widget/collapsebutton/CMakeLists.txt +++ b/app/widget/collapsebutton/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/collapsebutton/collapsebutton.cpp b/app/widget/collapsebutton/collapsebutton.cpp index 2740d63b5..2d31330b8 100644 --- a/app/widget/collapsebutton/collapsebutton.cpp +++ b/app/widget/collapsebutton/collapsebutton.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { CollapseButton::CollapseButton(QWidget *parent) : QPushButton(parent) @@ -47,4 +47,4 @@ void CollapseButton::UpdateIcon(bool e) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/collapsebutton/collapsebutton.h b/app/widget/collapsebutton/collapsebutton.h index 5699b218c..ab3a6ff18 100644 --- a/app/widget/collapsebutton/collapsebutton.h +++ b/app/widget/collapsebutton/collapsebutton.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class CollapseButton : public QPushButton { @@ -38,6 +38,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // COLLAPSEBUTTON_H diff --git a/app/widget/colorbutton/CMakeLists.txt b/app/widget/colorbutton/CMakeLists.txt index b7a5da383..e785da29c 100644 --- a/app/widget/colorbutton/CMakeLists.txt +++ b/app/widget/colorbutton/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/colorbutton/colorbutton.cpp b/app/widget/colorbutton/colorbutton.cpp index be5dc2b69..716d7f906 100644 --- a/app/widget/colorbutton/colorbutton.cpp +++ b/app/widget/colorbutton/colorbutton.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "dialog/color/colordialog.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ColorButton::ColorButton(ColorManager* color_manager, QWidget *parent) : QPushButton(parent), @@ -72,7 +72,7 @@ void ColorButton::UpdateColor() QColor managed = color_processor_->ConvertColor(color_).toQColor(); - setStyleSheet(QStringLiteral("%1--ColorButton {background: %2;}").arg(MACRO_VAL_AS_STR(OLIVE_NAMESPACE), managed.name())); + setStyleSheet(QStringLiteral("%1--ColorButton {background: %2;}").arg(MACRO_VAL_AS_STR(olive), managed.name())); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/colorbutton/colorbutton.h b/app/widget/colorbutton/colorbutton.h index fea1ce6ca..9d3a7e46c 100644 --- a/app/widget/colorbutton/colorbutton.h +++ b/app/widget/colorbutton/colorbutton.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "render/colormanager.h" #include "render/managedcolor.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ColorButton : public QPushButton { @@ -56,6 +56,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // COLORBUTTON_H diff --git a/app/widget/colorwheel/CMakeLists.txt b/app/widget/colorwheel/CMakeLists.txt index 508c7ce59..d78879230 100644 --- a/app/widget/colorwheel/CMakeLists.txt +++ b/app/widget/colorwheel/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/colorwheel/colorgradientwidget.cpp b/app/widget/colorwheel/colorgradientwidget.cpp index 82883eb69..56a166342 100644 --- a/app/widget/colorwheel/colorgradientwidget.cpp +++ b/app/widget/colorwheel/colorgradientwidget.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/lerp.h" #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ColorGradientWidget::ColorGradientWidget(Qt::Orientation orientation, QWidget *parent) : ColorSwatchWidget(parent), @@ -76,7 +76,7 @@ void ColorGradientWidget::paintEvent(QPaintEvent *e) p.setPen(QPen(GetUISelectorColor(), qMax(1, selector_radius / 2))); p.setBrush(Qt::NoBrush); - float clamped_val = clamp(val_, 0.0f, 1.0f); + double clamped_val = clamp(val_, 0.0, 1.0); if (orientation_ == Qt::Horizontal) { p.drawRect(qRound(width() * (1.0 - clamped_val)) - selector_radius, 0, selector_radius * 2, height() - 1); @@ -87,7 +87,7 @@ void ColorGradientWidget::paintEvent(QPaintEvent *e) void ColorGradientWidget::SelectedColorChangedEvent(const Color &c, bool external) { - float hue, sat; + double hue, sat; c.toHsv(&hue, &sat, &val_); @@ -106,4 +106,4 @@ Color ColorGradientWidget::LerpColor(const Color &a, const Color &b, int i, int lerp(a.blue(), b.blue(), t)); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/colorwheel/colorgradientwidget.h b/app/widget/colorwheel/colorgradientwidget.h index 725b662fe..ae972408e 100644 --- a/app/widget/colorwheel/colorgradientwidget.h +++ b/app/widget/colorwheel/colorgradientwidget.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "colorswatchwidget.h" #include "render/color.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ColorGradientWidget : public ColorSwatchWidget { @@ -50,10 +50,10 @@ private: Color end_; - float val_; + double val_; }; -OLIVE_NAMESPACE_EXIT +} #endif // COLORGRADIENTGLWIDGET_H diff --git a/app/widget/colorwheel/colorpreviewbox.cpp b/app/widget/colorwheel/colorpreviewbox.cpp index d15cfaf06..ad8360649 100644 --- a/app/widget/colorwheel/colorpreviewbox.cpp +++ b/app/widget/colorwheel/colorpreviewbox.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { ColorPreviewBox::ColorPreviewBox(QWidget *parent) : QWidget(parent), @@ -66,4 +66,4 @@ void ColorPreviewBox::paintEvent(QPaintEvent *e) p.drawRect(rect().adjusted(0, 0, -1, -1)); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/colorwheel/colorpreviewbox.h b/app/widget/colorwheel/colorpreviewbox.h index b7078e129..88d50335d 100644 --- a/app/widget/colorwheel/colorpreviewbox.h +++ b/app/widget/colorwheel/colorpreviewbox.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "render/color.h" #include "render/colorprocessor.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ColorPreviewBox : public QWidget { @@ -51,6 +51,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // COLORPREVIEWBOX_H diff --git a/app/widget/colorwheel/colorspacechooser.cpp b/app/widget/colorwheel/colorspacechooser.cpp index 6a0372566..46e98d125 100644 --- a/app/widget/colorwheel/colorspacechooser.cpp +++ b/app/widget/colorwheel/colorspacechooser.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { ColorSpaceChooser::ColorSpaceChooser(ColorManager* color_manager, bool enable_input_field, bool enable_display_fields, QWidget *parent): QGroupBox(parent), @@ -200,4 +200,4 @@ void ColorSpaceChooser::ComboBoxChanged() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/colorwheel/colorspacechooser.h b/app/widget/colorwheel/colorspacechooser.h index eba0db6ce..221dca934 100644 --- a/app/widget/colorwheel/colorspacechooser.h +++ b/app/widget/colorwheel/colorspacechooser.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "render/colormanager.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ColorSpaceChooser : public QGroupBox { @@ -66,6 +66,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // COLORSPACECHOOSER_H diff --git a/app/widget/colorwheel/colorswatchwidget.cpp b/app/widget/colorwheel/colorswatchwidget.cpp index f243e46e2..d0d030b38 100644 --- a/app/widget/colorwheel/colorswatchwidget.cpp +++ b/app/widget/colorwheel/colorswatchwidget.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,9 +22,7 @@ #include -#include "render/backend/opengl/openglrenderfunctions.h" - -OLIVE_NAMESPACE_ENTER +namespace olive { ColorSwatchWidget::ColorSwatchWidget(QWidget *parent) : QWidget(parent), @@ -100,4 +98,4 @@ void ColorSwatchWidget::SetSelectedColorInternal(const Color &c, bool external) update(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/colorwheel/colorswatchwidget.h b/app/widget/colorwheel/colorswatchwidget.h index de8c1a828..ee1d8526e 100644 --- a/app/widget/colorwheel/colorswatchwidget.h +++ b/app/widget/colorwheel/colorswatchwidget.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,11 +23,10 @@ #include -#include "render/backend/opengl/openglshader.h" #include "render/color.h" #include "render/colorprocessor.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ColorSwatchWidget : public QWidget { @@ -69,6 +68,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // COLORSWATCHWIDGET_H diff --git a/app/widget/colorwheel/colorvalueswidget.cpp b/app/widget/colorwheel/colorvalueswidget.cpp index 43b328949..cdb13f5e3 100644 --- a/app/widget/colorwheel/colorvalueswidget.cpp +++ b/app/widget/colorwheel/colorvalueswidget.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { ColorValuesWidget::ColorValuesWidget(ColorManager *manager, QWidget *parent) : QWidget(parent), @@ -213,4 +213,4 @@ void ColorValuesTab::SliderChanged() emit ColorChanged(GetColor()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/colorwheel/colorvalueswidget.h b/app/widget/colorwheel/colorvalueswidget.h index 698900a17..371cbb392 100644 --- a/app/widget/colorwheel/colorvalueswidget.h +++ b/app/widget/colorwheel/colorvalueswidget.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "render/colormanager.h" #include "widget/slider/floatslider.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ColorValuesTab : public QWidget { @@ -110,6 +110,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // COLORVALUESWIDGET_H diff --git a/app/widget/colorwheel/colorwheelwidget.cpp b/app/widget/colorwheel/colorwheelwidget.cpp index 4edf774f3..2e2aa31f4 100644 --- a/app/widget/colorwheel/colorwheelwidget.cpp +++ b/app/widget/colorwheel/colorwheelwidget.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/clamp.h" #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { #define M_180_OVER_PI 57.295791433133264917914229473464 #define M_RADIAN_TO_0_1 0.15915497620314795810531730409296 @@ -121,7 +121,7 @@ void ColorWheelWidget::SelectedColorChangedEvent(const Color &c, bool external) { if (external) { force_redraw_ = true; - val_ = clamp(c.value(), 0.0f, 1.0f); + val_ = clamp(c.value(), 0.0, 1.0); } } @@ -159,7 +159,7 @@ Color ColorWheelWidget::GetColorFromTriangle(const ColorWheelWidget::Triangle &t QPoint ColorWheelWidget::GetCoordsFromColor(const Color &c) const { - float hue, sat, val; + double hue, sat, val; c.toHsv(&hue, &sat, &val); qreal hypotenuse = sat * GetRadius(); @@ -177,4 +177,4 @@ QPoint ColorWheelWidget::GetCoordsFromColor(const Color &c) const return pos; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/colorwheel/colorwheelwidget.h b/app/widget/colorwheel/colorwheelwidget.h index 17c739886..c0d5fc776 100644 --- a/app/widget/colorwheel/colorwheelwidget.h +++ b/app/widget/colorwheel/colorwheelwidget.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,10 +24,9 @@ #include #include "colorswatchwidget.h" -#include "render/backend/opengl/openglshader.h" #include "render/color.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ColorWheelWidget : public ColorSwatchWidget { @@ -72,6 +71,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // COLORWHEELWIDGET_H diff --git a/app/widget/columnedgridlayout/CMakeLists.txt b/app/widget/columnedgridlayout/CMakeLists.txt index c23d2b8d9..ff49ef731 100644 --- a/app/widget/columnedgridlayout/CMakeLists.txt +++ b/app/widget/columnedgridlayout/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/columnedgridlayout/columnedgridlayout.cpp b/app/widget/columnedgridlayout/columnedgridlayout.cpp index 72faf93e7..5db3b0844 100644 --- a/app/widget/columnedgridlayout/columnedgridlayout.cpp +++ b/app/widget/columnedgridlayout/columnedgridlayout.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "columnedgridlayout.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ColumnedGridLayout::ColumnedGridLayout(QWidget* parent, int maximum_columns) : @@ -55,4 +55,4 @@ void ColumnedGridLayout::SetMaximumColumns(int maximum_columns) maximum_columns_ = maximum_columns; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/columnedgridlayout/columnedgridlayout.h b/app/widget/columnedgridlayout/columnedgridlayout.h index 32edb0796..87b50c014 100644 --- a/app/widget/columnedgridlayout/columnedgridlayout.h +++ b/app/widget/columnedgridlayout/columnedgridlayout.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief The ColumnedGridLayout class @@ -48,6 +48,6 @@ private: int maximum_columns_; }; -OLIVE_NAMESPACE_EXIT +} #endif // COLUMNEDGRIDLAYOUT_H diff --git a/app/widget/curvewidget/CMakeLists.txt b/app/widget/curvewidget/CMakeLists.txt index 52cf1cdf6..b6a6a0518 100644 --- a/app/widget/curvewidget/CMakeLists.txt +++ b/app/widget/curvewidget/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/curvewidget/beziercontrolpointitem.cpp b/app/widget/curvewidget/beziercontrolpointitem.cpp index 363ea3aa2..207a92e3e 100644 --- a/app/widget/curvewidget/beziercontrolpointitem.cpp +++ b/app/widget/curvewidget/beziercontrolpointitem.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/qtutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { BezierControlPointItem::BezierControlPointItem(NodeKeyframePtr key, NodeKeyframe::BezierType mode, QGraphicsItem *parent) : QGraphicsRectItem(parent), @@ -47,7 +47,7 @@ BezierControlPointItem::BezierControlPointItem(NodeKeyframePtr key, NodeKeyframe } - int control_point_size = QFontMetricsWidth(qApp->fontMetrics(), "o"); + int control_point_size = QtUtils::QFontMetricsWidth(qApp->fontMetrics(), "o"); int half_sz = control_point_size / 2; setRect(-half_sz, -half_sz, control_point_size, control_point_size); } @@ -103,4 +103,4 @@ void BezierControlPointItem::UpdatePos() setPos(handle_offset - rect().center()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/curvewidget/beziercontrolpointitem.h b/app/widget/curvewidget/beziercontrolpointitem.h index 81ed7302c..6cca33d5a 100644 --- a/app/widget/curvewidget/beziercontrolpointitem.h +++ b/app/widget/curvewidget/beziercontrolpointitem.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "node/keyframe.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class BezierControlPointItem : public QObject, public QGraphicsRectItem { @@ -63,6 +63,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // BEZIERCONTROLPOINTITEM_H diff --git a/app/widget/curvewidget/curveview.cpp b/app/widget/curvewidget/curveview.cpp index a9b43d4a9..e93a8fd3d 100644 --- a/app/widget/curvewidget/curveview.cpp +++ b/app/widget/curvewidget/curveview.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/qtutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { CurveView::CurveView(QWidget *parent) : KeyframeViewBase(parent) @@ -37,9 +37,9 @@ CurveView::CurveView(QWidget *parent) : setViewportUpdateMode(FullViewportUpdate); SetYAxisEnabled(true); - text_padding_ = QFontMetricsWidth(fontMetrics(), QStringLiteral("i")); + text_padding_ = QtUtils::QFontMetricsWidth(fontMetrics(), QStringLiteral("i")); - minimum_grid_space_ = QFontMetricsWidth(fontMetrics(), QStringLiteral("00000")); + minimum_grid_space_ = QtUtils::QFontMetricsWidth(fontMetrics(), QStringLiteral("00000")); connect(scene(), &QGraphicsScene::selectionChanged, this, &CurveView::SelectionChanged); } @@ -89,7 +89,7 @@ void CurveView::ConnectInput(NodeInput *input) void CurveView::DisconnectNode(Node *node) { - QList inputs = node->GetInputsIncludingArrays(); + QVector inputs = node->GetInputsIncludingArrays(); foreach (NodeInput* i, inputs) { DisconnectInput(i); @@ -431,4 +431,4 @@ void CurveView::AddKeyframe(NodeKeyframePtr key) connect(key.get(), &NodeKeyframe::TypeChanged, this, &CurveView::KeyframeTypeChanged); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/curvewidget/curveview.h b/app/widget/curvewidget/curveview.h index 762a015c5..65a82ed52 100644 --- a/app/widget/curvewidget/curveview.h +++ b/app/widget/curvewidget/curveview.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "widget/keyframeview/keyframeview.h" #include "widget/keyframeview/keyframeviewitem.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class CurveView : public KeyframeViewBase { @@ -97,6 +97,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // CURVEVIEW_H diff --git a/app/widget/curvewidget/curvewidget.cpp b/app/widget/curvewidget/curvewidget.cpp index 41d2a88ef..b8dcd1a1d 100644 --- a/app/widget/curvewidget/curvewidget.cpp +++ b/app/widget/curvewidget/curvewidget.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -32,7 +32,7 @@ #include "node/node.h" #include "widget/keyframeview/keyframeviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { CurveWidget::CurveWidget(QWidget *parent) : TimeBasedWidget(parent) @@ -89,7 +89,6 @@ CurveWidget::CurveWidget(QWidget *parent) : ruler_view_layout->addWidget(ruler()); view_ = new CurveView(); - connect(view_, &CurveView::RequestCenterScrollOnPlayhead, this, &CurveWidget::CenterScrollOnPlayhead); ConnectTimelineView(view_); ruler_view_layout->addWidget(view_); @@ -131,7 +130,7 @@ void CurveWidget::DeleteSelected() view_->DeleteSelected(); } -void CurveWidget::SetNodes(const QList &nodes) +void CurveWidget::SetNodes(const QVector &nodes) { tree_view_->SetNodes(nodes); @@ -216,7 +215,7 @@ void CurveWidget::UpdateBridgeTime(const int64_t ×tamp) void CurveWidget::ConnectNode(Node *n) { - QList inputs = n->GetInputsIncludingArrays(); + QVector inputs = n->GetInputsIncludingArrays(); foreach (NodeInput* i, inputs) { if (tree_view_->IsInputEnabled(i)) { @@ -322,4 +321,4 @@ void CurveWidget::InputEnabledChanged(NodeInput *i, bool e) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/curvewidget/curvewidget.h b/app/widget/curvewidget/curvewidget.h index 253ca6a71..127987289 100644 --- a/app/widget/curvewidget/curvewidget.h +++ b/app/widget/curvewidget/curvewidget.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -33,7 +33,7 @@ #include "widget/nodetreeview/nodetreeview.h" #include "widget/timebased/timebased.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class CurveWidget : public TimeBasedWidget, public TimeTargetObject { @@ -49,7 +49,7 @@ public: void DeleteSelected(); public slots: - void SetNodes(const QList& nodes); + void SetNodes(const QVector &nodes); protected: virtual void TimeChangedEvent(const int64_t &) override; @@ -85,9 +85,7 @@ private: NodeParamViewKeyframeControl* key_control_; - QList checkboxes_; - - QList nodes_; + QVector nodes_; private slots: void SelectionChanged(); @@ -102,6 +100,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // CURVEWIDGET_H diff --git a/app/widget/flowlayout/CMakeLists.txt b/app/widget/flowlayout/CMakeLists.txt index fa325df82..c1a99ae30 100644 --- a/app/widget/flowlayout/CMakeLists.txt +++ b/app/widget/flowlayout/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/focusablelineedit/CMakeLists.txt b/app/widget/focusablelineedit/CMakeLists.txt index 7ca836d05..61ec8ac20 100644 --- a/app/widget/focusablelineedit/CMakeLists.txt +++ b/app/widget/focusablelineedit/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/focusablelineedit/focusablelineedit.cpp b/app/widget/focusablelineedit/focusablelineedit.cpp index 6c83e2fe0..ea9c00efe 100644 --- a/app/widget/focusablelineedit/focusablelineedit.cpp +++ b/app/widget/focusablelineedit/focusablelineedit.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { FocusableLineEdit::FocusableLineEdit(QWidget *parent) : QLineEdit(parent) @@ -52,4 +52,4 @@ void FocusableLineEdit::focusOutEvent(QFocusEvent *e) emit Confirmed(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/focusablelineedit/focusablelineedit.h b/app/widget/focusablelineedit/focusablelineedit.h index 07bf57441..a6c2a82b8 100644 --- a/app/widget/focusablelineedit/focusablelineedit.h +++ b/app/widget/focusablelineedit/focusablelineedit.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class FocusableLineEdit : public QLineEdit { @@ -46,6 +46,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // SLIDERLINEEDIT_H diff --git a/app/widget/footagecombobox/CMakeLists.txt b/app/widget/footagecombobox/CMakeLists.txt index e9aab3fcb..2d83039ff 100644 --- a/app/widget/footagecombobox/CMakeLists.txt +++ b/app/widget/footagecombobox/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/footagecombobox/footagecombobox.cpp b/app/widget/footagecombobox/footagecombobox.cpp index 455dd0230..684eeeca2 100644 --- a/app/widget/footagecombobox/footagecombobox.cpp +++ b/app/widget/footagecombobox/footagecombobox.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "ui/icons/icons.h" #include "widget/menu/menu.h" -OLIVE_NAMESPACE_ENTER +namespace olive { FootageComboBox::FootageComboBox(QWidget *parent) : QComboBox(parent), @@ -128,4 +128,4 @@ QString FootageComboBox::FootageToString(Stream *f) return f->description(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/footagecombobox/footagecombobox.h b/app/widget/footagecombobox/footagecombobox.h index e59952069..2d96f4a6f 100644 --- a/app/widget/footagecombobox/footagecombobox.h +++ b/app/widget/footagecombobox/footagecombobox.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "project/item/footage/footage.h" #include "project/project.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class FootageComboBox : public QComboBox { @@ -63,6 +63,6 @@ private: bool only_show_ready_footage_; }; -OLIVE_NAMESPACE_EXIT +} #endif // FOOTAGECOMBOBOX_H diff --git a/app/widget/keyframeview/CMakeLists.txt b/app/widget/keyframeview/CMakeLists.txt index 713f9bb20..77ab1c808 100644 --- a/app/widget/keyframeview/CMakeLists.txt +++ b/app/widget/keyframeview/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/keyframeview/keyframeview.cpp b/app/widget/keyframeview/keyframeview.cpp index 2d6b880e9..dddf30c62 100644 --- a/app/widget/keyframeview/keyframeview.cpp +++ b/app/widget/keyframeview/keyframeview.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "keyframeview.h" -OLIVE_NAMESPACE_ENTER +namespace olive { KeyframeView::KeyframeView(QWidget *parent) : KeyframeViewBase(parent), @@ -52,4 +52,4 @@ void KeyframeView::AddKeyframe(NodeKeyframePtr key, int y) item->SetOverrideY(scene_pt.y()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/keyframeview/keyframeview.h b/app/widget/keyframeview/keyframeview.h index 90361c8e5..5eef3934c 100644 --- a/app/widget/keyframeview/keyframeview.h +++ b/app/widget/keyframeview/keyframeview.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "keyframeviewbase.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class KeyframeView : public KeyframeViewBase { @@ -49,6 +49,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // KEYFRAMEVIEW_H diff --git a/app/widget/keyframeview/keyframeviewbase.cpp b/app/widget/keyframeview/keyframeviewbase.cpp index b53a0c236..7850ada79 100644 --- a/app/widget/keyframeview/keyframeviewbase.cpp +++ b/app/widget/keyframeview/keyframeviewbase.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "widget/menu/menushared.h" #include "widget/nodeparamview/nodeparamviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { KeyframeViewBase::KeyframeViewBase(QWidget *parent) : TimelineViewBase(parent), @@ -76,7 +76,7 @@ void KeyframeViewBase::DeleteSelected() void KeyframeViewBase::RemoveKeyframesOfNode(Node *n) { - QList inputs = n->GetInputsIncludingArrays(); + QVector inputs = n->GetInputsIncludingArrays(); foreach (NodeInput* i, inputs) { RemoveKeyframesOfInput(i); @@ -538,4 +538,4 @@ void KeyframeViewBase::AutoSelectKeyTimeNeighbors() currently_autoselecting_ = false; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/keyframeview/keyframeviewbase.h b/app/widget/keyframeview/keyframeviewbase.h index f25a66937..113a14895 100644 --- a/app/widget/keyframeview/keyframeviewbase.h +++ b/app/widget/keyframeview/keyframeviewbase.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "widget/timelinewidget/view/timelineviewbase.h" #include "widget/timetarget/timetarget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class KeyframeViewBase : public TimelineViewBase, public TimeTargetObject { @@ -105,6 +105,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // KEYFRAMEVIEWBASE_H diff --git a/app/widget/keyframeview/keyframeviewitem.cpp b/app/widget/keyframeview/keyframeviewitem.cpp index c50a42743..783d94544 100644 --- a/app/widget/keyframeview/keyframeviewitem.cpp +++ b/app/widget/keyframeview/keyframeviewitem.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "common/qtutils.h" #include "node/input.h" -OLIVE_NAMESPACE_ENTER +namespace olive { KeyframeViewItem::KeyframeViewItem(NodeKeyframePtr key, QGraphicsItem *parent) : QGraphicsRectItem(parent), @@ -42,7 +42,7 @@ KeyframeViewItem::KeyframeViewItem(NodeKeyframePtr key, QGraphicsItem *parent) : connect(key.get(), &NodeKeyframe::TimeChanged, this, &KeyframeViewItem::UpdatePos); connect(key.get(), &NodeKeyframe::TypeChanged, this, &KeyframeViewItem::Redraw); - int keyframe_size = QFontMetricsWidth(qApp->fontMetrics(), "Oi"); + int keyframe_size = QtUtils::QFontMetricsWidth(qApp->fontMetrics(), "Oi"); int half_sz = keyframe_size/2; setRect(-half_sz, -half_sz, keyframe_size, keyframe_size); @@ -127,4 +127,4 @@ void KeyframeViewItem::Redraw() QGraphicsItem::update(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/keyframeview/keyframeviewitem.h b/app/widget/keyframeview/keyframeviewitem.h index ee5c06031..102da3b61 100644 --- a/app/widget/keyframeview/keyframeviewitem.h +++ b/app/widget/keyframeview/keyframeviewitem.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "node/keyframe.h" #include "widget/timetarget/timetarget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class KeyframeViewItem : public QObject, public QGraphicsRectItem, public TimeTargetObject { @@ -63,6 +63,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // KEYFRAMEVIEWITEM_H diff --git a/app/widget/keyframeview/keyframeviewundo.cpp b/app/widget/keyframeview/keyframeviewundo.cpp index 2ad37e0de..6e286768e 100644 --- a/app/widget/keyframeview/keyframeviewundo.cpp +++ b/app/widget/keyframeview/keyframeviewundo.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "node/node.h" #include "project/item/sequence/sequence.h" -OLIVE_NAMESPACE_ENTER +namespace olive { KeyframeSetTypeCommand::KeyframeSetTypeCommand(NodeKeyframePtr key, NodeKeyframe::Type type, QUndoCommand *parent) : UndoCommand(parent), @@ -82,4 +82,4 @@ void KeyframeSetBezierControlPoint::undo_internal() key_->set_bezier_control(mode_, old_point_); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/keyframeview/keyframeviewundo.h b/app/widget/keyframeview/keyframeviewundo.h index 6c7610866..a6aa322b1 100644 --- a/app/widget/keyframeview/keyframeviewundo.h +++ b/app/widget/keyframeview/keyframeviewundo.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "node/keyframe.h" #include "undo/undocommand.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class KeyframeSetTypeCommand : public UndoCommand { public: @@ -67,6 +67,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // KEYFRAMEVIEWUNDO_H diff --git a/app/widget/manageddisplay/CMakeLists.txt b/app/widget/manageddisplay/CMakeLists.txt index 0f9204b08..cf5ee7887 100644 --- a/app/widget/manageddisplay/CMakeLists.txt +++ b/app/widget/manageddisplay/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/manageddisplay/manageddisplay.cpp b/app/widget/manageddisplay/manageddisplay.cpp index 30574363a..1ac964fd7 100644 --- a/app/widget/manageddisplay/manageddisplay.cpp +++ b/app/widget/manageddisplay/manageddisplay.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,21 +20,63 @@ #include "manageddisplay.h" +#include #include -OLIVE_NAMESPACE_ENTER +#include "render/opengl/openglrenderer.h" +#include "render/rendermanager.h" + +namespace olive { ManagedDisplayWidget::ManagedDisplayWidget(QWidget *parent) : - QOpenGLWidget(parent), + QWidget(parent), color_manager_(nullptr), color_service_(nullptr) { setContextMenuPolicy(Qt::CustomContextMenu); + + QHBoxLayout* layout = new QHBoxLayout(this); + layout->setSpacing(0); + layout->setMargin(0); + + if (RenderManager::instance()->backend() == RenderManager::kOpenGL) { + // Create OpenGL widget + inner_widget_ = new ManagedDisplayWidgetOpenGL(); + connect(static_cast(inner_widget_), + &ManagedDisplayWidgetOpenGL::OnInit, + this, &ManagedDisplayWidget::OnInit, Qt::DirectConnection); + connect(static_cast(inner_widget_), + &ManagedDisplayWidgetOpenGL::OnDestroy, + this, &ManagedDisplayWidget::OnDestroy, Qt::DirectConnection); + connect(static_cast(inner_widget_), + &ManagedDisplayWidgetOpenGL::OnPaint, + this, &ManagedDisplayWidget::OnPaint, Qt::DirectConnection); + connect(static_cast(inner_widget_), + &ManagedDisplayWidgetOpenGL::frameSwapped, + this, &ManagedDisplayWidget::frameSwapped, Qt::DirectConnection); + + connect(static_cast(inner_widget_), + &ManagedDisplayWidgetOpenGL::OnMouseMove, + this, &ManagedDisplayWidget::InnerWidgetMouseMove); + + // Create OpenGL renderer + attached_renderer_ = new OpenGLRenderer(this); + } else { + inner_widget_ = nullptr; + } + + layout->addWidget(inner_widget_); } ManagedDisplayWidget::~ManagedDisplayWidget() { - ContextCleanup(); + OnDestroy(); + + if (RenderManager::instance()->backend() == RenderManager::kOpenGL) { + disconnect(static_cast(inner_widget_), + &ManagedDisplayWidgetOpenGL::OnDestroy, + this, &ManagedDisplayWidget::OnDestroy); + } } void ManagedDisplayWidget::ConnectColorManager(ColorManager *color_manager) @@ -102,20 +144,11 @@ void ManagedDisplayWidget::ColorConfigChanged() SetColorTransform(color_manager_->GetCompliantColorSpace(color_transform_, true)); } -OpenGLColorProcessorPtr ManagedDisplayWidget::color_service() +ColorProcessorPtr ManagedDisplayWidget::color_service() { return color_service_; } -void ManagedDisplayWidget::ContextCleanup() -{ - makeCurrent(); - - color_service_ = nullptr; - - doneCurrent(); -} - void ManagedDisplayWidget::ShowDefaultContextMenu() { Menu m(this); @@ -172,22 +205,28 @@ void ManagedDisplayWidget::MenuColorspaceSelect(QAction *action) SetColorTransform(color_manager()->GetCompliantColorSpace(ColorTransform(action->data().toString()))); } -void ManagedDisplayWidget::SetColorTransform(const ColorTransform &transform) +void ManagedDisplayWidget::OnDestroy() { - makeCurrent(); - - color_transform_ = transform; - SetupColorProcessor(); - ColorProcessorChangedEvent(); - - doneCurrent(); + attached_renderer_->Destroy(); + attached_renderer_->PostDestroy(); } -void ManagedDisplayWidget::initializeGL() +void ManagedDisplayWidget::SetColorTransform(const ColorTransform &transform) { + color_transform_ = transform; + SetupColorProcessor(); - connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ManagedDisplayWidget::ContextCleanup, Qt::DirectConnection); + ColorProcessorChangedEvent(); +} + +void ManagedDisplayWidget::OnInit() +{ + if (RenderManager::instance()->backend() == RenderManager::kOpenGL) { + QOpenGLContext* context = static_cast(inner_widget_)->context(); + static_cast(attached_renderer_)->Init(context); + static_cast(attached_renderer_)->PostInit(); + } } void ManagedDisplayWidget::EnableDefaultContextMenu() @@ -200,6 +239,27 @@ void ManagedDisplayWidget::ColorProcessorChangedEvent() update(); } +void ManagedDisplayWidget::makeCurrent() +{ + if (RenderManager::instance()->backend() == RenderManager::kOpenGL) { + static_cast(inner_widget_)->makeCurrent(); + } +} + +void ManagedDisplayWidget::doneCurrent() +{ + if (RenderManager::instance()->backend() == RenderManager::kOpenGL) { + static_cast(inner_widget_)->doneCurrent(); + } +} + +void ManagedDisplayWidget::update() +{ + if (RenderManager::instance()->backend() == RenderManager::kOpenGL) { + static_cast(inner_widget_)->update(); + } +} + Menu* ManagedDisplayWidget::GetDisplayMenu(QMenu* parent, bool auto_connect) { QStringList displays = color_manager()->ListAvailableDisplays(); @@ -269,37 +329,25 @@ Menu* ManagedDisplayWidget::GetLookMenu(QMenu* parent, bool auto_connect) void ManagedDisplayWidget::SetupColorProcessor() { - if (!context()) { - return; - } - color_service_ = nullptr; if (color_manager_) { // (Re)create color processor - try { - - color_service_ = OpenGLColorProcessor::Create(color_manager_, - color_manager_->GetReferenceColorSpace(), - color_transform_); - - color_service_->Enable(context(), true); - + color_service_ = ColorProcessor::Create(color_manager_, + color_manager_->GetReferenceColorSpace(), + color_transform_); } catch (OCIO::Exception& e) { - QMessageBox::critical(this, tr("OpenColorIO Error"), tr("Failed to set color configuration: %1").arg(e.what()), QMessageBox::Ok); - } - } else { color_service_ = nullptr; } - emit ColorProcessorChanged(std::static_pointer_cast(color_service_)); + emit ColorProcessorChanged(color_service_); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/manageddisplay/manageddisplay.h b/app/widget/manageddisplay/manageddisplay.h index c03d5ea71..4b08dfead 100644 --- a/app/widget/manageddisplay/manageddisplay.h +++ b/app/widget/manageddisplay/manageddisplay.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,15 +21,68 @@ #ifndef MANAGEDDISPLAYOBJECT_H #define MANAGEDDISPLAYOBJECT_H +#include +#include #include -#include "render/backend/opengl/openglcolorprocessor.h" #include "render/colormanager.h" +#include "render/renderer.h" #include "widget/menu/menu.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -class ManagedDisplayWidget : public QOpenGLWidget +class ManagedDisplayWidgetOpenGL : public QOpenGLWidget +{ + Q_OBJECT +public: + ManagedDisplayWidgetOpenGL(QWidget* parent = nullptr) : + QOpenGLWidget(parent) + { + } + +signals: + void OnInit(); + + void OnPaint(); + + void OnDestroy(); + + void OnMouseMove(QMouseEvent* e); + +protected: + virtual void initializeGL() override + { + connect(context(), &QOpenGLContext::aboutToBeDestroyed, + this, &ManagedDisplayWidgetOpenGL::OnDestroy); + + emit OnInit(); + } + + virtual void paintGL() override + { + emit OnPaint(); + } + + virtual void mouseMoveEvent(QMouseEvent* e) override + { + emit OnMouseMove(e); + + QOpenGLWidget::mouseMoveEvent(e); + } + +private slots: + void DestroyListener() + { + makeCurrent(); + + emit OnDestroy(); + + doneCurrent(); + } + +}; + +class ManagedDisplayWidget : public QWidget { Q_OBJECT public: @@ -72,6 +125,11 @@ public: */ Menu* GetLookMenu(QMenu* parent, bool auto_connect = true); + /** + * @brief Passes update signal through to inner widget + */ + void update(); + public slots: /** * @brief Replaces the color transform with a new one @@ -94,16 +152,15 @@ signals: */ void ColorManagerChanged(ColorManager* color_manager); + void frameSwapped(); + + void InnerWidgetMouseMove(QMouseEvent* event); + protected: /** * @brief Provides access to the color processor (nullptr if none is set) */ - OpenGLColorProcessorPtr color_service(); - - /** - * @brief Override when setting up OpenGL context - */ - virtual void initializeGL() override; + ColorProcessorPtr color_service(); /** * @brief Enables a context menu that allows simple access to the DVL pipeline @@ -117,6 +174,36 @@ protected: */ virtual void ColorProcessorChangedEvent(); + Renderer* renderer() const + { + return attached_renderer_; + } + + void makeCurrent(); + + void doneCurrent(); + + QWidget* inner_widget() const + { + return inner_widget_; + } + +protected slots: + /** + * @brief Called whenever the internal rendering context has been created + */ + virtual void OnInit(); + + /** + * @brief Called while the internal rendering context is being rendered + */ + virtual void OnPaint() = 0; + + /** + * @brief Called just before the internal rendering context is destroyed + */ + virtual void OnDestroy(); + private: /** * @brief Call this if this user has selected a different display/view/look to recreate the processor @@ -128,6 +215,16 @@ private: */ void ClearOCIOLutTexture(); + /** + * @brief Main drawing surface abstraction + */ + QWidget* inner_widget_; + + /** + * @brief Renderer abstraction + */ + Renderer* attached_renderer_; + /** * @brief Connected color manager */ @@ -136,7 +233,7 @@ private: /** * @brief Color management service */ - OpenGLColorProcessorPtr color_service_; + ColorProcessorPtr color_service_; /** * @brief Internal color transform storage @@ -149,11 +246,6 @@ private slots: */ void ColorConfigChanged(); - /** - * @brief Cleans up resources if context is about to be destroyed - */ - void ContextCleanup(); - /** * @brief The default context menu shown */ @@ -181,6 +273,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // MANAGEDDISPLAYOBJECT_H diff --git a/app/widget/menu/CMakeLists.txt b/app/widget/menu/CMakeLists.txt index 60470a2b5..c1281270b 100644 --- a/app/widget/menu/CMakeLists.txt +++ b/app/widget/menu/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/menu/menu.cpp b/app/widget/menu/menu.cpp index 9de1136f5..55e4c762d 100644 --- a/app/widget/menu/menu.cpp +++ b/app/widget/menu/menu.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "ui/style/style.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Menu::Menu(QMenuBar *bar) { @@ -111,4 +111,4 @@ void Menu::Init() StyleManager::UseOSNativeStyling(this); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/menu/menu.h b/app/widget/menu/menu.h index 142753402..6dafb99f1 100644 --- a/app/widget/menu/menu.h +++ b/app/widget/menu/menu.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A menu widget for context menus and menu bars @@ -237,6 +237,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // WIDGETMENU_H diff --git a/app/widget/menu/menushared.cpp b/app/widget/menu/menushared.cpp index a63e22fb3..9701ec9a6 100644 --- a/app/widget/menu/menushared.cpp +++ b/app/widget/menu/menushared.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "panel/panelmanager.h" #include "panel/timeline/timeline.h" -OLIVE_NAMESPACE_ENTER +namespace olive { MenuShared* MenuShared::instance_ = nullptr; @@ -309,4 +309,4 @@ void MenuShared::Retranslate() view_timecode_view_seconds_item_->setText(tr("Seconds")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/menu/menushared.h b/app/widget/menu/menushared.h index 414be8985..60d0b6989 100644 --- a/app/widget/menu/menushared.h +++ b/app/widget/menu/menushared.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "widget/menu/menu.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A static object that provides various "stock" menus for use throughout the application @@ -132,6 +132,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // MENUSHARED_H diff --git a/app/widget/nodecombobox/CMakeLists.txt b/app/widget/nodecombobox/CMakeLists.txt index 56a597688..c8d0dd535 100644 --- a/app/widget/nodecombobox/CMakeLists.txt +++ b/app/widget/nodecombobox/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/nodecombobox/nodecombobox.cpp b/app/widget/nodecombobox/nodecombobox.cpp index 89e1dfeda..d8d23c91a 100644 --- a/app/widget/nodecombobox/nodecombobox.cpp +++ b/app/widget/nodecombobox/nodecombobox.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "ui/icons/icons.h" #include "widget/menu/menu.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeComboBox::NodeComboBox(QWidget *parent) : QComboBox(parent) @@ -90,4 +90,4 @@ void NodeComboBox::SetNodeInternal(const QString &id, bool emit_signal) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodecombobox/nodecombobox.h b/app/widget/nodecombobox/nodecombobox.h index cadad971c..dbdb8cf16 100644 --- a/app/widget/nodecombobox/nodecombobox.h +++ b/app/widget/nodecombobox/nodecombobox.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeComboBox : public QComboBox { @@ -55,6 +55,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // FOOTAGECOMBOBOX_H diff --git a/app/widget/nodecopypaste/CMakeLists.txt b/app/widget/nodecopypaste/CMakeLists.txt index 5d21f27d8..808abbac5 100644 --- a/app/widget/nodecopypaste/CMakeLists.txt +++ b/app/widget/nodecopypaste/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/nodecopypaste/nodecopypaste.cpp b/app/widget/nodecopypaste/nodecopypaste.cpp index 914e9f32c..ccc6c235a 100644 --- a/app/widget/nodecopypaste/nodecopypaste.cpp +++ b/app/widget/nodecopypaste/nodecopypaste.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,9 +27,9 @@ #include "widget/nodeview/nodeviewundo.h" #include "window/mainwindow/mainwindow.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -void NodeCopyPasteWidget::CopyNodesToClipboard(const QList &nodes, void *userdata) +void NodeCopyPasteWidget::CopyNodesToClipboard(const QVector &nodes, void *userdata) { QString copy_str; @@ -56,17 +56,17 @@ void NodeCopyPasteWidget::CopyNodesToClipboard(const QList &nodes, void Core::CopyStringToClipboard(copy_str); } -QList NodeCopyPasteWidget::PasteNodesFromClipboard(Sequence *graph, QUndoCommand* command, void *userdata) +QVector NodeCopyPasteWidget::PasteNodesFromClipboard(Sequence *graph, QUndoCommand* command, void *userdata) { QString clipboard = Core::PasteStringFromClipboard(); if (clipboard.isEmpty()) { - return QList(); + return QVector(); } QXmlStreamReader reader(clipboard); - QList pasted_nodes; + QVector pasted_nodes; XMLNodeData xml_node_data; while (XMLReadNextStartElement(&reader)) { @@ -100,7 +100,7 @@ QList NodeCopyPasteWidget::PasteNodesFromClipboard(Sequence *graph, QUnd if (pasted_nodes.isEmpty()) { // If we passed through the whole string and there were no nodes, it must not be data for us after all - return QList(); + return QVector(); } // If we have some nodes AND the XML data was malformed, the user should probably know @@ -116,7 +116,7 @@ QList NodeCopyPasteWidget::PasteNodesFromClipboard(Sequence *graph, QUnd QCoreApplication::translate("NodeCopyPasteWidget", "Failed to paste nodes: %1").arg(reader.errorString()), QMessageBox::Ok); - return QList(); + return QVector(); } // Add all nodes to graph @@ -177,4 +177,4 @@ void NodeCopyPasteWidget::PasteNodesFromClipboardInternal(QXmlStreamReader* read reader->skipCurrentElement(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodecopypaste/nodecopypaste.h b/app/widget/nodecopypaste/nodecopypaste.h index 9791ae99f..00b7c30a0 100644 --- a/app/widget/nodecopypaste/nodecopypaste.h +++ b/app/widget/nodecopypaste/nodecopypaste.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "node/node.h" #include "project/item/sequence/sequence.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeCopyPasteWidget { @@ -35,9 +35,9 @@ public: NodeCopyPasteWidget() = default; protected: - void CopyNodesToClipboard(const QList& nodes, void* userdata = nullptr); + void CopyNodesToClipboard(const QVector &nodes, void* userdata = nullptr); - QList PasteNodesFromClipboard(Sequence *graph, QUndoCommand *command, void* userdata = nullptr); + QVector PasteNodesFromClipboard(Sequence *graph, QUndoCommand *command, void* userdata = nullptr); virtual void CopyNodesToClipboardInternal(QXmlStreamWriter *writer, void* userdata); @@ -45,6 +45,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODECOPYPASTEWIDGET_H diff --git a/app/widget/nodeparamview/CMakeLists.txt b/app/widget/nodeparamview/CMakeLists.txt index 9bac86e5a..bf423e224 100644 --- a/app/widget/nodeparamview/CMakeLists.txt +++ b/app/widget/nodeparamview/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/nodeparamview/nodeparamview.cpp b/app/widget/nodeparamview/nodeparamview.cpp index b07031ea6..597ef7d61 100644 --- a/app/widget/nodeparamview/nodeparamview.cpp +++ b/app/widget/nodeparamview/nodeparamview.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "common/timecodefunctions.h" #include "node/output/viewer/viewer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeParamView::NodeParamView(QWidget *parent) : TimeBasedWidget(true, false, parent), @@ -85,7 +85,6 @@ NodeParamView::NodeParamView(QWidget *parent) : keyframe_view_ = new KeyframeView(); keyframe_view_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ConnectTimelineView(keyframe_view_); - connect(keyframe_view_, &KeyframeView::RequestCenterScrollOnPlayhead, this, &NodeParamView::CenterScrollOnPlayhead); keyframe_area_layout->addWidget(keyframe_view_); // Connect ruler and keyframe view together @@ -135,7 +134,7 @@ NodeParamView::NodeParamView(QWidget *parent) : &NodeParamView::FocusChanged); } -void NodeParamView::SelectNodes(const QList &nodes) +void NodeParamView::SelectNodes(const QVector &nodes) { active_nodes_.append(nodes); @@ -185,7 +184,7 @@ void NodeParamView::SelectNodes(const QList &nodes) } } -void NodeParamView::DeselectNodes(const QList &nodes) +void NodeParamView::DeselectNodes(const QVector &nodes) { // Remove item from map and delete the widget bool changes_made = false; @@ -283,8 +282,8 @@ void NodeParamView::QueueKeyframePositionUpdate() void NodeParamView::SignalNodeOrder() { // Sort by item Y (apparently there's no way in Qt to get the order of dock widgets) - QList nodes; - QList item_ys; + QVector nodes; + QVector item_ys; for (auto it=items_.cbegin(); it!=items_.cend(); it++) { int item_y = it.value()->pos().y(); @@ -389,4 +388,4 @@ void NodeParamView::FocusChanged(QWidget* old, QWidget* now) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodeparamview/nodeparamview.h b/app/widget/nodeparamview/nodeparamview.h index f9fee45db..1bbefbf52 100644 --- a/app/widget/nodeparamview/nodeparamview.h +++ b/app/widget/nodeparamview/nodeparamview.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "widget/keyframeview/keyframeview.h" #include "widget/timebased/timebased.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeParamViewParamContainer : public QWidget { @@ -60,8 +60,8 @@ class NodeParamView : public TimeBasedWidget public: NodeParamView(QWidget* parent = nullptr); - void SelectNodes(const QList& nodes); - void DeselectNodes(const QList& nodes); + void SelectNodes(const QVector &nodes); + void DeselectNodes(const QVector& nodes); const QMap& GetItemMap() const { @@ -75,9 +75,9 @@ public: signals: void InputDoubleClicked(NodeInput* input); - void RequestSelectNode(const QList& target); + void RequestSelectNode(const QVector& target); - void NodeOrderChanged(const QList& nodes); + void NodeOrderChanged(const QVector& nodes); void FocusedNodeChanged(Node* n); @@ -113,9 +113,9 @@ private: // docking windows QMainWindow* param_widget_area_; - QList pinned_nodes_; + QVector pinned_nodes_; - QList active_nodes_; + QVector active_nodes_; QMap node_expanded_state_; @@ -134,6 +134,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEPARAMVIEW_H diff --git a/app/widget/nodeparamview/nodeparamviewarraywidget.cpp b/app/widget/nodeparamview/nodeparamviewarraywidget.cpp index 3e6df5614..dcbcb8e18 100644 --- a/app/widget/nodeparamview/nodeparamviewarraywidget.cpp +++ b/app/widget/nodeparamview/nodeparamviewarraywidget.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { NodeParamViewArrayWidget::NodeParamViewArrayWidget(NodeInputArray* array, QWidget* parent) : QWidget(parent), @@ -47,7 +47,7 @@ NodeParamViewArrayWidget::NodeParamViewArrayWidget(NodeInputArray* array, QWidge void NodeParamViewArrayWidget::UpdateCounter() { - count_lbl_->setText(tr("%1 elements").arg(array_->GetSize())); + count_lbl_->setText(tr("%1 element(s)").arg(array_->GetSize())); } void NodeParamViewArrayWidget::AddElement() @@ -55,4 +55,4 @@ void NodeParamViewArrayWidget::AddElement() array_->Append(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodeparamview/nodeparamviewarraywidget.h b/app/widget/nodeparamview/nodeparamviewarraywidget.h index e99455140..1582f497d 100644 --- a/app/widget/nodeparamview/nodeparamviewarraywidget.h +++ b/app/widget/nodeparamview/nodeparamviewarraywidget.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "node/inputarray.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeParamViewArrayWidget : public QWidget { @@ -49,6 +49,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEPARAMVIEWARRAYWIDGET_H diff --git a/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp b/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp index 43507cac6..fba601f93 100644 --- a/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp +++ b/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,14 +28,14 @@ #include "widget/menu/menu.h" #include "widget/nodeview/nodeviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeParamViewConnectedLabel::NodeParamViewConnectedLabel(NodeInput *input, QWidget *parent) : QWidget(parent), input_(input) { QHBoxLayout* layout = new QHBoxLayout(this); - layout->setSpacing(QFontMetricsWidth(fontMetrics(), QStringLiteral(" "))); + layout->setSpacing(QtUtils::QFontMetricsWidth(fontMetrics(), QStringLiteral(" "))); layout->setMargin(0); layout->addWidget(new QLabel(tr("Connected to"))); @@ -86,4 +86,4 @@ void NodeParamViewConnectedLabel::ShowLabelContextMenu() m.exec(QCursor::pos()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodeparamview/nodeparamviewconnectedlabel.h b/app/widget/nodeparamview/nodeparamviewconnectedlabel.h index 04103cae1..ffec58ecc 100644 --- a/app/widget/nodeparamview/nodeparamviewconnectedlabel.h +++ b/app/widget/nodeparamview/nodeparamviewconnectedlabel.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "node/input.h" #include "widget/clickablelabel/clickablelabel.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeParamViewConnectedLabel : public QWidget { Q_OBJECT @@ -46,6 +46,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEPARAMVIEWCONNECTEDLABEL_H diff --git a/app/widget/nodeparamview/nodeparamviewitem.cpp b/app/widget/nodeparamview/nodeparamviewitem.cpp index 0f5a88e67..8261d3720 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.cpp +++ b/app/widget/nodeparamview/nodeparamviewitem.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,7 +29,7 @@ #include "nodeparamviewundo.h" #include "project/item/sequence/sequence.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeParamViewItem::NodeParamViewItem(Node *node, QWidget *parent) : QDockWidget(parent), @@ -459,4 +459,4 @@ NodeParamViewItemBody::InputUI::InputUI() : { } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodeparamview/nodeparamviewitem.h b/app/widget/nodeparamview/nodeparamviewitem.h index 2bc8972fa..a71b46359 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.h +++ b/app/widget/nodeparamview/nodeparamviewitem.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -35,7 +35,7 @@ #include "widget/clickablelabel/clickablelabel.h" #include "widget/collapsebutton/collapsebutton.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeParamViewItemTitleBar : public QWidget { @@ -91,7 +91,7 @@ signals: void InputDoubleClicked(NodeInput* input); - void RequestSelectNode(const QList& node); + void RequestSelectNode(const QVector& node); private: void UpdateUIForEdgeConnection(NodeInput* input); @@ -161,7 +161,7 @@ signals: void InputDoubleClicked(NodeInput* input); - void RequestSelectNode(const QList& node); + void RequestSelectNode(const QVector& node); void PinToggled(bool e); @@ -186,6 +186,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEPARAMVIEWITEM_H diff --git a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp index 6c9e1306f..6e5e3e7ab 100644 --- a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp +++ b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "nodeparamviewundo.h" #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeParamViewKeyframeControl::NodeParamViewKeyframeControl(bool right_align, QWidget *parent) : QWidget(parent), @@ -277,4 +277,4 @@ void NodeParamViewKeyframeControl::KeyframeEnableChanged(bool e) Core::instance()->undo_stack()->pushIfHasChildren(command); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h index 002b00fc5..1a22a24c3 100644 --- a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h +++ b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "node/input.h" #include "widget/timetarget/timetarget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeParamViewKeyframeControl : public QWidget, public TimeTargetObject { @@ -77,6 +77,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEPARAMVIEWKEYFRAMECONTROL_H diff --git a/app/widget/nodeparamview/nodeparamviewrichtext.cpp b/app/widget/nodeparamview/nodeparamviewrichtext.cpp index 476c7cc76..1d122b68e 100644 --- a/app/widget/nodeparamview/nodeparamviewrichtext.cpp +++ b/app/widget/nodeparamview/nodeparamviewrichtext.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "dialog/richtext/richtext.h" #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeParamViewRichText::NodeParamViewRichText(QWidget *parent) : QWidget(parent) @@ -34,19 +34,21 @@ NodeParamViewRichText::NodeParamViewRichText(QWidget *parent) : QHBoxLayout* layout = new QHBoxLayout(this); layout->setMargin(0); - line_edit_ = new QLineEdit(); - connect(line_edit_, &QLineEdit::textEdited, this, &NodeParamViewRichText::textEdited); + line_edit_ = new QTextEdit(); + line_edit_->setUndoRedoEnabled(true); + connect(line_edit_, &QTextEdit::textChanged, this, &NodeParamViewRichText::InnerWidgetTextChanged); layout->addWidget(line_edit_); QPushButton* edit_btn = new QPushButton(); edit_btn->setIcon(icon::ToolEdit); + edit_btn->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); layout->addWidget(edit_btn); connect(edit_btn, &QPushButton::clicked, this, &NodeParamViewRichText::ShowRichTextDialog); } void NodeParamViewRichText::ShowRichTextDialog() { - RichTextDialog d(line_edit_->text(), this); + RichTextDialog d(this->text(), this); if (d.exec() == QDialog::Accepted) { QString s = d.text(); @@ -55,4 +57,9 @@ void NodeParamViewRichText::ShowRichTextDialog() } } -OLIVE_NAMESPACE_EXIT +void NodeParamViewRichText::InnerWidgetTextChanged() +{ + emit textEdited(this->text()); +} + +} diff --git a/app/widget/nodeparamview/nodeparamviewrichtext.h b/app/widget/nodeparamview/nodeparamviewrichtext.h index 974a742b4..28cae7200 100644 --- a/app/widget/nodeparamview/nodeparamviewrichtext.h +++ b/app/widget/nodeparamview/nodeparamviewrichtext.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,12 +21,12 @@ #ifndef NODEPARAMVIEWRICHTEXT_H #define NODEPARAMVIEWRICHTEXT_H -#include +#include #include #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeParamViewRichText : public QWidget { @@ -36,33 +36,44 @@ public: QString text() const { - return line_edit_->text(); + return line_edit_->toPlainText().replace('\n', QStringLiteral("
")); } public slots: - void setText(const QString &s) + void setText(QString s) { - line_edit_->setText(s); + line_edit_->blockSignals(true); + line_edit_->setPlainText(s.replace(QStringLiteral("
"), QStringLiteral("\n"))); + line_edit_->blockSignals(false); } void setTextPreservingCursor(const QString &s) { - int cursor_pos = line_edit_->cursorPosition(); - line_edit_->setText(s); - line_edit_->setCursorPosition(cursor_pos); + // Save cursor position + int cursor_pos = line_edit_->textCursor().position(); + + // Set text + this->setText(s); + + // Get new text cursor + QTextCursor c = line_edit_->textCursor(); + c.setPosition(cursor_pos); + line_edit_->setTextCursor(c); } signals: void textEdited(const QString &); private: - QLineEdit* line_edit_; + QTextEdit* line_edit_; private slots: void ShowRichTextDialog(); + void InnerWidgetTextChanged(); + }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEPARAMVIEWRICHTEXT_H diff --git a/app/widget/nodeparamview/nodeparamviewundo.cpp b/app/widget/nodeparamview/nodeparamviewundo.cpp index ad55dd256..7a02391af 100644 --- a/app/widget/nodeparamview/nodeparamviewundo.cpp +++ b/app/widget/nodeparamview/nodeparamviewundo.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "node/node.h" #include "project/item/sequence/sequence.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeParamSetKeyframingCommand::NodeParamSetKeyframingCommand(NodeInput *input, bool setting, QUndoCommand *parent) : UndoCommand(parent), @@ -200,4 +200,4 @@ void NodeParamSetStandardValueCommand::undo_internal() input_->set_standard_value(old_value_, track_); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodeparamview/nodeparamviewundo.h b/app/widget/nodeparamview/nodeparamviewundo.h index 2ce5b5150..07d190a83 100644 --- a/app/widget/nodeparamview/nodeparamviewundo.h +++ b/app/widget/nodeparamview/nodeparamviewundo.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "node/input.h" #include "undo/undocommand.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeParamSetKeyframingCommand : public UndoCommand { public: @@ -136,6 +136,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEPARAMVIEWUNDO_H diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index 456323238..59559d5c4 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -38,7 +38,7 @@ #include "widget/slider/floatslider.h" #include "widget/slider/integerslider.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeParamViewWidgetBridge::NodeParamViewWidgetBridge(NodeInput *input, QObject *parent) : QObject(parent), @@ -180,14 +180,17 @@ void NodeParamViewWidgetBridge::CreateWidgets() } // Check all properties - QHash::const_iterator iterator; - - for (iterator=input_->properties().begin();iterator!=input_->properties().end();iterator++) { - PropertyChanged(iterator.key(), iterator.value()); + foreach (const QByteArray& key, input_->dynamicPropertyNames()) { + PropertyChanged(key, input_->property(key)); } UpdateWidgetValues(); + // Install event filter to disable widgets picking up scroll events + foreach (QWidget* w, widgets_) { + w->installEventFilter(&scroll_filter_); + } + } } @@ -276,7 +279,9 @@ void NodeParamViewWidgetBridge::WidgetCallback() // Widget is a IntegerSlider IntegerSlider* slider = static_cast(sender()); - ProcessSlider(slider, QVariant::fromValue(slider->GetValue())); + int64_t offset = input_->property("offset").toLongLong(); + + ProcessSlider(slider, QVariant::fromValue(slider->GetValue() - offset)); break; } case NodeParam::kFloat: @@ -284,7 +289,9 @@ void NodeParamViewWidgetBridge::WidgetCallback() // Widget is a FloatSlider FloatSlider* slider = static_cast(sender()); - ProcessSlider(slider, slider->GetValue()); + double offset = input_->property("offset").toDouble(); + + ProcessSlider(slider, slider->GetValue() - offset); break; } case NodeParam::kVec2: @@ -292,7 +299,9 @@ void NodeParamViewWidgetBridge::WidgetCallback() // Widget is a FloatSlider FloatSlider* slider = static_cast(sender()); - ProcessSlider(slider, slider->GetValue()); + QVector2D offset = input_->property("offset").value(); + + ProcessSlider(slider, slider->GetValue() - offset[widgets_.indexOf(slider)]); break; } case NodeParam::kVec3: @@ -300,7 +309,9 @@ void NodeParamViewWidgetBridge::WidgetCallback() // Widget is a FloatSlider FloatSlider* slider = static_cast(sender()); - ProcessSlider(slider, slider->GetValue()); + QVector3D offset = input_->property("offset").value(); + + ProcessSlider(slider, slider->GetValue() - offset[widgets_.indexOf(slider)]); break; } case NodeParam::kVec4: @@ -308,7 +319,9 @@ void NodeParamViewWidgetBridge::WidgetCallback() // Widget is a FloatSlider FloatSlider* slider = static_cast(sender()); - ProcessSlider(slider, slider->GetValue()); + QVector4D offset = input_->property("offset").value(); + + ProcessSlider(slider, slider->GetValue() - offset[widgets_.indexOf(slider)]); break; } case NodeParam::kFile: @@ -327,10 +340,10 @@ void NodeParamViewWidgetBridge::WidgetCallback() SetInputValueInternal(c.alpha(), 3, command); input_->blockSignals(true); - input_->set_property(QStringLiteral("col_input"), c.color_input()); - input_->set_property(QStringLiteral("col_display"), c.color_output().display()); - input_->set_property(QStringLiteral("col_view"), c.color_output().view()); - input_->set_property(QStringLiteral("col_look"), c.color_output().look()); + input_->setProperty("col_input", c.color_input()); + input_->setProperty("col_display", c.color_output().display()); + input_->setProperty("col_view", c.color_output().view()); + input_->setProperty("col_look", c.color_output().look()); input_->blockSignals(false); Core::instance()->undo_stack()->pushIfHasChildren(command); @@ -417,36 +430,47 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues() case NodeParam::kVector: break; case NodeParam::kInt: - static_cast(widgets_.first())->SetValue(input_->get_value_at_time(node_time).toLongLong()); + { + int64_t offset = input_->property("offset").toLongLong(); + + static_cast(widgets_.first())->SetValue(input_->get_value_at_time(node_time).toLongLong() + offset); break; + } case NodeParam::kFloat: - static_cast(widgets_.first())->SetValue(input_->get_value_at_time(node_time).toDouble()); + { + double offset = input_->property("offset").toDouble(); + + static_cast(widgets_.first())->SetValue(input_->get_value_at_time(node_time).toDouble() + offset); break; + } case NodeParam::kVec2: { QVector2D vec2 = input_->get_value_at_time(node_time).value(); + QVector2D offset = input_->property("offset").value(); - static_cast(widgets_.at(0))->SetValue(static_cast(vec2.x())); - static_cast(widgets_.at(1))->SetValue(static_cast(vec2.y())); + static_cast(widgets_.at(0))->SetValue(static_cast(vec2.x() + offset.x())); + static_cast(widgets_.at(1))->SetValue(static_cast(vec2.y() + offset.y())); break; } case NodeParam::kVec3: { QVector3D vec3 = input_->get_value_at_time(node_time).value(); + QVector3D offset = input_->property("offset").value(); - static_cast(widgets_.at(0))->SetValue(static_cast(vec3.x())); - static_cast(widgets_.at(1))->SetValue(static_cast(vec3.y())); - static_cast(widgets_.at(2))->SetValue(static_cast(vec3.z())); + static_cast(widgets_.at(0))->SetValue(static_cast(vec3.x() + offset.x())); + static_cast(widgets_.at(1))->SetValue(static_cast(vec3.y() + offset.y())); + static_cast(widgets_.at(2))->SetValue(static_cast(vec3.z() + offset.z())); break; } case NodeParam::kVec4: { QVector4D vec4 = input_->get_value_at_time(node_time).value(); + QVector4D offset = input_->property("offset").value(); - static_cast(widgets_.at(0))->SetValue(static_cast(vec4.x())); - static_cast(widgets_.at(1))->SetValue(static_cast(vec4.y())); - static_cast(widgets_.at(2))->SetValue(static_cast(vec4.z())); - static_cast(widgets_.at(3))->SetValue(static_cast(vec4.w())); + static_cast(widgets_.at(0))->SetValue(static_cast(vec4.x() + offset.x())); + static_cast(widgets_.at(1))->SetValue(static_cast(vec4.y() + offset.y())); + static_cast(widgets_.at(2))->SetValue(static_cast(vec4.z() + offset.z())); + static_cast(widgets_.at(3))->SetValue(static_cast(vec4.w() + offset.w())); break; } case NodeParam::kFile: @@ -456,11 +480,11 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues() { ManagedColor mc = input_->get_value_at_time(node_time).value(); - mc.set_color_input(input_->get_property(QStringLiteral("col_input")).toString()); + mc.set_color_input(input_->property("col_input").toString()); - QString d = input_->get_property(QStringLiteral("col_display")).toString(); - QString v = input_->get_property(QStringLiteral("col_view")).toString(); - QString l = input_->get_property(QStringLiteral("col_look")).toString(); + QString d = input_->property("col_display").toString(); + QString v = input_->property("col_view").toString(); + QString l = input_->property("col_look").toString(); mc.set_color_output(ColorTransform(d, v, l)); @@ -604,6 +628,8 @@ void NodeParamViewWidgetBridge::PropertyChanged(const QString &key, const QVaria default: break; } + } else if (key == QStringLiteral("offset")) { + UpdateWidgetValues(); } } @@ -671,4 +697,16 @@ void NodeParamViewWidgetBridge::PropertyChanged(const QString &key, const QVaria } } -OLIVE_NAMESPACE_EXIT +bool NodeParamViewScrollBlocker::eventFilter(QObject *watched, QEvent *event) +{ + Q_UNUSED(watched) + + if (event->type() == QEvent::Wheel) { + // Block this event + return true; + } + + return false; +} + +} diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h index 245a03171..7704229d2 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,14 @@ #include "widget/slider/sliderbase.h" #include "widget/timetarget/timetarget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { + +class NodeParamViewScrollBlocker : public QObject +{ + Q_OBJECT +public: + virtual bool eventFilter(QObject* watched, QEvent* event) override; +}; class NodeParamViewWidgetBridge : public QObject, public TimeTargetObject { @@ -63,6 +70,8 @@ private: NodeInputDragger dragger_; + NodeParamViewScrollBlocker scroll_filter_; + private slots: void WidgetCallback(); @@ -72,6 +81,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEPARAMVIEWWIDGETBRIDGE_H diff --git a/app/widget/nodetableview/CMakeLists.txt b/app/widget/nodetableview/CMakeLists.txt index f12dff040..cb717d998 100644 --- a/app/widget/nodetableview/CMakeLists.txt +++ b/app/widget/nodetableview/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/nodetableview/nodetabletraverser.cpp b/app/widget/nodetableview/nodetabletraverser.cpp index 156409224..cd94ee5f8 100644 --- a/app/widget/nodetableview/nodetabletraverser.cpp +++ b/app/widget/nodetableview/nodetabletraverser.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "nodetabletraverser.h" -OLIVE_NAMESPACE_ENTER +namespace olive { QVariant NodeTableTraverser::ProcessVideoFootage(StreamPtr stream, const rational &input_time) { @@ -30,6 +30,7 @@ QVariant NodeTableTraverser::ProcessVideoFootage(StreamPtr stream, const rationa video_stream->height(), video_stream->timebase(), video_stream->format(), + video_stream->channel_count(), video_stream->pixel_aspect_ratio())); } @@ -39,7 +40,7 @@ QVariant NodeTableTraverser::ProcessAudioFootage(StreamPtr stream, const TimeRan return QVariant::fromValue(AudioParams(audio_stream->sample_rate(), audio_stream->channel_layout(), - SampleFormat::kInternalFormat)); + AudioParams::kInternalFormat)); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodetableview/nodetabletraverser.h b/app/widget/nodetableview/nodetabletraverser.h index 20dae8e2e..dbfc531cd 100644 --- a/app/widget/nodetableview/nodetabletraverser.h +++ b/app/widget/nodetableview/nodetabletraverser.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "node/traverser.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeTableTraverser : public NodeTraverser { @@ -37,6 +37,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODETABLETRAVERSER_H diff --git a/app/widget/nodetableview/nodetableview.cpp b/app/widget/nodetableview/nodetableview.cpp index 7696ace3b..90afc94af 100644 --- a/app/widget/nodetableview/nodetableview.cpp +++ b/app/widget/nodetableview/nodetableview.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "node/param.h" #include "nodetabletraverser.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeTableView::NodeTableView(QWidget* parent) : QTreeWidget(parent) @@ -40,7 +40,7 @@ NodeTableView::NodeTableView(QWidget* parent) : tr("A/W")}); } -void NodeTableView::SelectNodes(const QList &nodes) +void NodeTableView::SelectNodes(const QVector &nodes) { foreach (Node* n, nodes) { QTreeWidgetItem* top_item = new QTreeWidgetItem(); @@ -53,7 +53,7 @@ void NodeTableView::SelectNodes(const QList &nodes) SetTime(last_time_); } -void NodeTableView::DeselectNodes(const QList &nodes) +void NodeTableView::DeselectNodes(const QVector &nodes) { foreach (Node* n, nodes) { delete top_level_item_map_.take(n); @@ -145,10 +145,7 @@ void NodeTableView::SetTime(const rational &time) case NodeParam::kTexture: { // NodeTableTraverser puts video params in here - VideoParams p = value.data().value(); - int channel_count = PixelFormat::ChannelCount(p.format()); - - for (int k=0;ksetItemWidget(sub_item, 2 + k, new QCheckBox()); } break; @@ -263,4 +260,4 @@ void NodeTableView::SetNode(Node *n, const rational &time) } */ -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodetableview/nodetableview.h b/app/widget/nodetableview/nodetableview.h index 7aa6e3eeb..49e768740 100644 --- a/app/widget/nodetableview/nodetableview.h +++ b/app/widget/nodetableview/nodetableview.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,16 +25,17 @@ #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeTableView : public QTreeWidget { + Q_OBJECT public: NodeTableView(QWidget* parent = nullptr); - void SelectNodes(const QList& nodes); + void SelectNodes(const QVector &nodes); - void DeselectNodes(const QList& nodes); + void DeselectNodes(const QVector& nodes); void SetTime(const rational& time); @@ -45,6 +46,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODETABLEVIEW_H diff --git a/app/widget/nodetableview/nodetablewidget.cpp b/app/widget/nodetableview/nodetablewidget.cpp index f06678d33..1146e954b 100644 --- a/app/widget/nodetableview/nodetablewidget.cpp +++ b/app/widget/nodetableview/nodetablewidget.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { NodeTableWidget::NodeTableWidget(QWidget* parent) : TimeBasedWidget(parent) @@ -35,4 +35,4 @@ NodeTableWidget::NodeTableWidget(QWidget* parent) : layout->addWidget(view_); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodetableview/nodetablewidget.h b/app/widget/nodetableview/nodetablewidget.h index 1eeecbfcb..b2e39210a 100644 --- a/app/widget/nodetableview/nodetablewidget.h +++ b/app/widget/nodetableview/nodetablewidget.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,19 +24,19 @@ #include "nodetableview.h" #include "widget/timebased/timebased.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeTableWidget : public TimeBasedWidget { public: NodeTableWidget(QWidget* parent = nullptr); - void SelectNodes(const QList& nodes) + void SelectNodes(const QVector& nodes) { view_->SelectNodes(nodes); } - void DeselectNodes(const QList& nodes) + void DeselectNodes(const QVector& nodes) { view_->DeselectNodes(nodes); } @@ -57,6 +57,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODETABLEWIDGET_H diff --git a/app/widget/nodetreeview/CMakeLists.txt b/app/widget/nodetreeview/CMakeLists.txt index 486f03d0a..4c29e480e 100644 --- a/app/widget/nodetreeview/CMakeLists.txt +++ b/app/widget/nodetreeview/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/nodetreeview/nodetreeview.cpp b/app/widget/nodetreeview/nodetreeview.cpp index b02a707d9..8d4dfa4c3 100644 --- a/app/widget/nodetreeview/nodetreeview.cpp +++ b/app/widget/nodetreeview/nodetreeview.cpp @@ -1,6 +1,6 @@ #include "nodetreeview.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeTreeView::NodeTreeView(QWidget *parent) : QTreeWidget(parent), @@ -21,7 +21,7 @@ bool NodeTreeView::IsInputEnabled(NodeInput *i) const return !disabled_inputs_.contains(i); } -void NodeTreeView::SetNodes(const QList &nodes) +void NodeTreeView::SetNodes(const QVector &nodes) { nodes_ = nodes; @@ -34,7 +34,7 @@ void NodeTreeView::SetNodes(const QList &nodes) node_item->setData(0, kItemType, kItemTypeNode); node_item->setData(0, kItemPointer, reinterpret_cast(n)); - QList inputs = n->GetInputsIncludingArrays(); + QVector inputs = n->GetInputsIncludingArrays(); foreach (NodeInput* i, inputs) { if (only_show_keyframable_ && !i->is_keyframable()) { continue; @@ -108,4 +108,4 @@ void NodeTreeView::ItemCheckStateChanged(QTreeWidgetItem *item, int column) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodetreeview/nodetreeview.h b/app/widget/nodetreeview/nodetreeview.h index 2b221a68c..0984bcde4 100644 --- a/app/widget/nodetreeview/nodetreeview.h +++ b/app/widget/nodetreeview/nodetreeview.h @@ -5,7 +5,7 @@ #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeTreeView : public QTreeWidget { @@ -23,7 +23,7 @@ public: } public slots: - void SetNodes(const QList& nodes); + void SetNodes(const QVector &nodes); signals: void NodeEnableChanged(Node* n, bool e); @@ -44,11 +44,11 @@ private: static const int kItemType = Qt::UserRole; static const int kItemPointer = Qt::UserRole + 1; - QList nodes_; + QVector nodes_; - QList disabled_nodes_; + QVector disabled_nodes_; - QList disabled_inputs_; + QVector disabled_inputs_; bool only_show_keyframable_; @@ -57,6 +57,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODETREEVIEW_H diff --git a/app/widget/nodeview/CMakeLists.txt b/app/widget/nodeview/CMakeLists.txt index c36c19882..00aca1075 100644 --- a/app/widget/nodeview/CMakeLists.txt +++ b/app/widget/nodeview/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index d3cfdd3b9..8948c98ce 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #define super HandMovableView -OLIVE_NAMESPACE_ENTER +namespace olive { NodeView::NodeView(QWidget *parent) : HandMovableView(parent), @@ -115,7 +115,7 @@ void NodeView::DeleteSelected() QUndoCommand* command = new QUndoCommand(); { - QList selected_edges = scene_.GetSelectedEdges(); + QVector selected_edges = scene_.GetSelectedEdges(); foreach (NodeEdge* edge, selected_edges) { new NodeEdgeRemoveCommand(edge->output(), edge->input(), command); @@ -124,7 +124,7 @@ void NodeView::DeleteSelected() } { - QList selected_nodes = scene_.GetSelectedNodes(); + QVector selected_nodes = scene_.GetSelectedNodes(); // Ensure no nodes are "undeletable" for (int i=0;i &nodes) +void NodeView::Select(const QVector &nodes) { if (!graph_) { return; @@ -188,7 +188,7 @@ void NodeView::Select(const QList &nodes) SceneSelectionChangedSlot(); } -void NodeView::SelectWithDependencies(QList nodes) +void NodeView::SelectWithDependencies(QVector nodes) { if (!graph_) { return; @@ -202,7 +202,7 @@ void NodeView::SelectWithDependencies(QList nodes) Select(nodes); } -void NodeView::SelectBlocks(const QList &blocks) +void NodeView::SelectBlocks(const QVector &blocks) { if (!graph_) { return; @@ -213,7 +213,7 @@ void NodeView::SelectBlocks(const QList &blocks) QueueSelectBlocksInternal(); } -void NodeView::DeselectBlocks(const QList &blocks) +void NodeView::DeselectBlocks(const QVector &blocks) { if (!graph_) { return; @@ -240,7 +240,7 @@ void NodeView::CopySelected(bool cut) return; } - QList selected = scene_.GetSelectedNodes(); + QVector selected = scene_.GetSelectedNodes(); if (selected.isEmpty()) { return; @@ -261,7 +261,7 @@ void NodeView::Paste() QUndoCommand* command = new QUndoCommand(); - QList pasted_nodes = PasteNodesFromClipboard(static_cast(graph_), command); + QVector pasted_nodes = PasteNodesFromClipboard(static_cast(graph_), command); Core::instance()->undo_stack()->pushIfHasChildren(command); @@ -280,7 +280,7 @@ void NodeView::Duplicate() return; } - QList selected = scene_.GetSelectedNodes(); + QVector selected = scene_.GetSelectedNodes(); if (selected.isEmpty()) { return; @@ -288,43 +288,11 @@ void NodeView::Duplicate() QUndoCommand* command = new QUndoCommand(); - QList duplicated_nodes; - - foreach (Node* n, selected) { - Node* copy = n->copy(); - - Node::CopyInputs(n, copy, false); - - duplicated_nodes.append(copy); - - new NodeAddCommand(graph_, copy, command); - } - - for (int i=0;ioutput()->edges()) { - if (edge->input()->parentNode() == dst) { - new NodeEdgeAddCommand(duplicated_nodes.at(i)->output(), - duplicated_nodes.at(j)->GetInputWithID(edge->input()->id()), - command); - } - } - } - } + QVector duplicated_nodes = Node::CopyDependencyGraph(selected, command); Core::instance()->undo_stack()->pushIfHasChildren(command); - if (!duplicated_nodes.isEmpty()) { - AttachNodesToCursor(duplicated_nodes); - } + AttachNodesToCursor(duplicated_nodes); } void NodeView::ItemsChanged() @@ -488,10 +456,10 @@ void NodeView::wheelEvent(QWheelEvent *event) void NodeView::SceneSelectionChangedSlot() { - QList current_selection = scene_.GetSelectedNodes(); + QVector current_selection = scene_.GetSelectedNodes(); - QList selected; - QList deselected; + QVector selected; + QVector deselected; // Determine which nodes are newly selected if (selected_nodes_.isEmpty()) { @@ -540,7 +508,7 @@ void NodeView::ShowContextMenu(const QPoint &pos) m.addSeparator(); - QList selected = scene_.GetSelectedItems(); + QVector selected = scene_.GetSelectedItems(); if (itemAt(pos) && !selected.isEmpty()) { @@ -636,7 +604,7 @@ void NodeView::ContextMenuSetDirection(QAction *action) void NodeView::AutoPositionDescendents() { - QList selected = scene_.GetSelectedNodes(); + QVector selected = scene_.GetSelectedNodes(); foreach (Node* n, selected) { scene_.ReorganizeFrom(n); @@ -665,18 +633,18 @@ void NodeView::ContextMenuFilterChanged(QAction *action) } } -void NodeView::AttachNodesToCursor(const QList &nodes) +void NodeView::AttachNodesToCursor(const QVector &nodes) { - QList items; + QVector items(nodes.size()); - foreach (Node* p, nodes) { - items.append(scene_.NodeToUIObject(p)); + for (int i=0; i& items) +void NodeView::AttachItemsToCursor(const QVector& items) { DetachItemsFromCursor(); @@ -731,7 +699,7 @@ void NodeView::UpdateBlockFilter() bool first = true; QPointF last_bottom_right; - QList currently_visible; + QVector currently_visible; foreach (Block* b, selected_blocks_) { // Auto-position this node's dependencies @@ -741,7 +709,7 @@ void NodeView::UpdateBlockFilter() QPointF node_pos = b->GetPosition(); QRectF anchor(node_pos, node_pos); - QList deps = b->GetDependencies(); + QVector deps = b->GetDependencies(); foreach (Node* d, deps) { QPointF dep_pos = d->GetPosition(); @@ -779,8 +747,7 @@ void NodeView::UpdateBlockFilter() // ...then add its associations deps.append(temporary_association_map_[b]); - QHash >::const_iterator i; - for (i=association_map_.begin(); i!=association_map_.end(); i++) { + for (auto i=association_map_.begin(); i!=association_map_.end(); i++) { if (i.value().contains(b)) { deps.append(i.key()); } @@ -835,7 +802,7 @@ void NodeView::SelectBlocksInternal() UpdateBlockFilter(); } - QList nodes; + QVector nodes; nodes.reserve(selected_blocks_.size()); foreach (Block* b, selected_blocks_) { @@ -888,7 +855,7 @@ void NodeView::GraphEdgeAdded(NodeEdgePtr edge) Node* input_node = edge->input()->parentNode(); if (input_node->OutputsTo(static_cast(graph_)->viewer_output(), true)) { - QHash >::const_iterator i = association_map_.begin(); + auto i = association_map_.begin(); while (i != association_map_.end()) { if (input_node->InputsFrom(i.key(), true)) { @@ -917,14 +884,14 @@ void NodeView::GraphEdgeRemoved(NodeEdgePtr edge) } } - QList disconnected_nodes; + QVector disconnected_nodes; disconnected_nodes.append(output_node); disconnected_nodes.append(output_node->GetDependencies()); if (output_node->OutputsTo(static_cast(graph_)->viewer_output(), true)) { // Check if this disconnected node still has a path to the viewer somewhere else foreach (Block* b, selected_blocks_) { - QList& temp_assocs = temporary_association_map_[b]; + QVector& temp_assocs = temporary_association_map_[b]; temp_assocs.append(disconnected_nodes); } @@ -936,4 +903,4 @@ void NodeView::GraphEdgeRemoved(NodeEdgePtr edge) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h index 5bcf7799e..09c255468 100644 --- a/app/widget/nodeview/nodeview.h +++ b/app/widget/nodeview/nodeview.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,7 +29,7 @@ #include "widget/timelinewidget/view/handmovableview.h" #include "widget/nodecopypaste/nodecopypaste.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A widget for viewing and editing node graphs @@ -58,22 +58,22 @@ public: void SelectAll(); void DeselectAll(); - void Select(const QList& nodes); - void SelectWithDependencies(QList nodes); + void Select(const QVector& nodes); + void SelectWithDependencies(QVector nodes); void CopySelected(bool cut); void Paste(); void Duplicate(); - void SelectBlocks(const QList& blocks); + void SelectBlocks(const QVector& blocks); - void DeselectBlocks(const QList& blocks); + void DeselectBlocks(const QVector& blocks); signals: - void NodesSelected(const QList& nodes); + void NodesSelected(const QVector& nodes); - void NodesDeselected(const QList& nodes); + void NodesDeselected(const QVector& nodes); protected: virtual void keyPressEvent(QKeyEvent *event) override; @@ -85,9 +85,9 @@ protected: virtual void wheelEvent(QWheelEvent* event) override; private: - void AttachNodesToCursor(const QList& nodes); + void AttachNodesToCursor(const QVector &nodes); - void AttachItemsToCursor(const QList& items); + void AttachItemsToCursor(const QVector &items); void DetachItemsFromCursor(); @@ -121,13 +121,13 @@ private: NodeViewScene scene_; - QList selected_nodes_; + QVector selected_nodes_; - QList selected_blocks_; + QVector selected_blocks_; - QHash > association_map_; + QHash > association_map_; - QHash > temporary_association_map_; + QHash > temporary_association_map_; enum FilterMode { kFilterShowAll, @@ -190,6 +190,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEVIEW_H diff --git a/app/widget/nodeview/nodeviewcommon.h b/app/widget/nodeview/nodeviewcommon.h index cc2b870fe..648229b28 100644 --- a/app/widget/nodeview/nodeviewcommon.h +++ b/app/widget/nodeview/nodeviewcommon.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeViewCommon { public: @@ -53,6 +53,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEVIEWCOMMON_H diff --git a/app/widget/nodeview/nodeviewedge.cpp b/app/widget/nodeview/nodeviewedge.cpp index e07470fdc..15d0bfae2 100644 --- a/app/widget/nodeview/nodeviewedge.cpp +++ b/app/widget/nodeview/nodeviewedge.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,12 +25,12 @@ #include #include -#include "common/clamp.h" +#include "common/bezier.h" #include "common/lerp.h" #include "nodeview.h" #include "nodeviewscene.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeViewEdge::NodeViewEdge(QGraphicsItem *parent) : QGraphicsPathItem(parent), @@ -47,6 +47,7 @@ NodeViewEdge::NodeViewEdge(QGraphicsItem *parent) : // Use font metrics to set edge width for basic high DPI support edge_width_ = QFontMetrics(QFont()).height() / 12; + arrow_size_ = QFontMetrics(QFont()).height() / 2; } void NodeViewEdge::SetEdge(NodeEdgePtr edge) @@ -104,6 +105,8 @@ void NodeViewEdge::SetPoints(const QPointF &start, const QPointF &end, bool inpu QPainterPath path; path.moveTo(start); + double angle = qAtan2(end.y() - start.y(), end.x() - start.x()); + if (curved_) { double half_x = lerp(start.x(), end.x(), 0.5); @@ -125,6 +128,36 @@ void NodeViewEdge::SetPoints(const QPointF &start, const QPointF &end, bool inpu path.cubicTo(cp1, cp2, end); + if (!qFuzzyCompare(start.x(), end.x())) { + double continue_x = end.x() - qCos(angle)*arrow_size_; + + double x1, x2, x3, x4, y1, y2, y3, y4; + if (start.x() < end.x()) { + x1 = start.x(); + x2 = cp1.x(); + x3 = cp2.x(); + x4 = end.x(); + y1 = start.y(); + y2 = cp1.y(); + y3 = cp2.y(); + y4 = end.y(); + } else { + x1 = end.x(); + x2 = cp2.x(); + x3 = cp1.x(); + x4 = start.x(); + y1 = end.y(); + y2 = cp2.y(); + y3 = cp1.y(); + y4 = start.y(); + } + + double t = Bezier::CubicXtoT(continue_x, x1, x2, x3, x4); + double y = Bezier::CubicTtoY(y1, y2, y3, y4, t); + + angle = qAtan2(end.y() - y, end.x() - continue_x); + } + } else { path.lineTo(end); @@ -132,6 +165,15 @@ void NodeViewEdge::SetPoints(const QPointF &start, const QPointF &end, bool inpu } setPath(path); + + const double arrow_angle = 150.0 * 3.141592 / 180.0; + QVector arrow_points(4); + arrow_points[0] = end; + arrow_points[1] = end + QPointF(qCos(angle + arrow_angle) * arrow_size_, qSin(angle + arrow_angle) * arrow_size_); + arrow_points[2] = end + QPointF(qCos(angle - arrow_angle) * arrow_size_, qSin(angle - arrow_angle) * arrow_size_); + arrow_points[3] = end; + + arrow_ = QPolygonF(arrow_points); } void NodeViewEdge::SetFlowDirection(NodeViewCommon::FlowDirection dir) @@ -165,9 +207,17 @@ void NodeViewEdge::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti role = QPalette::Text; } - painter->setPen(QPen(qApp->palette().color(group, role), edge_width_)); + // Draw main path + QColor edge_color = qApp->palette().color(group, role); + + painter->setPen(QPen(edge_color, edge_width_)); painter->setBrush(Qt::NoBrush); painter->drawPath(path()); + + // Draw arrow + painter->setPen(Qt::NoPen); + painter->setBrush(edge_color); + painter->drawPolygon(arrow_); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodeview/nodeviewedge.h b/app/widget/nodeview/nodeviewedge.h index be1f6a666..361a3ffb5 100644 --- a/app/widget/nodeview/nodeviewedge.h +++ b/app/widget/nodeview/nodeviewedge.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "node/edge.h" #include "nodeviewcommon.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A graphical representation of a NodeEdge to be used in NodeView @@ -110,8 +110,12 @@ private: bool curved_; + QPolygonF arrow_; + + int arrow_size_; + }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEEDGEITEM_H diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp index 8f637a212..596024897 100644 --- a/app/widget/nodeview/nodeviewitem.cpp +++ b/app/widget/nodeview/nodeviewitem.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -36,7 +36,7 @@ #include "ui/icons/icons.h" #include "window/mainwindow/mainwindow.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeViewItem::NodeViewItem(QGraphicsItem *parent) : QGraphicsRectItem(parent), @@ -133,7 +133,7 @@ int NodeViewItem::DefaultItemHeight() int NodeViewItem::DefaultItemWidth() { - return QFontMetricsWidth(QFontMetrics(QFont()), "HHHHHHHHHHHH");; + return QtUtils::QFontMetricsWidth(QFontMetrics(QFont()), "HHHHHHHHHHHH");; } int NodeViewItem::DefaultItemBorder() @@ -316,7 +316,7 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti // Calculate how much space we have for text int item_width = title_bar_rect_.width(); int max_text_width = item_width - DefaultTextPadding() * 2 - icon_full_size; - int label_width = QFontMetricsWidth(fm, node_label); + int label_width = QtUtils::QFontMetricsWidth(fm, node_label); // Concatenate text if necessary (adds a "..." to the end and removes characters until the // string fits in the bounds) @@ -326,7 +326,7 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti do { node_label.chop(1); concatenated = QCoreApplication::translate("NodeViewItem", "%1...").arg(node_label); - } while ((label_width = QFontMetricsWidth(fm, concatenated)) > max_text_width); + } while ((label_width = QtUtils::QFontMetricsWidth(fm, concatenated)) > max_text_width); node_label = concatenated; } @@ -699,4 +699,4 @@ QPointF NodeViewItem::GetInputPoint(int index, const QPointF& source_pos) const } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodeview/nodeviewitem.h b/app/widget/nodeview/nodeviewitem.h index 75d32ffd0..845f0d652 100644 --- a/app/widget/nodeview/nodeviewitem.h +++ b/app/widget/nodeview/nodeviewitem.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -32,7 +32,7 @@ #include "nodeviewedge.h" #include "nodeviewitemwidgetproxy.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A visual widget representation of a Node object to be used in a NodeView @@ -174,6 +174,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEVIEWITEM_H diff --git a/app/widget/nodeview/nodeviewitemwidgetproxy.cpp b/app/widget/nodeview/nodeviewitemwidgetproxy.cpp index 040e755ce..b219e8b67 100644 --- a/app/widget/nodeview/nodeviewitemwidgetproxy.cpp +++ b/app/widget/nodeview/nodeviewitemwidgetproxy.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 diff --git a/app/widget/nodeview/nodeviewitemwidgetproxy.h b/app/widget/nodeview/nodeviewitemwidgetproxy.h index bfd087384..91d0312f3 100644 --- a/app/widget/nodeview/nodeviewitemwidgetproxy.h +++ b/app/widget/nodeview/nodeviewitemwidgetproxy.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 diff --git a/app/widget/nodeview/nodeviewscene.cpp b/app/widget/nodeview/nodeviewscene.cpp index a36657b7c..f326c100c 100644 --- a/app/widget/nodeview/nodeviewscene.cpp +++ b/app/widget/nodeview/nodeviewscene.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "nodeviewitem.h" #include "project/item/sequence/sequence.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeViewScene::NodeViewScene(QObject *parent) : QGraphicsScene(parent), @@ -120,10 +120,10 @@ void NodeViewScene::SetGraph(NodeGraph *graph) graph_ = graph; } -QList NodeViewScene::GetSelectedNodes() const +QVector NodeViewScene::GetSelectedNodes() const { QHash::const_iterator iterator; - QList selected; + QVector selected; for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) { if (iterator.value()->isSelected()) { @@ -134,10 +134,10 @@ QList NodeViewScene::GetSelectedNodes() const return selected; } -QList NodeViewScene::GetSelectedItems() const +QVector NodeViewScene::GetSelectedItems() const { QHash::const_iterator iterator; - QList selected; + QVector selected; for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) { if (iterator.value()->isSelected()) { @@ -148,9 +148,9 @@ QList NodeViewScene::GetSelectedItems() const return selected; } -QList NodeViewScene::GetSelectedEdges() const +QVector NodeViewScene::GetSelectedEdges() const { - QList edges; + QVector edges; QHash::const_iterator i; @@ -228,7 +228,7 @@ void NodeViewScene::RemoveEdge(NodeEdgePtr edge) int NodeViewScene::DetermineWeight(Node *n) { - QList inputs = n->GetImmediateDependencies(); + QVector inputs = n->GetImmediateDependencies(); int weight = 0; @@ -253,7 +253,7 @@ NodeViewCommon::FlowDirection NodeViewScene::GetFlowDirection() const void NodeViewScene::ReorganizeFrom(Node* n) { - QList immediates = n->GetImmediateDependencies(); + QVector immediates = n->GetImmediateDependencies(); if (immediates.isEmpty()) { // Nothing to do @@ -310,4 +310,4 @@ void NodeViewScene::NodeLabelChanged() item_map_.value(static_cast(sender()))->update(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodeview/nodeviewscene.h b/app/widget/nodeview/nodeviewscene.h index 1cb3d1a6c..51064c965 100644 --- a/app/widget/nodeview/nodeviewscene.h +++ b/app/widget/nodeview/nodeviewscene.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "nodeviewedge.h" #include "nodeviewitem.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class NodeViewScene : public QGraphicsScene { @@ -63,9 +63,9 @@ public: void SetGraph(NodeGraph* graph); - QList GetSelectedNodes() const; - QList GetSelectedItems() const; - QList GetSelectedEdges() const; + QVector GetSelectedNodes() const; + QVector GetSelectedItems() const; + QVector GetSelectedEdges() const; const QHash& item_map() const; const QHash& edge_map() const; @@ -146,6 +146,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEVIEWSCENE_H diff --git a/app/widget/nodeview/nodeviewundo.cpp b/app/widget/nodeview/nodeviewundo.cpp index 032cd0bcd..66416c158 100644 --- a/app/widget/nodeview/nodeviewundo.cpp +++ b/app/widget/nodeview/nodeviewundo.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include "project/item/sequence/sequence.h" -OLIVE_NAMESPACE_ENTER +namespace olive { NodeEdgeAddCommand::NodeEdgeAddCommand(NodeOutput *output, NodeInput *input, QUndoCommand *parent) : UndoCommand(parent), @@ -131,7 +131,7 @@ Project *NodeAddCommand::GetRelevantProject() const return static_cast(graph_)->project(); } -NodeRemoveCommand::NodeRemoveCommand(NodeGraph *graph, const QList &nodes, QUndoCommand *parent) : +NodeRemoveCommand::NodeRemoveCommand(NodeGraph *graph, const QVector &nodes, QUndoCommand *parent) : UndoCommand(parent), graph_(graph), nodes_(nodes) @@ -197,7 +197,7 @@ Project *NodeRemoveCommand::GetRelevantProject() const NodeRemoveWithExclusiveDeps::NodeRemoveWithExclusiveDeps(NodeGraph *graph, Node *node, QUndoCommand *parent) : UndoCommand(parent) { - QList node_and_its_deps; + QVector node_and_its_deps; node_and_its_deps.append(node); node_and_its_deps.append(node->GetExclusiveDependencies()); @@ -230,4 +230,4 @@ void NodeCopyInputsCommand::redo() Node::CopyInputs(src_, dest_, include_connections_); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/nodeview/nodeviewundo.h b/app/widget/nodeview/nodeviewundo.h index 6b2854e38..03f9f4bcd 100644 --- a/app/widget/nodeview/nodeviewundo.h +++ b/app/widget/nodeview/nodeviewundo.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,7 +29,7 @@ #include "undo/undocommand.h" #include "widget/timelinewidget/undo/undo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief An undoable command for connecting two NodeParams together @@ -98,7 +98,7 @@ private: class NodeRemoveCommand : public UndoCommand { public: NodeRemoveCommand(NodeGraph* graph, - const QList& nodes, + const QVector& nodes, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; @@ -111,9 +111,9 @@ private: QObject memory_manager_; NodeGraph* graph_; - QList nodes_; - QList edges_; - QList block_unlink_commands_; + QVector nodes_; + QVector edges_; + QVector block_unlink_commands_; }; class NodeRemoveWithExclusiveDeps : public UndoCommand { @@ -209,6 +209,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // NODEVIEWUNDO_H diff --git a/app/widget/panel/CMakeLists.txt b/app/widget/panel/CMakeLists.txt index db88a9b47..e17aff130 100644 --- a/app/widget/panel/CMakeLists.txt +++ b/app/widget/panel/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/panel/panel.cpp b/app/widget/panel/panel.cpp index d94b54448..49aef76cf 100644 --- a/app/widget/panel/panel.cpp +++ b/app/widget/panel/panel.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { PanelWidget::PanelWidget(const QString &object_name, QWidget *parent) : QDockWidget(parent), @@ -154,4 +154,4 @@ void PanelWidget::SetWidgetWithPadding(QWidget *widget) setWidget(wrapper); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/panel/panel.h b/app/widget/panel/panel.h index 1d25f5eba..939baa2af 100644 --- a/app/widget/panel/panel.h +++ b/app/widget/panel/panel.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,12 +26,13 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A widget that is always dockable within the MainWindow. */ -class PanelWidget : public QDockWidget { +class PanelWidget : public QDockWidget +{ Q_OBJECT public: /** @@ -235,6 +236,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // PANEL_WIDGET_H diff --git a/app/widget/path/CMakeLists.txt b/app/widget/path/CMakeLists.txt index a7bd17910..3c4598340 100644 --- a/app/widget/path/CMakeLists.txt +++ b/app/widget/path/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/path/pathwidget.cpp b/app/widget/path/pathwidget.cpp index b646e2d40..f0ffeeb57 100644 --- a/app/widget/path/pathwidget.cpp +++ b/app/widget/path/pathwidget.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/filefunctions.h" -OLIVE_NAMESPACE_ENTER +namespace olive { PathWidget::PathWidget(const QString &path, QWidget *parent) : QWidget(parent) @@ -65,4 +65,4 @@ void PathWidget::LineEditChanged() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/path/pathwidget.h b/app/widget/path/pathwidget.h index c35eae30e..74a0da99f 100644 --- a/app/widget/path/pathwidget.h +++ b/app/widget/path/pathwidget.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PathWidget : public QWidget { @@ -52,6 +52,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // PATHWIDGET_H diff --git a/app/widget/pixelsampler/CMakeLists.txt b/app/widget/pixelsampler/CMakeLists.txt index ecf7831f7..da53c06f6 100644 --- a/app/widget/pixelsampler/CMakeLists.txt +++ b/app/widget/pixelsampler/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/pixelsampler/pixelsampler.cpp b/app/widget/pixelsampler/pixelsampler.cpp index 22cde93f5..cd0ddf92f 100644 --- a/app/widget/pixelsampler/pixelsampler.cpp +++ b/app/widget/pixelsampler/pixelsampler.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { PixelSamplerWidget::PixelSamplerWidget(QWidget *parent) : QGroupBox(parent) @@ -77,4 +77,4 @@ void ManagedPixelSamplerWidget::SetValues(const Color &reference, const Color &d display_view_->SetValues(display); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/pixelsampler/pixelsampler.h b/app/widget/pixelsampler/pixelsampler.h index 414826962..a2f6ada6f 100644 --- a/app/widget/pixelsampler/pixelsampler.h +++ b/app/widget/pixelsampler/pixelsampler.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "render/color.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PixelSamplerWidget : public QGroupBox { @@ -63,6 +63,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // PIXELSAMPLERWIDGET_H diff --git a/app/widget/playbackcontrols/CMakeLists.txt b/app/widget/playbackcontrols/CMakeLists.txt index 68f3a0799..fdf35e08a 100644 --- a/app/widget/playbackcontrols/CMakeLists.txt +++ b/app/widget/playbackcontrols/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/playbackcontrols/dragbutton.cpp b/app/widget/playbackcontrols/dragbutton.cpp index ce3539ff6..644f1c1bc 100644 --- a/app/widget/playbackcontrols/dragbutton.cpp +++ b/app/widget/playbackcontrols/dragbutton.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "dragbutton.h" -OLIVE_NAMESPACE_ENTER +namespace olive { DragButton::DragButton(QWidget *parent) : QPushButton(parent) @@ -33,4 +33,4 @@ void DragButton::mousePressEvent(QMouseEvent *event) { emit MousePressed(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/playbackcontrols/dragbutton.h b/app/widget/playbackcontrols/dragbutton.h index 6c2eafde9..c0bb2f2a5 100644 --- a/app/widget/playbackcontrols/dragbutton.h +++ b/app/widget/playbackcontrols/dragbutton.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class DragButton : public QPushButton { @@ -41,6 +41,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // DRAGBUTTON_H diff --git a/app/widget/playbackcontrols/playbackcontrols.cpp b/app/widget/playbackcontrols/playbackcontrols.cpp index 3acb51bdc..692e20a91 100644 --- a/app/widget/playbackcontrols/playbackcontrols.cpp +++ b/app/widget/playbackcontrols/playbackcontrols.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "config/config.h" #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { PlaybackControls::PlaybackControls(QWidget *parent) : QWidget(parent), @@ -229,4 +229,4 @@ void PlaybackControls::TimecodeChanged() SetEndTime(end_time_); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/playbackcontrols/playbackcontrols.h b/app/widget/playbackcontrols/playbackcontrols.h index 6940b4102..a77563ac2 100644 --- a/app/widget/playbackcontrols/playbackcontrols.h +++ b/app/widget/playbackcontrols/playbackcontrols.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "dragbutton.h" #include "widget/slider/timeslider.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A playback controls widget providing buttons for navigating media @@ -134,6 +134,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // PLAYBACKCONTROLS_H diff --git a/app/widget/projectexplorer/CMakeLists.txt b/app/widget/projectexplorer/CMakeLists.txt index cc8d45b76..86d399e66 100644 --- a/app/widget/projectexplorer/CMakeLists.txt +++ b/app/widget/projectexplorer/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/projectexplorer/projectexplorer.cpp b/app/widget/projectexplorer/projectexplorer.cpp index 8a57628c9..a9c38820e 100644 --- a/app/widget/projectexplorer/projectexplorer.cpp +++ b/app/widget/projectexplorer/projectexplorer.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -41,7 +41,7 @@ #include "widget/timelinewidget/timelinewidget.h" #include "widget/nodeview/nodeviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectExplorer::ProjectExplorer(QWidget *parent) : QWidget(parent), @@ -637,12 +637,12 @@ void ProjectExplorer::DeleteSelected() if (msgbox.clickedButton() == delete_clip_btn) { // Delete any blocks that use this footage - QList blocks_to_remove; + QVector blocks_to_remove; foreach (Sequence* s, used_in_sequences) { foreach (TrackOutput* track, s->viewer_output()->GetTracks()) { foreach (Block* b, track->Blocks()) { - QList deps = b->GetDependencies(); + QVector deps = b->GetDependencies(); foreach (MediaInput* i, footage_nodes) { if (deps.contains(i)) { @@ -683,4 +683,4 @@ void ProjectExplorer::DeleteSelected() Core::instance()->undo_stack()->pushIfHasChildren(command); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/projectexplorer/projectexplorer.h b/app/widget/projectexplorer/projectexplorer.h index 90dd10841..e935b9084 100644 --- a/app/widget/projectexplorer/projectexplorer.h +++ b/app/widget/projectexplorer/projectexplorer.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -34,7 +34,7 @@ #include "widget/projectexplorer/projectexplorernavigation.h" #include "widget/projecttoolbar/projecttoolbar.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A widget for browsing through a Project structure. @@ -186,6 +186,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTEXPLORER_H diff --git a/app/widget/projectexplorer/projectexplorericonview.cpp b/app/widget/projectexplorer/projectexplorericonview.cpp index 0284dd5f5..ac2bd7561 100644 --- a/app/widget/projectexplorer/projectexplorericonview.cpp +++ b/app/widget/projectexplorer/projectexplorericonview.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "projectexplorericonview.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectExplorerIconView::ProjectExplorerIconView(QWidget *parent) : ProjectExplorerListViewBase(parent) @@ -30,4 +30,4 @@ ProjectExplorerIconView::ProjectExplorerIconView(QWidget *parent) : setItemDelegate(&delegate_); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/projectexplorer/projectexplorericonview.h b/app/widget/projectexplorer/projectexplorericonview.h index c0b11cfd2..68e7f25e9 100644 --- a/app/widget/projectexplorer/projectexplorericonview.h +++ b/app/widget/projectexplorer/projectexplorericonview.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "projectexplorerlistviewbase.h" #include "projectexplorericonviewitemdelegate.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief The view widget used when ProjectExplorer is in Icon View @@ -39,6 +39,6 @@ private: ProjectExplorerIconViewItemDelegate delegate_; }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTEXPLORERICONVIEW_H diff --git a/app/widget/projectexplorer/projectexplorericonviewitemdelegate.cpp b/app/widget/projectexplorer/projectexplorericonviewitemdelegate.cpp index d0bb4cdd6..3690576bf 100644 --- a/app/widget/projectexplorer/projectexplorericonviewitemdelegate.cpp +++ b/app/widget/projectexplorer/projectexplorericonviewitemdelegate.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "common/qtutils.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectExplorerIconViewItemDelegate::ProjectExplorerIconViewItemDelegate(QObject *parent) : QStyledItemDelegate (parent) @@ -66,7 +66,7 @@ void ProjectExplorerIconViewItemDelegate::paint(QPainter *painter, const QStyleO QString duration_str = index.data(Qt::UserRole).toString(); - int timecode_width = QFontMetricsWidth(fm, duration_str); + int timecode_width = QtUtils::QFontMetricsWidth(fm, duration_str); int max_name_width = option.rect.width(); @@ -99,4 +99,4 @@ void ProjectExplorerIconViewItemDelegate::paint(QPainter *painter, const QStyleO } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/projectexplorer/projectexplorericonviewitemdelegate.h b/app/widget/projectexplorer/projectexplorericonviewitemdelegate.h index 583ece26a..69da53e64 100644 --- a/app/widget/projectexplorer/projectexplorericonviewitemdelegate.h +++ b/app/widget/projectexplorer/projectexplorericonviewitemdelegate.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief The delegate that's used to draw items when ProjectExplorer is in Icon view @@ -38,6 +38,6 @@ public: virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTEXPLORERICONVIEWITEMDELEGATE_H diff --git a/app/widget/projectexplorer/projectexplorerlistview.cpp b/app/widget/projectexplorer/projectexplorerlistview.cpp index 0f028dde9..340107c54 100644 --- a/app/widget/projectexplorer/projectexplorerlistview.cpp +++ b/app/widget/projectexplorer/projectexplorerlistview.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "projectexplorerlistview.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectExplorerListView::ProjectExplorerListView(QWidget *parent) : ProjectExplorerListViewBase(parent) @@ -30,4 +30,4 @@ ProjectExplorerListView::ProjectExplorerListView(QWidget *parent) : setItemDelegate(&delegate_); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/projectexplorer/projectexplorerlistview.h b/app/widget/projectexplorer/projectexplorerlistview.h index 9f62925f3..5d15941c4 100644 --- a/app/widget/projectexplorer/projectexplorerlistview.h +++ b/app/widget/projectexplorer/projectexplorerlistview.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "projectexplorerlistviewbase.h" #include "projectexplorerlistviewitemdelegate.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief The view widget used when ProjectExplorer is in List View @@ -39,6 +39,6 @@ private: ProjectExplorerListViewItemDelegate delegate_; }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTEXPLORERLISTVIEW_H diff --git a/app/widget/projectexplorer/projectexplorerlistviewbase.cpp b/app/widget/projectexplorer/projectexplorerlistviewbase.cpp index c01e1125e..79cb6e9db 100644 --- a/app/widget/projectexplorer/projectexplorerlistviewbase.cpp +++ b/app/widget/projectexplorer/projectexplorerlistviewbase.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectExplorerListViewBase::ProjectExplorerListViewBase(QWidget *parent) : QListView(parent) @@ -51,4 +51,4 @@ void ProjectExplorerListViewBase::mouseDoubleClickEvent(QMouseEvent *event) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/projectexplorer/projectexplorerlistviewbase.h b/app/widget/projectexplorer/projectexplorerlistviewbase.h index 19b816f74..f3b397b8a 100644 --- a/app/widget/projectexplorer/projectexplorerlistviewbase.h +++ b/app/widget/projectexplorer/projectexplorerlistviewbase.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A QListView derivative that contains functionality used by both List view and Icon view (which are both based @@ -57,6 +57,6 @@ signals: void DoubleClickedEmptyArea(); }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTEXPLORERLISTVIEWBASE_H diff --git a/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.cpp b/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.cpp index 8414864a0..465b3aee9 100644 --- a/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.cpp +++ b/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectExplorerListViewItemDelegate::ProjectExplorerListViewItemDelegate(QObject *parent) : QStyledItemDelegate(parent) @@ -80,4 +80,4 @@ void ProjectExplorerListViewItemDelegate::paint(QPainter *painter, const QStyleO painter->drawText(text_rect, static_cast(Qt::AlignLeft | Qt::AlignVCenter), text); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.h b/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.h index 0e99869d1..780b153b4 100644 --- a/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.h +++ b/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief The delegate that's used to draw items when ProjectExplorer is in List view @@ -39,6 +39,6 @@ public: virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTEXPLORERLISTVIEWITEMDELEGATE_H diff --git a/app/widget/projectexplorer/projectexplorernavigation.cpp b/app/widget/projectexplorer/projectexplorernavigation.cpp index a67650a19..6f23ee6d8 100644 --- a/app/widget/projectexplorer/projectexplorernavigation.cpp +++ b/app/widget/projectexplorer/projectexplorernavigation.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/define.h" #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectExplorerNavigation::ProjectExplorerNavigation(QWidget *parent) : QWidget(parent) @@ -96,4 +96,4 @@ void ProjectExplorerNavigation::UpdateIcons() size_slider_->setValue(kProjectIconSizeDefault); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/projectexplorer/projectexplorernavigation.h b/app/widget/projectexplorer/projectexplorernavigation.h index 3f91ec6eb..4edb93ac4 100644 --- a/app/widget/projectexplorer/projectexplorernavigation.h +++ b/app/widget/projectexplorer/projectexplorernavigation.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A navigation bar widget for ProjectExplorer's Icon and List views @@ -112,6 +112,6 @@ private: QSlider* size_slider_; }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTEXPLORERLISTVIEWTOOLBAR_H diff --git a/app/widget/projectexplorer/projectexplorertreeview.cpp b/app/widget/projectexplorer/projectexplorertreeview.cpp index 65d76dfd9..0b7a95514 100644 --- a/app/widget/projectexplorer/projectexplorertreeview.cpp +++ b/app/widget/projectexplorer/projectexplorertreeview.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectExplorerTreeView::ProjectExplorerTreeView(QWidget *parent) : QTreeView(parent) @@ -54,4 +54,4 @@ void ProjectExplorerTreeView::mouseDoubleClickEvent(QMouseEvent *event) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/projectexplorer/projectexplorertreeview.h b/app/widget/projectexplorer/projectexplorertreeview.h index c3e4668e8..0d1c562e7 100644 --- a/app/widget/projectexplorer/projectexplorertreeview.h +++ b/app/widget/projectexplorer/projectexplorertreeview.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief The view widget used when ProjectExplorer is in Tree View @@ -59,6 +59,6 @@ signals: void DoubleClickedEmptyArea(); }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTEXPLORERTREEVIEW_H diff --git a/app/widget/projectexplorer/projectexplorerundo.cpp b/app/widget/projectexplorer/projectexplorerundo.cpp index 609402caa..3bb2753d7 100644 --- a/app/widget/projectexplorer/projectexplorerundo.cpp +++ b/app/widget/projectexplorer/projectexplorerundo.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "projectexplorerundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { OfflineFootageCommand::OfflineFootageCommand(const QList &media, QUndoCommand* parent) : UndoCommand(parent) @@ -51,4 +51,4 @@ void OfflineFootageCommand::undo_internal() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/projectexplorer/projectexplorerundo.h b/app/widget/projectexplorer/projectexplorerundo.h index 8aaabdc0e..fbab93992 100644 --- a/app/widget/projectexplorer/projectexplorerundo.h +++ b/app/widget/projectexplorer/projectexplorerundo.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "node/input/media/media.h" #include "undo/undocommand.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief An undo command for offlining footage when it is deleted from the project explorer @@ -47,6 +47,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTEXPLORERUNDO_H diff --git a/app/widget/projecttoolbar/CMakeLists.txt b/app/widget/projecttoolbar/CMakeLists.txt index 79846cee3..ffab1214b 100644 --- a/app/widget/projecttoolbar/CMakeLists.txt +++ b/app/widget/projecttoolbar/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/projecttoolbar/projecttoolbar.cpp b/app/widget/projecttoolbar/projecttoolbar.cpp index 056cd0ee5..ba7d5303d 100644 --- a/app/widget/projecttoolbar/projecttoolbar.cpp +++ b/app/widget/projecttoolbar/projecttoolbar.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ProjectToolbar::ProjectToolbar(QWidget *parent) : QWidget(parent) @@ -36,43 +36,35 @@ ProjectToolbar::ProjectToolbar(QWidget *parent) : layout->setMargin(0); new_button_ = new QPushButton(); - connect(new_button_, SIGNAL(clicked(bool)), this, SIGNAL(NewClicked())); + connect(new_button_, &QPushButton::clicked, this, &ProjectToolbar::NewClicked); layout->addWidget(new_button_); open_button_ = new QPushButton(); - connect(open_button_, SIGNAL(clicked(bool)), this, SIGNAL(OpenClicked())); + connect(open_button_, &QPushButton::clicked, this, &ProjectToolbar::OpenClicked); layout->addWidget(open_button_); save_button_ = new QPushButton(); - connect(save_button_, SIGNAL(clicked(bool)), this, SIGNAL(SaveClicked())); + connect(save_button_, &QPushButton::clicked, this, &ProjectToolbar::SaveClicked); layout->addWidget(save_button_); - undo_button_ = new QPushButton(); - connect(undo_button_, SIGNAL(clicked(bool)), this, SIGNAL(UndoClicked())); - layout->addWidget(undo_button_); - - redo_button_ = new QPushButton(); - connect(redo_button_, SIGNAL(clicked(bool)), this, SIGNAL(RedoClicked())); - layout->addWidget(redo_button_); - search_field_ = new QLineEdit(); search_field_->setClearButtonEnabled(true); - connect(search_field_, SIGNAL(textChanged(const QString &)), this, SIGNAL(SearchChanged(const QString&))); + connect(search_field_, &QLineEdit::textChanged, this, &ProjectToolbar::SearchChanged); layout->addWidget(search_field_); tree_button_ = new QPushButton(); tree_button_->setCheckable(true); - connect(tree_button_, SIGNAL(clicked(bool)), this, SLOT(ViewButtonClicked())); + connect(tree_button_, &QPushButton::clicked, this, &ProjectToolbar::ViewButtonClicked); layout->addWidget(tree_button_); list_button_ = new QPushButton(); list_button_->setCheckable(true); - connect(list_button_, SIGNAL(clicked(bool)), this, SLOT(ViewButtonClicked())); + connect(list_button_, &QPushButton::clicked, this, &ProjectToolbar::ViewButtonClicked); layout->addWidget(list_button_); icon_button_ = new QPushButton(); icon_button_->setCheckable(true); - connect(icon_button_, SIGNAL(clicked(bool)), this, SLOT(ViewButtonClicked())); + connect(icon_button_, &QPushButton::clicked, this, &ProjectToolbar::ViewButtonClicked); layout->addWidget(icon_button_); // Group Tree/List/Icon view buttons into a button group for easy exclusive-buttons @@ -116,14 +108,12 @@ void ProjectToolbar::Retranslate() new_button_->setToolTip(tr("New...")); open_button_->setToolTip(tr("Open Project")); save_button_->setToolTip(tr("Save Project")); - undo_button_->setToolTip(tr("Undo")); - redo_button_->setToolTip(tr("Redo")); search_field_->setPlaceholderText(tr("Search media, markers, etc.")); - tree_button_->setToolTip(tr("Switch to Tree View")); - list_button_->setToolTip(tr("Switch to List View")); - icon_button_->setToolTip(tr("Switch to Icon View")); + tree_button_->setToolTip(tr("Tree View")); + list_button_->setToolTip(tr("List View")); + icon_button_->setToolTip(tr("Icon View")); } void ProjectToolbar::UpdateIcons() @@ -131,8 +121,6 @@ void ProjectToolbar::UpdateIcons() new_button_->setIcon(icon::New); open_button_->setIcon(icon::Open); save_button_->setIcon(icon::Save); - undo_button_->setIcon(icon::Undo); - redo_button_->setIcon(icon::Redo); tree_button_->setIcon(icon::TreeView); list_button_->setIcon(icon::ListView); icon_button_->setIcon(icon::IconView); @@ -153,4 +141,4 @@ void ProjectToolbar::ViewButtonClicked() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/projecttoolbar/projecttoolbar.h b/app/widget/projecttoolbar/projecttoolbar.h index 7f5624484..a5f5cfa28 100644 --- a/app/widget/projecttoolbar/projecttoolbar.h +++ b/app/widget/projecttoolbar/projecttoolbar.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief The ProjectToolbar class @@ -60,9 +60,6 @@ signals: void OpenClicked(); void SaveClicked(); - void UndoClicked(); - void RedoClicked(); - void SearchChanged(const QString&); void ViewChanged(ViewType type); @@ -74,8 +71,6 @@ private: QPushButton* new_button_; QPushButton* open_button_; QPushButton* save_button_; - QPushButton* undo_button_; - QPushButton* redo_button_; QLineEdit* search_field_; @@ -87,6 +82,6 @@ private slots: void ViewButtonClicked(); }; -OLIVE_NAMESPACE_EXIT +} #endif // PROJECTTOOLBAR_H diff --git a/app/widget/resizablescrollbar/CMakeLists.txt b/app/widget/resizablescrollbar/CMakeLists.txt index a31827510..ee97e209d 100644 --- a/app/widget/resizablescrollbar/CMakeLists.txt +++ b/app/widget/resizablescrollbar/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -16,7 +16,9 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} - widget/resizablescrollbar/resizablescrollbar.h widget/resizablescrollbar/resizablescrollbar.cpp + widget/resizablescrollbar/resizablescrollbar.h + widget/resizablescrollbar/resizabletimelinescrollbar.cpp + widget/resizablescrollbar/resizabletimelinescrollbar.h PARENT_SCOPE ) diff --git a/app/widget/resizablescrollbar/resizablescrollbar.cpp b/app/widget/resizablescrollbar/resizablescrollbar.cpp index 412f63a95..d7cbfb8e8 100644 --- a/app/widget/resizablescrollbar/resizablescrollbar.cpp +++ b/app/widget/resizablescrollbar/resizablescrollbar.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/range.h" -OLIVE_NAMESPACE_ENTER +namespace olive { const int ResizableScrollBar::kHandleWidth = 10; @@ -159,4 +159,4 @@ int ResizableScrollBar::GetActiveMousePos(QMouseEvent *event) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/resizablescrollbar/resizablescrollbar.h b/app/widget/resizablescrollbar/resizablescrollbar.h index 92652a617..1e0d21f13 100644 --- a/app/widget/resizablescrollbar/resizablescrollbar.h +++ b/app/widget/resizablescrollbar/resizablescrollbar.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ResizableScrollBar : public QScrollBar { @@ -65,6 +65,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // RESIZABLESCROLLBAR_H diff --git a/app/widget/resizablescrollbar/resizabletimelinescrollbar.cpp b/app/widget/resizablescrollbar/resizabletimelinescrollbar.cpp new file mode 100644 index 000000000..5174357d8 --- /dev/null +++ b/app/widget/resizablescrollbar/resizabletimelinescrollbar.cpp @@ -0,0 +1,128 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 "resizabletimelinescrollbar.h" + +#include +#include +#include +#include + +namespace olive { + +ResizableTimelineScrollBar::ResizableTimelineScrollBar(QWidget* parent) : + ResizableScrollBar(parent), + points_(nullptr), + scale_(1.0) +{ +} + +ResizableTimelineScrollBar::ResizableTimelineScrollBar(Qt::Orientation orientation, QWidget* parent) : + ResizableScrollBar(orientation, parent), + points_(nullptr), + scale_(1.0) +{ +} + +void ResizableTimelineScrollBar::ConnectTimelinePoints(TimelinePoints *points) +{ + if (points_) { + disconnect(points_->workarea(), &TimelineWorkArea::RangeChanged, this, static_cast(&ResizableTimelineScrollBar::update)); + disconnect(points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast(&ResizableTimelineScrollBar::update)); + disconnect(points_->markers(), &TimelineMarkerList::MarkerAdded, this, static_cast(&ResizableTimelineScrollBar::update)); + disconnect(points_->markers(), &TimelineMarkerList::MarkerRemoved, this, static_cast(&ResizableTimelineScrollBar::update)); + } + + points_ = points; + + if (points_) { + connect(points_->workarea(), &TimelineWorkArea::RangeChanged, this, static_cast(&ResizableTimelineScrollBar::update)); + connect(points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast(&ResizableTimelineScrollBar::update)); + connect(points_->markers(), &TimelineMarkerList::MarkerAdded, this, static_cast(&ResizableTimelineScrollBar::update)); + connect(points_->markers(), &TimelineMarkerList::MarkerRemoved, this, static_cast(&ResizableTimelineScrollBar::update)); + } + + update(); +} + +void ResizableTimelineScrollBar::SetScale(double d) +{ + scale_ = d; + + update(); +} + +void ResizableTimelineScrollBar::paintEvent(QPaintEvent *event) +{ + ResizableScrollBar::paintEvent(event); + + if (points_ + && !timebase().isNull() + && (points_->workarea()->enabled() || !points_->markers()->list().isEmpty())) { + QStyleOptionSlider opt; + initStyleOption(&opt); + + QRect gr = style()->subControlRect(QStyle::CC_ScrollBar, &opt, + QStyle::SC_ScrollBarGroove, this); + + double ratio = scale_ * double(gr.width()) / double(this->maximum() + gr.width()); + + QPainter p(this); + + if (points_->workarea()->enabled()) { + QColor workarea_color(this->palette().highlight().color()); + workarea_color.setAlpha(128); + + qint64 in = qMax(qint64(0), qRound64(ratio * TimeToScene(points_->workarea()->in()))); + + qint64 out; + if (points_->workarea()->out() == RATIONAL_MAX) { + out = gr.width(); + } else { + out = qMin(qint64(gr.width()), qRound64(ratio * TimeToScene(points_->workarea()->out()))); + } + + qint64 length = qMax(qint64(1), out-in); + + p.fillRect(gr.x() + in, + 0, + length, + height(), + workarea_color); + } + + if (!points_->markers()->list().isEmpty()) { + QColor marker_color(0, 255, 0, 128); + foreach (TimelineMarker* marker, points_->markers()->list()) { + int64_t in = qRound64(ratio * TimeToScene(marker->time().in())); + int64_t out = qRound64(ratio * TimeToScene(marker->time().out())); + int64_t length = qMax(int64_t(1), out-in); + + p.fillRect(gr.x() + in, + 0, + length, + height(), + marker_color); + } + } + } +} + +} diff --git a/app/render/backend/opengl/openglframebuffer.h b/app/widget/resizablescrollbar/resizabletimelinescrollbar.h similarity index 50% rename from app/render/backend/opengl/openglframebuffer.h rename to app/widget/resizablescrollbar/resizabletimelinescrollbar.h index e7d8de9b4..6c82a5dd9 100644 --- a/app/render/backend/opengl/openglframebuffer.h +++ b/app/widget/resizablescrollbar/resizabletimelinescrollbar.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -18,48 +18,36 @@ ***/ -#ifndef OPENGLFRAMEBUFFER_H -#define OPENGLFRAMEBUFFER_H +#ifndef RESIZABLETIMELINESCROLLBAR_H +#define RESIZABLETIMELINESCROLLBAR_H -#include +#include "resizablescrollbar.h" +#include "timeline/timelinepoints.h" +#include "widget/timelinewidget/timelinescaledobject.h" -#include "opengltexture.h" +namespace olive { -OLIVE_NAMESPACE_ENTER - -class OpenGLFramebuffer : public QObject +class ResizableTimelineScrollBar : public ResizableScrollBar, public TimelineScaledObject { Q_OBJECT public: - OpenGLFramebuffer(); - virtual ~OpenGLFramebuffer() override; + ResizableTimelineScrollBar(QWidget* parent = nullptr); + ResizableTimelineScrollBar(Qt::Orientation orientation, QWidget* parent = nullptr); - void Create(QOpenGLContext *ctx); + void ConnectTimelinePoints(TimelinePoints* points); - bool IsCreated() const; + void SetScale(double d); - void Bind(); - - void Release(); - - void Attach(OpenGLTexture* texture, bool clear = false); - void Attach(OpenGLTexturePtr texture, bool clear = false); - - void Detach(); - - const GLuint& buffer() const; - -public slots: - void Destroy(); +protected: + virtual void paintEvent(QPaintEvent* event) override; private: - QOpenGLContext* context_; + TimelinePoints* points_; - GLuint buffer_; + double scale_; - OpenGLTexture* texture_; }; -OLIVE_NAMESPACE_EXIT +} -#endif // OPENGLFRAMEBUFFER_H +#endif // RESIZABLETIMELINESCROLLBAR_H diff --git a/app/widget/scope/CMakeLists.txt b/app/widget/scope/CMakeLists.txt index 91c4f0b44..2002d1a11 100644 --- a/app/widget/scope/CMakeLists.txt +++ b/app/widget/scope/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/scope/histogram/CMakeLists.txt b/app/widget/scope/histogram/CMakeLists.txt index 3204a53d7..a2b058cfc 100644 --- a/app/widget/scope/histogram/CMakeLists.txt +++ b/app/widget/scope/histogram/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/scope/histogram/histogram.cpp b/app/widget/scope/histogram/histogram.cpp index e89918c06..54211a066 100644 --- a/app/widget/scope/histogram/histogram.cpp +++ b/app/widget/scope/histogram/histogram.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,12 +22,12 @@ #include #include +#include #include "common/qtutils.h" #include "node/node.h" -#include "render/backend/opengl/openglrenderfunctions.h" -OLIVE_NAMESPACE_ENTER +namespace olive { HistogramScope::HistogramScope(QWidget* parent) : ScopeBase(parent) @@ -36,74 +36,33 @@ HistogramScope::HistogramScope(QWidget* parent) : HistogramScope::~HistogramScope() { - CleanUp(); - - if (context()) { - disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this, - &HistogramScope::CleanUp); - } + OnDestroy(); } -void HistogramScope::initializeGL() +void HistogramScope::OnInit() { - ScopeBase::initializeGL(); + ScopeBase::OnInit(); - pipeline_secondary_ = CreateSecondaryShader(); - - connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, - &HistogramScope::CleanUp, Qt::DirectConnection); + ShaderCode secondary_code(FileFunctions::ReadFileAsString(":/shaders/rgbhistogram_secondary.frag"), + FileFunctions::ReadFileAsString(":/shaders/rgbhistogram.vert")); + pipeline_secondary_ = renderer()->CreateNativeShader(secondary_code); } -void HistogramScope::AssertAdditionalTextures() +void HistogramScope::OnDestroy() { - if (!texture_row_sums_.IsCreated() - || texture_row_sums_.width() != width() - || texture_row_sums_.height() != height()) { - texture_row_sums_.Destroy(); - texture_row_sums_.Create(context(), VideoParams(width(), - height(), managed_tex().format())); - } + ScopeBase::OnDestroy(); + + pipeline_secondary_.clear(); + texture_row_sums_ = nullptr; } -void HistogramScope::CleanUp() +ShaderCode HistogramScope::GenerateShaderCode() { - makeCurrent(); - - pipeline_secondary_ = nullptr; - texture_row_sums_.Destroy(); - - doneCurrent(); + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/rgbhistogram.frag"), + FileFunctions::ReadFileAsString(":/shaders/default.vert")); } -OpenGLShaderPtr HistogramScope::CreateShader() -{ - OpenGLShaderPtr pipeline = OpenGLShader::Create(); - - pipeline->create(); - pipeline->addShaderFromSourceCode(QOpenGLShader::Vertex, - OpenGLShader::CodeDefaultVertex()); - pipeline->addShaderFromSourceCode(QOpenGLShader::Fragment, - Node::ReadFileAsString(":/shaders/rgbhistogram.frag")); - pipeline->link(); - - return pipeline; -} - -OpenGLShaderPtr HistogramScope::CreateSecondaryShader() -{ - OpenGLShaderPtr shader = OpenGLShader::Create(); - - shader->create(); - shader->addShaderFromSourceCode(QOpenGLShader::Vertex, - Node::ReadFileAsString(":/shaders/rgbhistogram.vert")); - shader->addShaderFromSourceCode(QOpenGLShader::Fragment, - Node::ReadFileAsString(":/shaders/rgbhistogram_secondary.frag")); - shader->link(); - - return shader; -} - -void HistogramScope::DrawScope() +void HistogramScope::DrawScope(TexturePtr managed_tex, QVariant pipeline) { float histogram_scale = 0.80f; // This value is eyeballed for usefulness. Until we have a geometry @@ -112,43 +71,30 @@ void HistogramScope::DrawScope() float histogram_base = 2.5f; float histogram_power = 1.0f / histogram_base; - pipeline()->bind(); - pipeline()->setUniformValue("ove_resolution", managed_tex().width(), - managed_tex().height()); - pipeline()->setUniformValue("ove_viewport", width(), height()); - pipeline()->setUniformValue("histogram_scale", histogram_scale); - pipeline()->release(); + ShaderJob shader_job; - AssertAdditionalTextures(); + shader_job.InsertValue(QStringLiteral("viewport"), ShaderValue(QVector2D(width(), height()), NodeParam::kVec2)); + shader_job.InsertValue(QStringLiteral("histogram_scale"), ShaderValue(histogram_scale, NodeParam::kFloat)); + shader_job.InsertValue(QStringLiteral("histogram_power"), ShaderValue(histogram_power, NodeParam::kFloat)); - framebuffer().Attach(&texture_row_sums_, true); - framebuffer().Bind(); + if (!texture_row_sums_ + || texture_row_sums_->width() != this->width() + || texture_row_sums_->height() != this->height()) { + texture_row_sums_ = renderer()->CreateTexture(VideoParams(width(), height(), + managed_tex->format(), + managed_tex->channel_count())); + } - managed_tex().Bind(); + // Draw managed texture to a sums texture + shader_job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(managed_tex), NodeParam::kTexture)); + renderer()->BlitToTexture(pipeline, shader_job, texture_row_sums_.get()); - OpenGLRenderFunctions::Blit(pipeline()); - - managed_tex().Release(); - - framebuffer().Release(); - framebuffer().Detach(); - - pipeline_secondary_->bind(); - pipeline_secondary_->setUniformValue("ove_resolution", - texture_row_sums_.width(), texture_row_sums_.height()); - pipeline_secondary_->setUniformValue("ove_viewport", width(), height()); - pipeline_secondary_->setUniformValue("histogram_scale", histogram_scale); - pipeline_secondary_->setUniformValue("histogram_power", histogram_power); - pipeline_secondary_->release(); - - texture_row_sums_.Bind(); - - OpenGLRenderFunctions::Blit(pipeline_secondary_); - - texture_row_sums_.Release(); + // Draw sums into a histogram + shader_job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(texture_row_sums_), NodeParam::kTexture)); + renderer()->Blit(pipeline_secondary_, shader_job, texture_row_sums_->params()); // Draw line overlays - QPainter p(this); + QPainter p(inner_widget()); QFont font = p.font(); font.setPixelSize(10); QFontMetrics font_metrics = QFontMetrics(font); @@ -173,31 +119,31 @@ void HistogramScope::DrawScope() float histogram_dim_x = ceil((width() - 1.0) * histogram_scale); float histogram_dim_y = ceil((height() - 1.0) * histogram_scale); float histogram_start_dim_x = - ((width() - 1.0) - histogram_dim_x) / 2.0f; + ((width() - 1.0) - histogram_dim_x) / 2.0f; float histogram_start_dim_y = - ((height() - 1.0) - histogram_dim_y) / 2.0f; + ((height() - 1.0) - histogram_dim_y) / 2.0f; float histogram_end_dim_x = (width() - 1.0) - histogram_start_dim_x; // for (int i=0; i <= histogram_steps; i++) { for(std::vector::iterator it = histogram_increments.begin(); - it != histogram_increments.end(); it++) { + it != histogram_increments.end(); it++) { histogram_lines[it - histogram_increments.begin()].setLine( - histogram_start_dim_x, - (histogram_dim_y * pow(1.0 - *it, histogram_base)) + - histogram_start_dim_y, - histogram_end_dim_x, - (histogram_dim_y * pow(1.0 - *it, histogram_base)) + - histogram_start_dim_y); - label = QString::number( - *it * 100, 'f', 1) + "%"; - font_x_offset = QFontMetricsWidth(font_metrics, label) + 4; + histogram_start_dim_x, + (histogram_dim_y * pow(1.0 - *it, histogram_base)) + + histogram_start_dim_y, + histogram_end_dim_x, + (histogram_dim_y * pow(1.0 - *it, histogram_base)) + + histogram_start_dim_y); + label = QString::number( + *it * 100, 'f', 1) + "%"; + font_x_offset = QtUtils::QFontMetricsWidth(font_metrics, label) + 4; - p.drawText( - histogram_start_dim_x - font_x_offset, - (histogram_dim_y * pow(1.0 - *it, histogram_base)) + + p.drawText( + histogram_start_dim_x - font_x_offset, + (histogram_dim_y * pow(1.0 - *it, histogram_base)) + histogram_start_dim_y + font_y_offset, label); } p.drawLines(histogram_lines); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/scope/histogram/histogram.h b/app/widget/scope/histogram/histogram.h index 70751355f..756a40d54 100644 --- a/app/widget/scope/histogram/histogram.h +++ b/app/widget/scope/histogram/histogram.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "widget/scope/scopebase/scopebase.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class HistogramScope : public ScopeBase { @@ -33,24 +33,23 @@ public: virtual ~HistogramScope() override; +protected slots: + virtual void OnInit() override; + + virtual void OnDestroy() override; + protected: - virtual void initializeGL() override; + virtual ShaderCode GenerateShaderCode() override; + QVariant CreateSecondaryShader(); - virtual OpenGLShaderPtr CreateShader() override; - OpenGLShaderPtr CreateSecondaryShader(); - - void AssertAdditionalTextures(); - - virtual void DrawScope() override; + virtual void DrawScope(TexturePtr managed_tex, QVariant pipeline) override; private: - OpenGLShaderPtr pipeline_secondary_; - OpenGLTexture texture_row_sums_; + QVariant pipeline_secondary_; + TexturePtr texture_row_sums_; -private slots: - void CleanUp(); }; -OLIVE_NAMESPACE_EXIT +} #endif // HISTOGRAMSCOPE_H diff --git a/app/widget/scope/scopebase/CMakeLists.txt b/app/widget/scope/scopebase/CMakeLists.txt index ca6d924c3..f49abc150 100644 --- a/app/widget/scope/scopebase/CMakeLists.txt +++ b/app/widget/scope/scopebase/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/scope/scopebase/scopebase.cpp b/app/widget/scope/scopebase/scopebase.cpp index e3b65d48c..3f9c4cd68 100644 --- a/app/widget/scope/scopebase/scopebase.cpp +++ b/app/widget/scope/scopebase/scopebase.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,9 +20,9 @@ #include "scopebase.h" -#include "render/backend/opengl/openglrenderfunctions.h" +#include "config/config.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ScopeBase::ScopeBase(QWidget* parent) : ManagedDisplayWidget(parent), @@ -33,11 +33,7 @@ ScopeBase::ScopeBase(QWidget* parent) : ScopeBase::~ScopeBase() { - CleanUp(); - - if (context()) { - disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ScopeBase::CleanUp); - } + OnDestroy(); } void ScopeBase::SetBuffer(Frame *frame) @@ -54,18 +50,15 @@ void ScopeBase::showEvent(QShowEvent* e) UploadTextureFromBuffer(); } -OpenGLShaderPtr ScopeBase::CreateShader() +void ScopeBase::DrawScope(TexturePtr managed_tex, QVariant pipeline) { - return OpenGLShader::CreateDefault(); -} + ShaderJob job; -void ScopeBase::DrawScope() -{ - managed_tex().Bind(); + job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(managed_tex), NodeParam::kTexture)); - OpenGLRenderFunctions::Blit(pipeline()); - - managed_tex().Release(); + renderer()->Blit(pipeline, job, VideoParams(width(), height(), + static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + VideoParams::kInternalChannelCount)); } void ScopeBase::UploadTextureFromBuffer() @@ -77,17 +70,18 @@ void ScopeBase::UploadTextureFromBuffer() if (buffer_) { makeCurrent(); - if (!texture_.IsCreated() - || texture_.width() != buffer_->width() - || texture_.height() != buffer_->height() - || texture_.format() != buffer_->format()) { - texture_.Destroy(); - managed_tex_.Destroy(); + if (!texture_ + || texture_->width() != buffer_->width() + || texture_->height() != buffer_->height() + || texture_->format() != buffer_->format()) { + texture_ = nullptr; + managed_tex_ = nullptr; - texture_.Create(context(), buffer_); - managed_tex_.Create(context(), buffer_->video_params()); + texture_ = renderer()->CreateTexture(buffer_->video_params(), + buffer_->data(), buffer_->linesize_pixels()); + managed_tex_ = renderer()->CreateTexture(buffer_->video_params()); } else { - texture_.Upload(buffer_); + texture_->Upload(buffer_->data(), buffer_->linesize_pixels()); } doneCurrent(); @@ -96,58 +90,35 @@ void ScopeBase::UploadTextureFromBuffer() update(); } -void ScopeBase::CleanUp() +void ScopeBase::OnInit() { - makeCurrent(); - - pipeline_ = nullptr; - texture_.Destroy(); - managed_tex_.Destroy(); - framebuffer_.Destroy(); - - doneCurrent(); -} - -void ScopeBase::initializeGL() -{ - ManagedDisplayWidget::initializeGL(); - - pipeline_ = CreateShader(); - - framebuffer_.Create(context()); - - connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ScopeBase::CleanUp, Qt::DirectConnection); + ManagedDisplayWidget::OnInit(); UploadTextureFromBuffer(); + + pipeline_ = renderer()->CreateNativeShader(GenerateShaderCode()); } -void ScopeBase::paintGL() +void ScopeBase::OnPaint() { - QOpenGLFunctions* f = context()->functions(); + // Clear display surface + renderer()->ClearDestination(); - f->glClearColor(0, 0, 0, 0); - f->glClear(GL_COLOR_BUFFER_BIT); - - if (buffer_ && pipeline() && texture_.IsCreated()) { + if (buffer_) { // Convert reference frame to display space - framebuffer_.Attach(&managed_tex_); - framebuffer_.Bind(); + renderer()->BlitColorManaged(color_service(), texture_, true, managed_tex_.get()); - texture_.Bind(); - - f->glViewport(0, 0, texture_.width(), texture_.height()); - - color_service()->ProcessOpenGL(); - - texture_.Release(); - - framebuffer_.Release(); - framebuffer_.Detach(); - - f->glViewport(0, 0, width(), height()); - - DrawScope(); + DrawScope(managed_tex_, pipeline_); } } -OLIVE_NAMESPACE_EXIT +void ScopeBase::OnDestroy() +{ + ManagedDisplayWidget::OnDestroy(); + + managed_tex_ = nullptr; + texture_ = nullptr; + pipeline_.clear(); +} + +} diff --git a/app/widget/scope/scopebase/scopebase.h b/app/widget/scope/scopebase/scopebase.h index 41e2edefc..4e7d852f9 100644 --- a/app/widget/scope/scopebase/scopebase.h +++ b/app/widget/scope/scopebase/scopebase.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,13 +22,10 @@ #define SCOPEBASE_H #include "codec/frame.h" -#include "render/backend/opengl/openglcolorprocessor.h" -#include "render/backend/opengl/openglframebuffer.h" -#include "render/backend/opengl/openglshader.h" -#include "render/backend/opengl/opengltexture.h" +#include "render/colorprocessor.h" #include "widget/manageddisplay/manageddisplay.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ScopeBase : public ManagedDisplayWidget { @@ -40,50 +37,38 @@ public: public slots: void SetBuffer(Frame* frame); +protected slots: + virtual void OnInit() override; + + virtual void OnPaint() override; + + virtual void OnDestroy() override; + protected: - virtual void initializeGL() override; - - virtual void paintGL() override; - virtual void showEvent(QShowEvent* e) override; - virtual OpenGLShaderPtr CreateShader(); + virtual ShaderCode GenerateShaderCode() = 0; - virtual void DrawScope(); - - OpenGLShaderPtr pipeline() - { - return pipeline_; - } - - OpenGLTexture& managed_tex() - { - return managed_tex_; - } - - OpenGLFramebuffer& framebuffer() - { - return framebuffer_; - } + /** + * @brief Draw function + * + * Override this if your sub-class scope needs extra drawing. + */ + virtual void DrawScope(TexturePtr managed_tex, QVariant pipeline); private: void UploadTextureFromBuffer(); - OpenGLShaderPtr pipeline_; + QVariant pipeline_; - OpenGLTexture texture_; + TexturePtr texture_; - OpenGLTexture managed_tex_; - - OpenGLFramebuffer framebuffer_; + TexturePtr managed_tex_; Frame* buffer_; -private slots: - void CleanUp(); - }; -OLIVE_NAMESPACE_EXIT +} #endif // SCOPEBASE_H diff --git a/app/widget/scope/waveform/CMakeLists.txt b/app/widget/scope/waveform/CMakeLists.txt index 61a980b8f..c2729d17a 100644 --- a/app/widget/scope/waveform/CMakeLists.txt +++ b/app/widget/scope/waveform/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/scope/waveform/waveform.cpp b/app/widget/scope/waveform/waveform.cpp index ff4f1296b..c92a7158a 100644 --- a/app/widget/scope/waveform/waveform.cpp +++ b/app/widget/scope/waveform/waveform.cpp @@ -2,7 +2,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,65 +24,71 @@ #include #include #include +#include +#include #include "common/qtutils.h" +#include "config/config.h" #include "node/node.h" -#include "render/backend/opengl/openglrenderfunctions.h" -OLIVE_NAMESPACE_ENTER +namespace olive { WaveformScope::WaveformScope(QWidget* parent) : ScopeBase(parent) { } -OpenGLShaderPtr WaveformScope::CreateShader() +WaveformScope::~WaveformScope() { - OpenGLShaderPtr pipeline = OpenGLShader::Create(); - - pipeline->create(); - pipeline->addShaderFromSourceCode(QOpenGLShader::Vertex, - Node::ReadFileAsString(":/shaders/rgbwaveform.vert")); - pipeline->addShaderFromSourceCode(QOpenGLShader::Fragment, - Node::ReadFileAsString(":/shaders/rgbwaveform.frag")); - pipeline->link(); - - return pipeline; + OnDestroy(); } -void WaveformScope::DrawScope() +ShaderCode WaveformScope::GenerateShaderCode() +{ + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/rgbwaveform.frag"), + FileFunctions::ReadFileAsString(":/shaders/rgbwaveform.vert")); +} + +void WaveformScope::DrawScope(TexturePtr managed_tex, QVariant pipeline) { float waveform_scale = 0.80f; // Draw waveform through shader - pipeline()->bind(); - pipeline()->setUniformValue("ove_resolution", managed_tex().width(), managed_tex().height()); - pipeline()->setUniformValue("ove_viewport", width(), height()); - GLfloat luma[3] = {0.0, 0.0, 0.0}; - color_manager()->GetDefaultLumaCoefs(luma); - pipeline()->setUniformValue("luma_coeffs", luma[0], luma[1], luma[2]); + ShaderJob job; + + // Set viewport size + job.InsertValue(QStringLiteral("viewport"), + ShaderValue(QVector2D(width(), height()), NodeParam::kVec2)); + + // Set luma coefficients + double luma_coeffs[3] = {0.0f, 0.0f, 0.0f}; + color_manager()->GetDefaultLumaCoefs(luma_coeffs); + job.InsertValue(QStringLiteral("luma_coeffs"), + ShaderValue(QVector3D(luma_coeffs[0], luma_coeffs[1], luma_coeffs[2]), NodeParam::kVec3)); + // Scale of the waveform relative to the viewport surface. - pipeline()->setUniformValue("waveform_scale", waveform_scale); + job.InsertValue(QStringLiteral("waveform_scale"), + ShaderValue(waveform_scale, NodeParam::kFloat)); - pipeline()->release(); + // Insert source texture + job.InsertValue(QStringLiteral("ove_maintex"), + ShaderValue(QVariant::fromValue(managed_tex), NodeParam::kTexture)); - managed_tex().Bind(); - - OpenGLRenderFunctions::Blit(pipeline()); - - managed_tex().Release(); + renderer()->Blit(pipeline, job, VideoParams(width(), height(), + static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + VideoParams::kInternalChannelCount)); float waveform_dim_x = ceil((width() - 1.0) * waveform_scale); float waveform_dim_y = ceil((height() - 1.0) * waveform_scale); float waveform_start_dim_x = - ((width() - 1.0) - waveform_dim_x) / 2.0f; + ((width() - 1.0) - waveform_dim_x) / 2.0f; float waveform_start_dim_y = - ((height() - 1.0) - waveform_dim_y) / 2.0f; + ((height() - 1.0) - waveform_dim_y) / 2.0f; float waveform_end_dim_x = (width() - 1.0) - waveform_start_dim_x; // Draw line overlays - QPainter p(this); + QPainter p(inner_widget()); QFont font; font.setPixelSize(10); QFontMetrics font_metrics = QFontMetrics(font); @@ -100,19 +106,20 @@ void WaveformScope::DrawScope() for (int i=0; i <= ire_steps; i++) { ire_lines[i].setLine( - waveform_start_dim_x, - (waveform_dim_y * (i * ire_increment)) + waveform_start_dim_y, - waveform_end_dim_x, - (waveform_dim_y * (i * ire_increment)) + waveform_start_dim_y); - label = QString::number(1.0 - (i * ire_increment), 'f', 1); - font_x_offset = QFontMetricsWidth(font_metrics, label) + 4; + waveform_start_dim_x, + (waveform_dim_y * (i * ire_increment)) + waveform_start_dim_y, + waveform_end_dim_x, + (waveform_dim_y * (i * ire_increment)) + waveform_start_dim_y); + label = QString::number(1.0 - (i * ire_increment), 'f', 1); + font_x_offset = QtUtils::QFontMetricsWidth(font_metrics, label) + 4; - p.drawText( - waveform_start_dim_x - font_x_offset, - (waveform_dim_y * (i * ire_increment)) + waveform_start_dim_y + font_y_offset, - label); + p.drawText( + waveform_start_dim_x - font_x_offset, + (waveform_dim_y * (i * ire_increment)) + waveform_start_dim_y + font_y_offset, + label); } + p.drawLines(ire_lines); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/scope/waveform/waveform.h b/app/widget/scope/waveform/waveform.h index 04a464e52..743d3de5c 100644 --- a/app/widget/scope/waveform/waveform.h +++ b/app/widget/scope/waveform/waveform.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "widget/scope/scopebase/scopebase.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class WaveformScope : public ScopeBase { @@ -31,13 +31,15 @@ class WaveformScope : public ScopeBase public: WaveformScope(QWidget* parent = nullptr); -protected: - virtual OpenGLShaderPtr CreateShader() override; + virtual ~WaveformScope() override; - virtual void DrawScope() override; +protected: + virtual ShaderCode GenerateShaderCode() override; + + virtual void DrawScope(TexturePtr managed_tex, QVariant pipeline) override; }; -OLIVE_NAMESPACE_EXIT +} #endif // WAVEFORMSCOPE_H diff --git a/app/widget/slider/CMakeLists.txt b/app/widget/slider/CMakeLists.txt index 3a14e174f..ef2b3443c 100644 --- a/app/widget/slider/CMakeLists.txt +++ b/app/widget/slider/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/slider/floatslider.cpp b/app/widget/slider/floatslider.cpp index 2793fcf17..4c30e7d0b 100644 --- a/app/widget/slider/floatslider.cpp +++ b/app/widget/slider/floatslider.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { FloatSlider::FloatSlider(QWidget *parent) : SliderBase(kFloat, parent), @@ -184,4 +184,4 @@ void FloatSlider::ConvertValue(QVariant v) emit ValueChanged(v.toDouble()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/slider/floatslider.h b/app/widget/slider/floatslider.h index 27b6aa007..51b806fce 100644 --- a/app/widget/slider/floatslider.h +++ b/app/widget/slider/floatslider.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "sliderbase.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class FloatSlider : public SliderBase { @@ -73,6 +73,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // FLOATSLIDER_H diff --git a/app/widget/slider/integerslider.cpp b/app/widget/slider/integerslider.cpp index 25615e2a5..2c2973cd1 100644 --- a/app/widget/slider/integerslider.cpp +++ b/app/widget/slider/integerslider.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "integerslider.h" -OLIVE_NAMESPACE_ENTER +namespace olive { IntegerSlider::IntegerSlider(QWidget* parent) : SliderBase(kInteger, parent) @@ -72,4 +72,4 @@ void IntegerSlider::ConvertValue(QVariant v) emit ValueChanged(v.toInt()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/slider/integerslider.h b/app/widget/slider/integerslider.h index 01ea4f064..bb4236366 100644 --- a/app/widget/slider/integerslider.h +++ b/app/widget/slider/integerslider.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "sliderbase.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class IntegerSlider : public SliderBase { @@ -49,6 +49,6 @@ private slots: void ConvertValue(QVariant v); }; -OLIVE_NAMESPACE_EXIT +} #endif // INTEGERSLIDER_H diff --git a/app/widget/slider/sliderbase.cpp b/app/widget/slider/sliderbase.cpp index 727b2aa01..b3e6ce6ee 100644 --- a/app/widget/slider/sliderbase.cpp +++ b/app/widget/slider/sliderbase.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "core.h" #include "window/mainwindow/mainwindow.h" -OLIVE_NAMESPACE_ENTER +namespace olive { SliderBase::SliderBase(Mode mode, QWidget *parent) : QStackedWidget(parent), @@ -143,8 +143,8 @@ void SliderBase::SetValue(const QVariant &v) UpdateLabel(value_); } -void SliderBase::SetDefaultValue(const QVariant &v) -{ +void SliderBase::SetDefaultValue(const QVariant &v) +{ default_value_ = v; } @@ -203,12 +203,12 @@ QString SliderBase::GetFormat() const void SliderBase::RepositionLadder() { QPoint label_global_pos = label_->mapToGlobal(label_->pos()); - int text_width = QFontMetricsWidth(label_->fontMetrics(), label_->text()); + int text_width = QtUtils::QFontMetricsWidth(label_->fontMetrics(), label_->text()); QPoint ladder_pos(label_global_pos.x(), label_global_pos.y() + label_->height() / 2 - drag_ladder_->height() / 2); if (ladder_element_count_ > 0) { - ladder_pos.setX(ladder_pos.x() + text_width + QFontMetricsWidth(label_->fontMetrics(), QStringLiteral("H"))); + ladder_pos.setX(ladder_pos.x() + text_width + QtUtils::QFontMetricsWidth(label_->fontMetrics(), QStringLiteral("H"))); } else { ladder_pos.setX(ladder_pos.x() + text_width / 2 - drag_ladder_->width() / 2); } @@ -395,4 +395,4 @@ void SliderBase::ResetValue() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/slider/sliderbase.h b/app/widget/slider/sliderbase.h index 7e8062694..31c6d31c4 100644 --- a/app/widget/slider/sliderbase.h +++ b/app/widget/slider/sliderbase.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "sliderladder.h" #include "widget/focusablelineedit/focusablelineedit.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SliderBase : public QStackedWidget { Q_OBJECT @@ -141,6 +141,6 @@ private slots: void ResetValue(); }; -OLIVE_NAMESPACE_EXIT +} #endif // SLIDERBASE_H diff --git a/app/widget/slider/sliderlabel.cpp b/app/widget/slider/sliderlabel.cpp index ffc07fb2c..11048658f 100644 --- a/app/widget/slider/sliderlabel.cpp +++ b/app/widget/slider/sliderlabel.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { SliderLabel::SliderLabel(QWidget *parent) : QLabel(parent) @@ -69,4 +69,4 @@ void SliderLabel::focusInEvent(QFocusEvent *event) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/slider/sliderlabel.h b/app/widget/slider/sliderlabel.h index 68d0666e3..2f698eb2c 100644 --- a/app/widget/slider/sliderlabel.h +++ b/app/widget/slider/sliderlabel.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SliderLabel : public QLabel { @@ -47,6 +47,6 @@ signals: }; -OLIVE_NAMESPACE_EXIT +} #endif // SLIDERLABEL_H diff --git a/app/widget/slider/sliderladder.cpp b/app/widget/slider/sliderladder.cpp index c5c0054ae..3412f7d5f 100644 --- a/app/widget/slider/sliderladder.cpp +++ b/app/widget/slider/sliderladder.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -33,7 +33,7 @@ #include "common/clamp.h" #include "common/lerp.h" -OLIVE_NAMESPACE_ENTER +namespace olive { SliderLadder::SliderLadder(double drag_multiplier, int nb_outer_values, QWidget* parent) : QFrame(parent, Qt::Popup), @@ -241,4 +241,4 @@ void SliderLadderElement::UpdateLabel() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/slider/sliderladder.h b/app/widget/slider/sliderladder.h index 9fc30e511..aac5c1bd3 100644 --- a/app/widget/slider/sliderladder.h +++ b/app/widget/slider/sliderladder.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SliderLadderElement : public QWidget { @@ -98,6 +98,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // SLIDERLADDER_H diff --git a/app/widget/slider/stringslider.cpp b/app/widget/slider/stringslider.cpp index c096eeed0..33db4d8f5 100644 --- a/app/widget/slider/stringslider.cpp +++ b/app/widget/slider/stringslider.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "stringslider.h" -OLIVE_NAMESPACE_ENTER +namespace olive { StringSlider::StringSlider(QWidget* parent) : SliderBase(kString, parent) @@ -49,4 +49,4 @@ void StringSlider::ConvertValue(QVariant v) emit ValueChanged(v.toString()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/slider/stringslider.h b/app/widget/slider/stringslider.h index 573af0482..232df2480 100644 --- a/app/widget/slider/stringslider.h +++ b/app/widget/slider/stringslider.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "sliderbase.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class StringSlider : public SliderBase { @@ -47,6 +47,6 @@ private slots: void ConvertValue(QVariant v); }; -OLIVE_NAMESPACE_EXIT +} #endif // STRINGSLIDER_H diff --git a/app/widget/slider/timeslider.cpp b/app/widget/slider/timeslider.cpp index 5180819ff..146d5750a 100644 --- a/app/widget/slider/timeslider.cpp +++ b/app/widget/slider/timeslider.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "common/timecodefunctions.h" #include "core.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimeSlider::TimeSlider(QWidget *parent) : IntegerSlider(parent) @@ -63,4 +63,4 @@ void TimeSlider::TimecodeDisplayChanged() UpdateLabel(Value()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/slider/timeslider.h b/app/widget/slider/timeslider.h index d1e835dca..a8e6d977c 100644 --- a/app/widget/slider/timeslider.h +++ b/app/widget/slider/timeslider.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "common/rational.h" #include "integerslider.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimeSlider : public IntegerSlider { @@ -47,6 +47,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMESLIDER_H diff --git a/app/widget/standardcombos/CMakeLists.txt b/app/widget/standardcombos/CMakeLists.txt index cbfac1d51..8f4354b74 100644 --- a/app/widget/standardcombos/CMakeLists.txt +++ b/app/widget/standardcombos/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/standardcombos/channellayoutcombobox.h b/app/widget/standardcombos/channellayoutcombobox.h index 7deec22e6..0ff814ed8 100644 --- a/app/widget/standardcombos/channellayoutcombobox.h +++ b/app/widget/standardcombos/channellayoutcombobox.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "render/audioparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ChannelLayoutComboBox : public QComboBox { @@ -57,6 +57,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // CHANNELLAYOUTCOMBOBOX_H diff --git a/app/widget/standardcombos/frameratecombobox.h b/app/widget/standardcombos/frameratecombobox.h index 00eefe7aa..d4482d7c1 100644 --- a/app/widget/standardcombos/frameratecombobox.h +++ b/app/widget/standardcombos/frameratecombobox.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/rational.h" #include "render/videoparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class FrameRateComboBox : public QComboBox { @@ -57,6 +57,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // FRAMERATECOMBOBOX_H diff --git a/app/widget/standardcombos/interlacedcombobox.h b/app/widget/standardcombos/interlacedcombobox.h index 1bf54806b..9c8599562 100644 --- a/app/widget/standardcombos/interlacedcombobox.h +++ b/app/widget/standardcombos/interlacedcombobox.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "render/videoparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class InterlacedComboBox : public QComboBox { @@ -52,6 +52,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // INTERLACEDCOMBOBOX_H diff --git a/app/widget/standardcombos/pixelaspectratiocombobox.h b/app/widget/standardcombos/pixelaspectratiocombobox.h index a5e2d02b9..a78aae0b3 100644 --- a/app/widget/standardcombos/pixelaspectratiocombobox.h +++ b/app/widget/standardcombos/pixelaspectratiocombobox.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/ratiodialog.h" #include "render/videoparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PixelAspectRatioComboBox : public QComboBox { @@ -122,6 +122,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // PIXELASPECTRATIOCOMBOBOX_H diff --git a/app/widget/standardcombos/pixelformatcombobox.h b/app/widget/standardcombos/pixelformatcombobox.h index 48638a14b..3614a7f35 100644 --- a/app/widget/standardcombos/pixelformatcombobox.h +++ b/app/widget/standardcombos/pixelformatcombobox.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,34 +23,33 @@ #include -#include "render/pixelformat.h" +#include "render/videoparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PixelFormatComboBox : public QComboBox { Q_OBJECT public: - PixelFormatComboBox(bool alpha_only, bool float_only, QWidget* parent = nullptr) : + PixelFormatComboBox(bool float_only, QWidget* parent = nullptr) : QComboBox(parent) { // Set up preview formats - for (int i=0;i(i); + for (int i=0;i(i); - if ((!alpha_only || PixelFormat::FormatHasAlphaChannel(pix_fmt)) - && (!float_only || PixelFormat::FormatIsFloat(pix_fmt))) { - this->addItem(PixelFormat::GetName(pix_fmt), pix_fmt); + if (!float_only || VideoParams::FormatIsFloat(pix_fmt)) { + this->addItem(VideoParams::GetFormatName(pix_fmt), pix_fmt); } } } - PixelFormat::Format GetPixelFormat() const + VideoParams::Format GetPixelFormat() const { - return static_cast(this->currentData().toInt()); + return static_cast(this->currentData().toInt()); } - void SetPixelFormat(PixelFormat::Format fmt) + void SetPixelFormat(VideoParams::Format fmt) { for (int i=0; icount(); i++) { if (this->itemData(i).toInt() == fmt) { @@ -62,6 +61,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // PIXELFORMATCOMBOBOX_H diff --git a/app/widget/standardcombos/sampleratecombobox.h b/app/widget/standardcombos/sampleratecombobox.h index e7300517f..f1689126f 100644 --- a/app/widget/standardcombos/sampleratecombobox.h +++ b/app/widget/standardcombos/sampleratecombobox.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "render/audioparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SampleRateComboBox : public QComboBox { @@ -56,6 +56,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // SAMPLERATECOMBOBOX_H diff --git a/app/widget/standardcombos/standardcombos.h b/app/widget/standardcombos/standardcombos.h index e59aedab8..4e275bbe1 100644 --- a/app/widget/standardcombos/standardcombos.h +++ b/app/widget/standardcombos/standardcombos.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 diff --git a/app/widget/standardcombos/videodividercombobox.h b/app/widget/standardcombos/videodividercombobox.h index 89b6c1b6a..e7924cbb2 100644 --- a/app/widget/standardcombos/videodividercombobox.h +++ b/app/widget/standardcombos/videodividercombobox.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "render/videoparams.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class VideoDividerComboBox : public QComboBox { @@ -64,6 +64,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // VIDEODIVIDERCOMBOBOX_H diff --git a/app/widget/taskview/CMakeLists.txt b/app/widget/taskview/CMakeLists.txt index 26bcced3f..b9e308173 100644 --- a/app/widget/taskview/CMakeLists.txt +++ b/app/widget/taskview/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/taskview/elapsedcounterwidget.cpp b/app/widget/taskview/elapsedcounterwidget.cpp index 04cc05e39..e38c5e4b8 100644 --- a/app/widget/taskview/elapsedcounterwidget.cpp +++ b/app/widget/taskview/elapsedcounterwidget.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/timecodefunctions.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ElapsedCounterWidget::ElapsedCounterWidget(QWidget* parent) : QWidget(parent), @@ -65,6 +65,11 @@ void ElapsedCounterWidget::Start(qint64 start_time) UpdateTimers(); } +void ElapsedCounterWidget::Stop() +{ + elapsed_timer_.stop(); +} + void ElapsedCounterWidget::UpdateTimers() { int64_t elapsed_ms, remaining_ms; @@ -85,4 +90,4 @@ void ElapsedCounterWidget::UpdateTimers() remaining_lbl_->setText(tr("Remaining: %1").arg(Timecode::TimeToString(remaining_ms))); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/taskview/elapsedcounterwidget.h b/app/widget/taskview/elapsedcounterwidget.h index fcfdff43a..d85d7ba70 100644 --- a/app/widget/taskview/elapsedcounterwidget.h +++ b/app/widget/taskview/elapsedcounterwidget.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ElapsedCounterWidget : public QWidget { @@ -40,6 +40,9 @@ public: void Start(); void Start(qint64 start_time); +public slots: + void Stop(); + private: QLabel* elapsed_lbl_; @@ -56,6 +59,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // ELAPSEDCOUNTERWIDGET_H diff --git a/app/widget/taskview/taskview.cpp b/app/widget/taskview/taskview.cpp index f3c264248..ef1c83c8c 100644 --- a/app/widget/taskview/taskview.cpp +++ b/app/widget/taskview/taskview.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { TaskView::TaskView(QWidget* parent) : QScrollArea(parent) @@ -63,4 +63,4 @@ void TaskView::RemoveTask(Task *t) items_.remove(t); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/taskview/taskview.h b/app/widget/taskview/taskview.h index 19862c6a1..17dd23d66 100644 --- a/app/widget/taskview/taskview.h +++ b/app/widget/taskview/taskview.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "widget/taskview/taskviewitem.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A widget that shows a list of Tasks @@ -66,6 +66,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TASKVIEW_H diff --git a/app/widget/taskview/taskviewitem.cpp b/app/widget/taskview/taskviewitem.cpp index 49c7c8c91..0a3d15c56 100644 --- a/app/widget/taskview/taskviewitem.cpp +++ b/app/widget/taskview/taskviewitem.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/timecodefunctions.h" #include "ui/icons/icons.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TaskViewItem::TaskViewItem(Task* task, QWidget *parent) : QFrame(parent), @@ -92,4 +92,4 @@ void TaskViewItem::UpdateProgress(double d) elapsed_timer_lbl_->SetProgress(d); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/taskview/taskviewitem.h b/app/widget/taskview/taskviewitem.h index 40f9c003b..75cf766f0 100644 --- a/app/widget/taskview/taskviewitem.h +++ b/app/widget/taskview/taskviewitem.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "elapsedcounterwidget.h" #include "task/task.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A widget that visually represents the status of a Task @@ -68,6 +68,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // TASKVIEWITEM_H diff --git a/app/widget/timebased/CMakeLists.txt b/app/widget/timebased/CMakeLists.txt index 9711117d9..8719d0f0a 100644 --- a/app/widget/timebased/CMakeLists.txt +++ b/app/widget/timebased/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/timebased/timebased.cpp b/app/widget/timebased/timebased.cpp index 5c83206c6..90296bd64 100644 --- a/app/widget/timebased/timebased.cpp +++ b/app/widget/timebased/timebased.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,13 +23,14 @@ #include #include +#include "common/autoscroll.h" #include "common/timecodefunctions.h" #include "config/config.h" #include "core.h" #include "project/item/sequence/sequence.h" #include "widget/timelinewidget/undo/undo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimeBasedWidget::TimeBasedWidget(bool ruler_text_visible, bool ruler_cache_status_visible, QWidget *parent) : TimelineScaledWidget(parent), @@ -42,8 +43,10 @@ TimeBasedWidget::TimeBasedWidget(bool ruler_text_visible, bool ruler_cache_statu ruler_ = new TimeRuler(ruler_text_visible, ruler_cache_status_visible, this); connect(ruler_, &TimeRuler::TimeChanged, this, &TimeBasedWidget::SetTimeAndSignal); - scrollbar_ = new ResizableScrollBar(Qt::Horizontal, this); + scrollbar_ = new ResizableTimelineScrollBar(Qt::Horizontal, this); connect(scrollbar_, &ResizableScrollBar::RequestScale, this, &TimeBasedWidget::ScrollBarResized); + + PassWheelEventsToScrollBar(ruler_); } void TimeBasedWidget::SetScaleAndCenterOnPlayhead(const double &scale) @@ -88,6 +91,7 @@ void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node) points_ = nullptr; ruler()->ConnectTimelinePoints(nullptr); + scrollbar_->ConnectTimelinePoints(nullptr); } viewer_node_ = node; @@ -99,6 +103,7 @@ void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node) if ((points_ = ConnectTimelinePoints())) { ruler()->ConnectTimelinePoints(points_); + scrollbar_->ConnectTimelinePoints(points_); } if (auto_set_timebase_) { @@ -155,12 +160,28 @@ void TimeBasedWidget::ScrollBarResized(const double &multiplier) SetScale(GetScale() * corrected_scale); } +void TimeBasedWidget::PageScrollToPlayhead() +{ + int playhead_pos = qRound(TimeToScene(GetTime())); + + int viewport_width = ruler()->width(); + int viewport_padding = viewport_width / 16; + + if (playhead_pos < scrollbar()->value()) { + // Anchor the playhead to the RIGHT of where we scroll to + scrollbar()->setValue(playhead_pos - viewport_width + viewport_padding); + } else if (playhead_pos > scrollbar()->value() + viewport_width) { + // Anchor the playhead to the LEFT of where we scroll to + scrollbar()->setValue(playhead_pos - viewport_padding); + } +} + TimeRuler *TimeBasedWidget::ruler() const { return ruler_; } -ResizableScrollBar *TimeBasedWidget::scrollbar() const +ResizableTimelineScrollBar *TimeBasedWidget::scrollbar() const { return scrollbar_; } @@ -170,6 +191,7 @@ void TimeBasedWidget::TimebaseChangedEvent(const rational &timebase) TimelineScaledWidget::TimebaseChangedEvent(timebase); ruler_->SetTimebase(timebase); + scrollbar_->SetTimebase(timebase); emit TimebaseChanged(timebase); } @@ -179,6 +201,7 @@ void TimeBasedWidget::ScaleChangedEvent(const double &scale) TimelineScaledWidget::ScaleChangedEvent(scale); ruler_->SetScale(scale); + scrollbar_->SetScale(scale); UpdateMaximumScroll(); @@ -220,10 +243,28 @@ void TimeBasedWidget::ConnectTimelineView(TimelineViewBase *base) timeline_views_.append(base); } +void TimeBasedWidget::PassWheelEventsToScrollBar(QObject *object) +{ + wheel_passthrough_objects_.append(object); + object->installEventFilter(this); +} + void TimeBasedWidget::SetTimestamp(int64_t timestamp) { ruler_->SetTime(timestamp); + switch (static_cast(Config::Current()["Autoscroll"].toInt())) { + case AutoScroll::kNone: + // Do nothing + break; + case AutoScroll::kPage: + QMetaObject::invokeMethod(this, "PageScrollToPlayhead", Qt::QueuedConnection); + break; + case AutoScroll::kSmooth: + QMetaObject::invokeMethod(this, "CenterScrollOnPlayhead", Qt::QueuedConnection); + break; + } + TimeChangedEvent(timestamp); } @@ -458,7 +499,8 @@ void TimeBasedWidget::SetMarker() } if (ok) { - points_->markers()->AddMarker(TimeRange(GetTime(), GetTime()), marker_name); + Core::instance()->undo_stack()->push(new MarkerAddCommand(static_cast(GetConnectedNode()->parent())->project(), + points_->markers(), TimeRange(GetTime(), GetTime()), marker_name)); } } @@ -517,4 +559,36 @@ void TimeBasedWidget::GoToOut() } } -OLIVE_NAMESPACE_EXIT +TimeBasedWidget::MarkerAddCommand::MarkerAddCommand(Project *project, TimelineMarkerList *marker_list, const TimeRange &range, const QString &name) : + project_(project), + marker_list_(marker_list), + range_(range), + name_(name) +{ +} + +Project *TimeBasedWidget::MarkerAddCommand::GetRelevantProject() const +{ + return project_; +} + +void TimeBasedWidget::MarkerAddCommand::redo_internal() +{ + added_marker_ = marker_list_->AddMarker(range_, name_); +} + +void TimeBasedWidget::MarkerAddCommand::undo_internal() +{ + marker_list_->RemoveMarker(added_marker_); +} + +bool TimeBasedWidget::eventFilter(QObject *object, QEvent *event) +{ + if (wheel_passthrough_objects_.contains(object) && event->type() == QEvent::Wheel) { + QCoreApplication::sendEvent(scrollbar(), event); + } + + return false; +} + +} diff --git a/app/widget/timebased/timebased.h b/app/widget/timebased/timebased.h index 008514d26..ddca58835 100644 --- a/app/widget/timebased/timebased.h +++ b/app/widget/timebased/timebased.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,12 +25,12 @@ #include "node/output/viewer/viewer.h" #include "timeline/timelinecommon.h" -#include "widget/resizablescrollbar/resizablescrollbar.h" +#include "widget/resizablescrollbar/resizabletimelinescrollbar.h" #include "widget/timelinewidget/timelinescaledobject.h" #include "widget/timelinewidget/view/timelineview.h" #include "widget/timeruler/timeruler.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimeBasedWidget : public TimelineScaledWidget { @@ -54,6 +54,8 @@ public: TimeRuler* ruler() const; + virtual bool eventFilter(QObject* object, QEvent* event) override; + public slots: void SetTimestamp(int64_t timestamp); @@ -95,7 +97,7 @@ protected slots: void SetTimeAndSignal(const int64_t& t); protected: - ResizableScrollBar* scrollbar() const; + ResizableTimelineScrollBar* scrollbar() const; virtual void TimebaseChangedEvent(const rational&) override; @@ -121,6 +123,8 @@ protected: void ConnectTimelineView(TimelineViewBase* base); + void PassWheelEventsToScrollBar(QObject* object); + protected slots: /** * @brief Slot to center the horizontal scroll bar on the playhead's current position @@ -139,6 +143,27 @@ signals: void TimebaseChanged(const rational&); private: + class MarkerAddCommand : public UndoCommand + { + public: + MarkerAddCommand(Project* project, TimelineMarkerList* marker_list, const TimeRange& range, const QString& name); + + virtual Project* GetRelevantProject() const override; + + protected: + virtual void redo_internal() override; + virtual void undo_internal() override; + + private: + Project* project_; + TimelineMarkerList* marker_list_; + TimeRange range_; + QString name_; + + TimelineMarker* added_marker_; + + }; + /** * @brief Set either in or out point to the current playhead * @@ -163,7 +188,7 @@ private: TimeRuler* ruler_; - ResizableScrollBar* scrollbar_; + ResizableTimelineScrollBar* scrollbar_; bool auto_max_scrollbar_; @@ -178,13 +203,23 @@ private: bool auto_set_timebase_; + QVector wheel_passthrough_objects_; + private slots: void UpdateMaximumScroll(); void ScrollBarResized(const double& multiplier); + /** + * @brief Slot to handle page scrolling of the playhead + * + * If the playhead is outside the current scroll bounds, this function will scroll to where it is. Otherwise it will + * do nothing. + */ + void PageScrollToPlayhead(); + }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMEBASEDWIDGET_H diff --git a/app/widget/timelinewidget/CMakeLists.txt b/app/widget/timelinewidget/CMakeLists.txt index 9672f1a58..86173dc1b 100644 --- a/app/widget/timelinewidget/CMakeLists.txt +++ b/app/widget/timelinewidget/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/timelinewidget/snapservice.h b/app/widget/timelinewidget/snapservice.h index ad7b09834..c9c6a601c 100644 --- a/app/widget/timelinewidget/snapservice.h +++ b/app/widget/timelinewidget/snapservice.h @@ -3,7 +3,7 @@ #include "common/rational.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SnapService { @@ -26,6 +26,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // SNAPSERVICE_H diff --git a/app/widget/timelinewidget/timelineandtrackview.cpp b/app/widget/timelinewidget/timelineandtrackview.cpp index d233c25da..233a00c79 100644 --- a/app/widget/timelinewidget/timelineandtrackview.cpp +++ b/app/widget/timelinewidget/timelineandtrackview.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { TimelineAndTrackView::TimelineAndTrackView(Qt::Alignment vertical_alignment, QWidget *parent) : QWidget(parent) @@ -73,4 +73,4 @@ void TimelineAndTrackView::TracksValueChanged(int v) view_->verticalScrollBar()->setValue(view_->verticalScrollBar()->minimum() + v); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/timelineandtrackview.h b/app/widget/timelinewidget/timelineandtrackview.h index 7b482cde7..cc4331556 100644 --- a/app/widget/timelinewidget/timelineandtrackview.h +++ b/app/widget/timelinewidget/timelineandtrackview.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "view/timelineview.h" #include "trackview/trackview.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimelineAndTrackView : public QWidget { @@ -55,6 +55,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEANDTRACKVIEW_H diff --git a/app/widget/timelinewidget/timelinescaledobject.cpp b/app/widget/timelinewidget/timelinescaledobject.cpp index d12a998f8..28453c391 100644 --- a/app/widget/timelinewidget/timelinescaledobject.cpp +++ b/app/widget/timelinewidget/timelinescaledobject.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/clamp.h" -OLIVE_NAMESPACE_ENTER +namespace olive { const int TimelineScaledObject::kCalculateDimensionsPadding = 10; @@ -134,4 +134,4 @@ TimelineScaledWidget::TimelineScaledWidget(QWidget *parent) : { } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/timelinescaledobject.h b/app/widget/timelinewidget/timelinescaledobject.h index 3b05f8e26..8e96ec122 100644 --- a/app/widget/timelinewidget/timelinescaledobject.h +++ b/app/widget/timelinewidget/timelinescaledobject.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/rational.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimelineScaledObject { @@ -82,6 +82,6 @@ public: TimelineScaledWidget(QWidget* parent = nullptr); }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINESCALEDOBJECT_H diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index 4a3a6b759..05baf88b6 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -35,6 +35,7 @@ #include "tool/edit.h" #include "tool/pointer.h" #include "tool/razor.h" +#include "tool/record.h" #include "tool/ripple.h" #include "tool/rolling.h" #include "tool/slide.h" @@ -47,7 +48,7 @@ #include "widget/menu/menushared.h" #include "widget/nodeview/nodeviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimelineWidget::TimelineWidget(QWidget *parent) : TimeBasedWidget(true, true, parent), @@ -84,20 +85,20 @@ TimelineWidget::TimelineWidget(QWidget *parent) : views_.append(new TimelineAndTrackView(Qt::AlignTop)); // Create tools - tools_.resize(OLIVE_NAMESPACE::Tool::kCount); + tools_.resize(olive::Tool::kCount); tools_.fill(nullptr); - tools_.replace(OLIVE_NAMESPACE::Tool::kPointer, new PointerTool(this)); - tools_.replace(OLIVE_NAMESPACE::Tool::kEdit, new EditTool(this)); - tools_.replace(OLIVE_NAMESPACE::Tool::kRipple, new RippleTool(this)); - tools_.replace(OLIVE_NAMESPACE::Tool::kRolling, new RollingTool(this)); - tools_.replace(OLIVE_NAMESPACE::Tool::kRazor, new RazorTool(this)); - tools_.replace(OLIVE_NAMESPACE::Tool::kSlip, new SlipTool(this)); - tools_.replace(OLIVE_NAMESPACE::Tool::kSlide, new SlideTool(this)); - tools_.replace(OLIVE_NAMESPACE::Tool::kZoom, new ZoomTool(this)); - tools_.replace(OLIVE_NAMESPACE::Tool::kTransition, new TransitionTool(this)); - //tools_.replace(OLIVE_NAMESPACE::Tool::kRecord, new PointerTool(this)); FIXME: Implement - tools_.replace(OLIVE_NAMESPACE::Tool::kAdd, new AddTool(this)); + tools_.replace(olive::Tool::kPointer, new PointerTool(this)); + tools_.replace(olive::Tool::kEdit, new EditTool(this)); + tools_.replace(olive::Tool::kRipple, new RippleTool(this)); + tools_.replace(olive::Tool::kRolling, new RollingTool(this)); + tools_.replace(olive::Tool::kRazor, new RazorTool(this)); + tools_.replace(olive::Tool::kSlip, new SlipTool(this)); + tools_.replace(olive::Tool::kSlide, new SlideTool(this)); + tools_.replace(olive::Tool::kZoom, new ZoomTool(this)); + tools_.replace(olive::Tool::kTransition, new TransitionTool(this)); + tools_.replace(olive::Tool::kRecord, new RecordTool(this)); + tools_.replace(olive::Tool::kAdd, new AddTool(this)); import_tool_ = new ImportTool(this); @@ -131,7 +132,6 @@ TimelineWidget::TimelineWidget(QWidget *parent) : connect(view, &TimelineView::customContextMenuRequested, this, &TimelineWidget::ShowContextMenu); connect(scrollbar(), &QScrollBar::valueChanged, view->horizontalScrollBar(), &QScrollBar::setValue); connect(view->horizontalScrollBar(), &QScrollBar::valueChanged, scrollbar(), &QScrollBar::setValue); - connect(view, &TimelineView::RequestCenterScrollOnPlayhead, this, &TimelineWidget::CenterScrollOnPlayhead); connect(view, &TimelineView::MousePressed, this, &TimelineWidget::ViewMousePressed); connect(view, &TimelineView::MouseMoved, this, &TimelineWidget::ViewMouseMoved); @@ -278,6 +278,8 @@ void TimelineWidget::DisconnectNodeInternal(ViewerOutput *n) disconnect(n, &ViewerOutput::TimebaseChanged, this, &TimelineWidget::SetTimebase); disconnect(n, &ViewerOutput::TrackHeightChanged, this, &TimelineWidget::TrackHeightChanged); + DeselectAll(); + foreach (TrackOutput* track, n->GetTracks()) { RemoveTrack(track); } @@ -297,7 +299,7 @@ void TimelineWidget::DisconnectNodeInternal(ViewerOutput *n) void TimelineWidget::CopyNodesToClipboardInternal(QXmlStreamWriter *writer, void* userdata) { // Cache the earliest in point so all copied clips have a "relative" in point that can be pasted anywhere - QList& selected = *static_cast*>(userdata); + QVector& selected = *static_cast*>(userdata); rational earliest_in = RATIONAL_MAX; foreach (TimelineViewBlockItem* item, selected) { @@ -327,7 +329,7 @@ void TimelineWidget::CopyNodesToClipboardInternal(QXmlStreamWriter *writer, void void TimelineWidget::PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData& xml_node_data, void *userdata) { - QList& paste_data = *static_cast*>(userdata); + QVector& paste_data = *static_cast*>(userdata); while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("block")) { @@ -352,17 +354,9 @@ void TimelineWidget::PasteNodesFromClipboardInternal(QXmlStreamReader *reader, X } } -rational TimelineWidget::GetToolTipTimebase() const -{ - if (GetConnectedNode() && use_audio_time_units_) { - return GetConnectedNode()->audio_params().time_base(); - } - return timebase(); -} - void TimelineWidget::SelectAll() { - QList newly_selected_blocks; + QVector newly_selected_blocks; for (auto it=block_items_.cbegin(); it!=block_items_.cend(); it++) { if (!selected_blocks_.contains(it.key())) { @@ -414,7 +408,7 @@ void TimelineWidget::SplitAtPlayhead() rational playhead_time = Timecode::timestamp_to_time(GetTimestamp(), timebase()); - QList selected_blocks = GetSelectedBlocks(); + QVector selected_blocks = GetSelectedBlocks(); // Prioritize blocks that are selected and overlap the playhead QVector blocks_to_split; @@ -459,7 +453,7 @@ void TimelineWidget::SplitAtPlayhead() } } -void TimelineWidget::ReplaceBlocksWithGaps(const QList &blocks, +void TimelineWidget::ReplaceBlocksWithGaps(const QVector &blocks, bool remove_from_graph, QUndoCommand *command) { @@ -482,8 +476,8 @@ void TimelineWidget::ReplaceBlocksWithGaps(const QList &blocks, void TimelineWidget::DeleteSelected(bool ripple) { - QList selected_list = GetSelectedBlocks(); - QList blocks_to_delete; + QVector selected_list = GetSelectedBlocks(); + QVector blocks_to_delete; foreach (TimelineViewBlockItem* item, selected_list) { Block* b = item->block(); @@ -498,8 +492,8 @@ void TimelineWidget::DeleteSelected(bool ripple) QUndoCommand* command = new QUndoCommand(); - QList clips_to_delete; - QList transitions_to_delete; + QVector clips_to_delete; + QVector transitions_to_delete; foreach (Block* b, blocks_to_delete) { if (b->type() == Block::kClip) { @@ -531,7 +525,7 @@ void TimelineWidget::DeleteSelected(bool ripple) TimeRangeList range_list; foreach (Block* b, blocks_to_delete) { - range_list.InsertTimeRange(TimeRange(b->in(), b->out())); + range_list.insert(TimeRange(b->in(), b->out())); } new TimelineRippleDeleteGapsAtRegionsCommand(GetConnectedNode(), range_list, command); @@ -580,9 +574,9 @@ void TimelineWidget::OverwriteFootageAtPlayhead(const QList &footage) void TimelineWidget::ToggleLinksOnSelected() { - QList sel = GetSelectedBlocks(); + QVector sel = GetSelectedBlocks(); - QList blocks; + QVector blocks; bool link = true; foreach (TimelineViewBlockItem* item, sel) { @@ -599,11 +593,11 @@ void TimelineWidget::ToggleLinksOnSelected() blocks.append(item->block()); } - if (link) { - Core::instance()->undo_stack()->push(new BlockLinkManyCommand(blocks, true)); - } else { - Core::instance()->undo_stack()->push(new BlockLinkManyCommand(blocks, false)); + if (blocks.isEmpty()) { + return; } + + Core::instance()->undo_stack()->push(new BlockLinkManyCommand(blocks, link)); } void TimelineWidget::CopySelected(bool cut) @@ -612,20 +606,20 @@ void TimelineWidget::CopySelected(bool cut) return; } - QList selected = GetSelectedBlocks(); + QVector selected = GetSelectedBlocks(); if (selected.isEmpty()) { return; } - QList selected_nodes; + QVector selected_nodes; foreach (TimelineViewBlockItem* item, selected) { Node* block = item->block(); selected_nodes.append(block); - QList deps = block->GetDependencies(); + QVector deps = block->GetDependencies(); foreach (Node* d, deps) { if (!selected_nodes.contains(d)) { @@ -649,8 +643,8 @@ void TimelineWidget::Paste(bool insert) QUndoCommand* command = new QUndoCommand(); - QList paste_data; - QList pasted = PasteNodesFromClipboard(static_cast(GetConnectedNode()->parent()), command, &paste_data); + QVector paste_data; + QVector pasted = PasteNodesFromClipboard(static_cast(GetConnectedNode()->parent()), command, &paste_data); rational paste_start = GetTime(); @@ -731,7 +725,7 @@ void TimelineWidget::DeleteInToOut(bool ripple) void TimelineWidget::ToggleSelectedEnabled() { - QList items = GetSelectedBlocks(); + QVector items = GetSelectedBlocks(); if (items.isEmpty()) { return; @@ -748,12 +742,12 @@ void TimelineWidget::ToggleSelectedEnabled() Core::instance()->undo_stack()->pushIfHasChildren(command); } -QList TimelineWidget::GetSelectedBlocks() +QVector TimelineWidget::GetSelectedBlocks() { - QList list; + QVector list(selected_blocks_.size()); - foreach (Block* b, selected_blocks_) { - list.append(block_items_.value(b)); + for (int i=0; iMousePress(event); + UpdateViewports(); } if (event->GetButton() != Qt::LeftButton) { // Suspend tool immediately if the cursor isn't the primary button active_tool_->MouseRelease(event); + UpdateViewports(); active_tool_ = nullptr; } } @@ -827,12 +823,14 @@ void TimelineWidget::ViewMouseMoved(TimelineViewMouseEvent *event) if (GetConnectedNode()) { if (active_tool_) { active_tool_->MouseMove(event); + UpdateViewports(); } else { // Mouse is not down, attempt a hover event TimelineTool* hover_tool = GetActiveTool(); if (hover_tool) { hover_tool->HoverMove(event); + UpdateViewports(); } } } @@ -842,6 +840,7 @@ void TimelineWidget::ViewMouseReleased(TimelineViewMouseEvent *event) { if (GetConnectedNode() && active_tool_ != nullptr) { active_tool_->MouseRelease(event); + UpdateViewports(); active_tool_ = nullptr; } } @@ -850,27 +849,32 @@ void TimelineWidget::ViewMouseDoubleClicked(TimelineViewMouseEvent *event) { if (GetConnectedNode()) { GetActiveTool()->MouseDoubleClick(event); + UpdateViewports(); } } void TimelineWidget::ViewDragEntered(TimelineViewMouseEvent *event) { import_tool_->DragEnter(event); + UpdateViewports(); } void TimelineWidget::ViewDragMoved(TimelineViewMouseEvent *event) { import_tool_->DragMove(event); + UpdateViewports(); } void TimelineWidget::ViewDragLeft(QDragLeaveEvent *event) { import_tool_->DragLeave(event); + UpdateViewports(); } void TimelineWidget::ViewDragDropped(TimelineViewMouseEvent *event) { import_tool_->DragDrop(event); + UpdateViewports(); } void TimelineWidget::AddBlock(Block *block, TrackReference track) @@ -908,10 +912,7 @@ void TimelineWidget::AddBlock(Block *block, TrackReference track) void TimelineWidget::RemoveBlock(const QList &blocks) { - QList delete_items; - delete_items.reserve(blocks.size()); - - QList deselect_blocks; + QVector deselect_blocks; foreach (Block* b, blocks) { // Disconnect all signals @@ -940,8 +941,6 @@ void TimelineWidget::RemoveBlock(const QList &blocks) // through emit BlocksDeselected(deselect_blocks); } - - qDeleteAll(delete_items); } void TimelineWidget::AddTrack(TrackOutput *track, Timeline::TrackType type) @@ -1051,7 +1050,7 @@ void TimelineWidget::ShowContextMenu() { Menu menu(this); - QList selected = GetSelectedBlocks(); + QVector selected = GetSelectedBlocks(); if (!selected.isEmpty()) { MenuShared::instance()->AddItemsForEditMenu(&menu, true); @@ -1060,8 +1059,8 @@ void TimelineWidget::ShowContextMenu() QAction* properties_action = menu.addAction(tr("Properties")); connect(properties_action, &QAction::triggered, this, [this](){ - QList block_items = GetSelectedBlocks(); - QList nodes; + QVector block_items = GetSelectedBlocks(); + QVector nodes; foreach (TimelineViewBlockItem* i, block_items) { nodes.append(i->block()); @@ -1205,12 +1204,17 @@ TimelineView *TimelineWidget::GetFirstTimelineView() return views_.first()->view(); } +rational TimelineWidget::GetTimebaseForTrackType(Timeline::TrackType type) +{ + return views_.at(type)->view()->timebase(); +} + const QRect& TimelineWidget::GetRubberBandGeometry() const { return rubberband_.geometry(); } -void TimelineWidget::SignalSelectedBlocks(QList input, bool filter) +void TimelineWidget::SignalSelectedBlocks(QVector input, bool filter) { if (input.isEmpty()) { return; @@ -1233,7 +1237,7 @@ void TimelineWidget::SignalSelectedBlocks(QList input, bool filter) emit BlocksSelected(input); } -void TimelineWidget::SignalDeselectedBlocks(const QList &deselected_blocks) +void TimelineWidget::SignalDeselectedBlocks(const QVector &deselected_blocks) { if (deselected_blocks.isEmpty()) { return; @@ -1423,16 +1427,19 @@ void TimelineWidget::RestoreSplitterState(const QByteArray &state) view_splitter_->restoreState(state); } -void TimelineWidget::StartRubberBandSelect(bool enable_selecting, bool select_links) +void TimelineWidget::StartRubberBandSelect(const QPoint &global_cursor_start) { - drag_origin_ = QCursor::pos(); + drag_origin_ = global_cursor_start; + + // Start rubberband at origin + QPoint local_origin = mapFromGlobal(drag_origin_); + rubberband_.setGeometry(QRect(local_origin.x(), local_origin.y(), 0, 0)); + rubberband_.show(); // We don't touch any blocks that are already selected. If you want these to be deselected by // default, call DeselectAll() before calling StartRubberBandSelect() rubberband_old_selections_ = selections_; - - MoveRubberBandSelect(enable_selecting, select_links); } void TimelineWidget::MoveRubberBandSelect(bool enable_selecting, bool select_links) @@ -1512,7 +1519,7 @@ void TimelineWidget::EndRubberBandSelect() void TimelineWidget::AddSelection(const TimeRange &time, const TrackReference &track) { - selections_[track].InsertTimeRange(time); + selections_[track].insert(time); UpdateViewports(track.type()); } @@ -1524,7 +1531,7 @@ void TimelineWidget::AddSelection(TimelineViewBlockItem *item) void TimelineWidget::RemoveSelection(const TimeRange &time, const TrackReference &track) { - selections_[track].RemoveTimeRange(time); + selections_[track].remove(time); UpdateViewports(track.type()); } @@ -1660,4 +1667,4 @@ bool TimelineWidget::SnapPoint(QList start_times, rational* movement, return true; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/timelinewidget.h b/app/widget/timelinewidget/timelinewidget.h index c1be47a75..3c5e728cf 100644 --- a/app/widget/timelinewidget/timelinewidget.h +++ b/app/widget/timelinewidget/timelinewidget.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -38,7 +38,7 @@ #include "widget/timelinewidget/tool/import.h" #include "widget/timelinewidget/tool/tool.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief Full widget for working with TimelineOutput nodes @@ -89,7 +89,7 @@ public: void ToggleSelectedEnabled(); - QList GetSelectedBlocks(); + QVector GetSelectedBlocks(); virtual bool SnapPoint(QList start_times, rational *movement, int snap_points = kSnapAll) override; @@ -99,7 +99,7 @@ public: void RestoreSplitterState(const QByteArray& state); - static void ReplaceBlocksWithGaps(const QList& blocks, bool remove_from_graph, QUndoCommand* command); + static void ReplaceBlocksWithGaps(const QVector &blocks, bool remove_from_graph, QUndoCommand* command); /** * @brief Retrieve the QGraphicsItem at a particular scene position @@ -138,7 +138,7 @@ public: void InsertGapsAt(const rational& time, const rational& length, QUndoCommand* command); - void StartRubberBandSelect(bool enable_selecting, bool select_links); + void StartRubberBandSelect(const QPoint& global_cursor_start); void MoveRubberBandSelect(bool enable_selecting, bool select_links); void EndRubberBandSelect(); @@ -154,8 +154,6 @@ public: return !ghost_items_.isEmpty(); } - rational GetToolTipTimebase() const; - bool IsBlockSelected(Block* b) const { return selected_blocks_.contains(b); @@ -167,6 +165,8 @@ public: TimelineView* GetFirstTimelineView(); + rational GetTimebaseForTrackType(Timeline::TrackType type); + const QRect &GetRubberBandGeometry() const; /** @@ -185,12 +185,12 @@ public: * this is preferable and should only be set to FALSE if the list is guaranteed not to contain * already selected blocks (and therefore filtering can be skipped to save time). */ - void SignalSelectedBlocks(QList selected_blocks, bool filter = true); + void SignalSelectedBlocks(QVector selected_blocks, bool filter = true); /** * @brief Track blocks that have been newly deselected */ - void SignalDeselectedBlocks(const QList& deselected_blocks); + void SignalDeselectedBlocks(const QVector &deselected_blocks); /** * @brief Convenience function to deselect all blocks and signal them @@ -198,9 +198,9 @@ public: void SignalDeselectedAllBlocks(); signals: - void BlocksSelected(const QList& selected_blocks); + void BlocksSelected(const QVector& selected_blocks); - void BlocksDeselected(const QList& deselected_blocks); + void BlocksDeselected(const QVector& deselected_blocks); protected: virtual void resizeEvent(QResizeEvent *event) override; @@ -237,7 +237,7 @@ private: QRubberBand rubberband_; TimelineWidgetSelections rubberband_old_selections_; - QList rubberband_now_selected_; + QVector rubberband_now_selected_; TimelineWidgetSelections selections_; @@ -257,7 +257,7 @@ private: TimeSlider* timecode_label_; - QList selected_blocks_; + QVector selected_blocks_; int deferred_scroll_value_; @@ -321,6 +321,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEWIDGET_H diff --git a/app/widget/timelinewidget/timelinewidgetselections.cpp b/app/widget/timelinewidget/timelinewidgetselections.cpp index 951b80946..5c082fe52 100644 --- a/app/widget/timelinewidget/timelinewidgetselections.cpp +++ b/app/widget/timelinewidget/timelinewidgetselections.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,14 +20,12 @@ #include "timelinewidgetselections.h" -OLIVE_NAMESPACE_ENTER +namespace olive { void TimelineWidgetSelections::ShiftTime(const rational &diff) { for (auto it=this->begin(); it!=this->end(); it++) { - for (auto it2=it.value().begin(); it2!=it.value().end(); it2++) { - (*it2) += diff; - } + it.value().shift(diff); } } @@ -59,19 +57,15 @@ void TimelineWidgetSelections::ShiftTracks(Timeline::TrackType type, int diff) void TimelineWidgetSelections::TrimIn(const rational &diff) { for (auto it=this->begin(); it!=this->end(); it++) { - for (auto it2=it.value().begin(); it2!=it.value().end(); it2++) { - (*it2).set_in((*it2).in() + diff); - } + it.value().trim_in(diff); } } void TimelineWidgetSelections::TrimOut(const rational &diff) { for (auto it=this->begin(); it!=this->end(); it++) { - for (auto it2=it.value().begin(); it2!=it.value().end(); it2++) { - (*it2).set_out((*it2).out() + diff); - } + it.value().trim_out(diff); } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/timelinewidgetselections.h b/app/widget/timelinewidget/timelinewidgetselections.h index 1413bbac0..ce866ba1f 100644 --- a/app/widget/timelinewidget/timelinewidgetselections.h +++ b/app/widget/timelinewidget/timelinewidgetselections.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "common/timerange.h" #include "timeline/trackreference.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimelineWidgetSelections : public QHash { @@ -43,6 +43,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEWIDGETSELECTIONS_H diff --git a/app/widget/timelinewidget/tool/CMakeLists.txt b/app/widget/timelinewidget/tool/CMakeLists.txt index 4e9850fc0..78d2a061d 100644 --- a/app/widget/timelinewidget/tool/CMakeLists.txt +++ b/app/widget/timelinewidget/tool/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 @@ -28,6 +28,8 @@ set(OLIVE_SOURCES widget/timelinewidget/tool/pointer.h widget/timelinewidget/tool/razor.cpp widget/timelinewidget/tool/razor.h + widget/timelinewidget/tool/record.cpp + widget/timelinewidget/tool/record.h widget/timelinewidget/tool/ripple.cpp widget/timelinewidget/tool/ripple.h widget/timelinewidget/tool/rolling.cpp diff --git a/app/widget/timelinewidget/tool/add.cpp b/app/widget/timelinewidget/tool/add.cpp index 4ea4831f9..738e2af19 100644 --- a/app/widget/timelinewidget/tool/add.cpp +++ b/app/widget/timelinewidget/tool/add.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "node/generator/text/text.h" #include "widget/nodeview/nodeviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { AddTool::AddTool(TimelineWidget *parent) : BeamTool(parent), @@ -48,18 +48,18 @@ void AddTool::MousePress(TimelineViewMouseEvent *event) Timeline::TrackType add_type = Timeline::kTrackTypeNone; switch (Core::instance()->GetSelectedAddableObject()) { - case OLIVE_NAMESPACE::Tool::kAddableBars: - case OLIVE_NAMESPACE::Tool::kAddableSolid: - case OLIVE_NAMESPACE::Tool::kAddableTitle: + case olive::Tool::kAddableBars: + case olive::Tool::kAddableSolid: + case olive::Tool::kAddableTitle: add_type = Timeline::kTrackTypeVideo; break; - case OLIVE_NAMESPACE::Tool::kAddableTone: + case olive::Tool::kAddableTone: add_type = Timeline::kTrackTypeAudio; break; - case OLIVE_NAMESPACE::Tool::kAddableEmpty: + case olive::Tool::kAddableEmpty: // Leave as "none", which means this block can be placed on any track break; - case OLIVE_NAMESPACE::Tool::kAddableCount: + case olive::Tool::kAddableCount: // Return so we do nothing return; } @@ -97,7 +97,7 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event) ClipBlock* clip = new ClipBlock(); clip->set_length_and_media_out(ghost_->GetAdjustedLength()); - clip->SetLabel(OLIVE_NAMESPACE::Tool::GetAddableObjectName(Core::instance()->GetSelectedAddableObject())); + clip->SetLabel(olive::Tool::GetAddableObjectName(Core::instance()->GetSelectedAddableObject())); NodeGraph* graph = static_cast(parent()->GetConnectedNode()->parent()); @@ -112,10 +112,10 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event) command); switch (Core::instance()->GetSelectedAddableObject()) { - case OLIVE_NAMESPACE::Tool::kAddableEmpty: + case olive::Tool::kAddableEmpty: // Empty, nothing to be done break; - case OLIVE_NAMESPACE::Tool::kAddableSolid: + case olive::Tool::kAddableSolid: { Node* solid = new SolidGenerator(); @@ -126,7 +126,7 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event) new NodeEdgeAddCommand(solid->output(), clip->texture_input(), command); break; } - case OLIVE_NAMESPACE::Tool::kAddableTitle: + case olive::Tool::kAddableTitle: { Node* text = new TextGenerator(); @@ -137,12 +137,12 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event) new NodeEdgeAddCommand(text->output(), clip->texture_input(), command); break; } - case OLIVE_NAMESPACE::Tool::kAddableBars: - case OLIVE_NAMESPACE::Tool::kAddableTone: + case olive::Tool::kAddableBars: + case olive::Tool::kAddableTone: // Not implemented yet qWarning() << "Unimplemented add object:" << Core::instance()->GetSelectedAddableObject(); break; - case OLIVE_NAMESPACE::Tool::kAddableCount: + case olive::Tool::kAddableCount: // Invalid value, do nothing break; } @@ -190,4 +190,4 @@ void AddTool::MouseMoveInternal(const rational &cursor_frame, bool outwards) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/tool/add.h b/app/widget/timelinewidget/tool/add.h index eabbdf3c9..9e655756e 100644 --- a/app/widget/timelinewidget/tool/add.h +++ b/app/widget/timelinewidget/tool/add.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "beam.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class AddTool : public BeamTool { @@ -42,6 +42,6 @@ protected: rational drag_start_point_; }; -OLIVE_NAMESPACE_EXIT +} #endif // ADDTIMELINETOOL_H diff --git a/app/widget/timelinewidget/tool/beam.cpp b/app/widget/timelinewidget/tool/beam.cpp index 574f2077e..ec57b4122 100644 --- a/app/widget/timelinewidget/tool/beam.cpp +++ b/app/widget/timelinewidget/tool/beam.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,7 +21,7 @@ #include "beam.h" #include "widget/timelinewidget/timelinewidget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { BeamTool::BeamTool(TimelineWidget *parent) : TimelineTool(parent) @@ -46,4 +46,4 @@ TimelineCoordinate BeamTool::ValidatedCoordinate(TimelineCoordinate coord) return coord; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/tool/beam.h b/app/widget/timelinewidget/tool/beam.h index 7949474c2..dc4f89f9d 100644 --- a/app/widget/timelinewidget/tool/beam.h +++ b/app/widget/timelinewidget/tool/beam.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "tool.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class BeamTool : public TimelineTool { @@ -37,6 +37,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // BEAMTIMELINETOOL_H diff --git a/app/widget/timelinewidget/tool/edit.cpp b/app/widget/timelinewidget/tool/edit.cpp index 142aca321..231997e5e 100644 --- a/app/widget/timelinewidget/tool/edit.cpp +++ b/app/widget/timelinewidget/tool/edit.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,7 +21,7 @@ #include "edit.h" #include "widget/timelinewidget/timelinewidget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { EditTool::EditTool(TimelineWidget* parent) : BeamTool(parent) @@ -85,4 +85,4 @@ void EditTool::MouseDoubleClick(TimelineViewMouseEvent *event) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/tool/edit.h b/app/widget/timelinewidget/tool/edit.h index 9f1e40be3..5a2f61519 100644 --- a/app/widget/timelinewidget/tool/edit.h +++ b/app/widget/timelinewidget/tool/edit.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "tool.h" #include "widget/timelinewidget/timelinewidgetselections.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class EditTool : public BeamTool { @@ -44,6 +44,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // EDITTIMELINETOOL_H diff --git a/app/widget/timelinewidget/tool/import.cpp b/app/widget/timelinewidget/tool/import.cpp index a2c77b7d4..ff9a6a2b3 100644 --- a/app/widget/timelinewidget/tool/import.cpp +++ b/app/widget/timelinewidget/tool/import.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,15 +30,15 @@ #include "core.h" #include "dialog/sequence/sequence.h" #include "node/audio/volume/volume.h" +#include "node/distort/transform/transformdistortnode.h" #include "node/generator/matrix/matrix.h" -#include "node/input/media/audio/audio.h" -#include "node/input/media/video/video.h" +#include "node/input/media/media.h" #include "node/math/math/math.h" #include "project/item/sequence/sequence.h" #include "widget/nodeview/nodeviewundo.h" #include "window/mainwindow/mainwindow.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Timeline::TrackType TrackTypeFromStreamType(Stream::Type stream_type) { @@ -63,7 +63,7 @@ ImportTool::ImportTool(TimelineWidget *parent) : TimelineTool(parent) { // Calculate width used for importing to give ghosts a slight lead-in so the ghosts aren't right on the cursor - import_pre_buffer_ = QFontMetricsWidth(parent->fontMetrics(), "HHHHHHHH"); + import_pre_buffer_ = QtUtils::QFontMetricsWidth(parent->fontMetrics(), "HHHHHHHH"); } void ImportTool::DragEnter(TimelineViewMouseEvent *event) @@ -149,9 +149,10 @@ void ImportTool::DragMove(TimelineViewMouseEvent *event) } // Generate tooltip (showing earliest in point of imported clip) - int64_t earliest_timestamp = Timecode::time_to_timestamp(earliest_ghost, parent()->GetToolTipTimebase()); + rational tooltip_timebase = parent()->GetTimebaseForTrackType(event->GetTrack().type()); + int64_t earliest_timestamp = Timecode::time_to_timestamp(earliest_ghost, tooltip_timebase); QString tooltip_text = Timecode::timestamp_to_timecode(earliest_timestamp, - parent()->GetToolTipTimebase(), + tooltip_timebase, Core::instance()->GetTimecodeDisplay()); // Force tooltip to update (otherwise the tooltip won't move as written in the documentation, and could get in the way @@ -271,6 +272,12 @@ void ImportTool::FootageToGhosts(rational ghost_start, const QList(); } + // Snap footage duration to timebase + rational snap_mvmt = SnapMovementToTimebase(footage_duration, 0, dest_tb); + if (!snap_mvmt.isNull()) { + footage_duration += snap_mvmt; + } + foreach (TimelineViewGhostItem* ghost, footage_ghosts) { ghost->SetIn(ghost_start); ghost->SetOut(ghost_start + footage_duration); @@ -314,17 +321,17 @@ void ImportTool::DropGhosts(bool insert) DropWithoutSequenceBehavior behavior = static_cast(Config::Current()["DropWithoutSequenceBehavior"].toInt()); if (behavior == kDWSAsk) { - QCheckBox* dont_ask_again_box = new QCheckBox(tr("Don't ask me again")); + QCheckBox* dont_ask_again_box = new QCheckBox(QCoreApplication::translate("ImportTool", "Don't ask me again")); QMessageBox mbox(parent()); mbox.setIcon(QMessageBox::Question); - mbox.setWindowTitle(tr("No Active Sequence")); - mbox.setText(tr("No sequence is currently open. Would you like to create one?")); + mbox.setWindowTitle(QCoreApplication::translate("ImportTool", "No Active Sequence")); + mbox.setText(QCoreApplication::translate("ImportTool", "No sequence is currently open. Would you like to create one?")); mbox.setCheckBox(dont_ask_again_box); - QPushButton* auto_params_btn = mbox.addButton(tr("Automatically Detect Parameters From Footage"), QMessageBox::YesRole); - QPushButton* manual_params_btn = mbox.addButton(tr("Set Parameters Manually"), QMessageBox::NoRole); + QPushButton* auto_params_btn = mbox.addButton(QCoreApplication::translate("ImportTool", "Automatically Detect Parameters From Footage"), QMessageBox::YesRole); + QPushButton* manual_params_btn = mbox.addButton(QCoreApplication::translate("ImportTool", "Set Parameters Manually"), QMessageBox::NoRole); mbox.addButton(QMessageBox::Cancel); mbox.exec(); @@ -343,10 +350,10 @@ void ImportTool::DropGhosts(bool insert) } if (behavior != kDWSDisable) { - ProjectPtr active_project = Core::instance()->GetActiveProject(); + Project* active_project = Core::instance()->GetActiveProject(); if (active_project) { - SequencePtr new_sequence = Core::instance()->CreateNewSequenceForProject(active_project.get()); + SequencePtr new_sequence = Core::instance()->CreateNewSequenceForProject(active_project); new_sequence->set_default_parameters(); @@ -397,8 +404,8 @@ void ImportTool::DropGhosts(bool insert) QVector block_items(parent()->GetGhostItems().size()); - // Check if we're inserting - if (insert) { + // Check if we're inserting (only valid if we're not creating this sequence ourselves) + if (insert && !open_sequence) { InsertGapsAtGhostDestination(command); } @@ -416,11 +423,16 @@ void ImportTool::DropGhosts(bool insert) switch (footage_stream->type()) { case Stream::kVideo: { - VideoInput* video_input = new VideoInput(); + MediaInput* video_input = new MediaInput(); video_input->SetStream(footage_stream); new NodeAddCommand(dst_graph, video_input, command); - new NodeEdgeAddCommand(video_input->output(), clip->texture_input(), command); + + TransformDistortNode* transform = new TransformDistortNode(); + new NodeAddCommand(dst_graph, transform, command); + + new NodeEdgeAddCommand(video_input->output(), transform->texture_input(), command); + new NodeEdgeAddCommand(transform->output(), clip->texture_input(), command); /* MatrixGenerator* matrix = new MatrixGenerator(); @@ -438,7 +450,7 @@ void ImportTool::DropGhosts(bool insert) } case Stream::kAudio: { - AudioInput* audio_input = new AudioInput(); + MediaInput* audio_input = new MediaInput(); audio_input->SetStream(footage_stream); new NodeAddCommand(dst_graph, audio_input, command); @@ -498,9 +510,4 @@ QList ImportTool::FootageToDraggedFootage(QList FootageToDraggedFootage(QList footage); - QString tr(const char* s); - void FootageToGhosts(rational ghost_start, const QList& footage, const rational &dest_tb, const int &track_start); void PrepGhosts(const rational &frame, const int &track_index); @@ -86,6 +84,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // IMPORTTIMELINETOOL_H diff --git a/app/widget/timelinewidget/tool/pointer.cpp b/app/widget/timelinewidget/tool/pointer.cpp index 7f4f8e772..d059c21ef 100644 --- a/app/widget/timelinewidget/tool/pointer.cpp +++ b/app/widget/timelinewidget/tool/pointer.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -35,7 +35,7 @@ #include "pointer.h" #include "widget/nodeview/nodeviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { PointerTool::PointerTool(TimelineWidget *parent) : TimelineTool(parent), @@ -52,6 +52,8 @@ void PointerTool::MousePress(TimelineViewMouseEvent *event) // Determine if item clicked on is selectable clicked_item_ = parent()->GetItemAtScenePos(event->GetCoordinates()); + can_rubberband_select_ = false; + bool selectable_item = (clicked_item_ && !parent()->GetTrackFromReference(clicked_item_->Track())->IsLocked()); @@ -79,7 +81,7 @@ void PointerTool::MousePress(TimelineViewMouseEvent *event) if (parent()->IsBlockSelected(clicked_item_->block())) { // Collect item deselections - QList deselected_blocks; + QVector deselected_blocks; // If shift is held, deselect it if (event->GetModifiers() & Qt::ShiftModifier) { @@ -89,7 +91,7 @@ void PointerTool::MousePress(TimelineViewMouseEvent *event) // If not holding alt, deselect all links as well if (!(event->GetModifiers() & Qt::AltModifier)) { parent()->SetBlockLinksSelected(clicked_item_->block(), false); - deselected_blocks.append(clicked_item_->block()->linked_clips().toList()); + deselected_blocks.append(clicked_item_->block()->linked_clips()); } } @@ -107,7 +109,7 @@ void PointerTool::MousePress(TimelineViewMouseEvent *event) if (selectable_item) { // Collect item selections - QList selected_blocks; + QVector selected_blocks; // Select this item parent()->AddSelection(clicked_item_); @@ -116,26 +118,43 @@ void PointerTool::MousePress(TimelineViewMouseEvent *event) // If not holding alt, select all links as well if (!(event->GetModifiers() & Qt::AltModifier)) { parent()->SetBlockLinksSelected(clicked_item_->block(), true); - selected_blocks.append(clicked_item_->block()->linked_clips().toList()); + selected_blocks.append(clicked_item_->block()->linked_clips()); } parent()->SignalSelectedBlocks(selected_blocks); - } else if (event->GetButton() == Qt::LeftButton) { + } - // Start rubberband drag - parent()->StartRubberBandSelect(true, !(event->GetModifiers() & Qt::AltModifier)); - - rubberband_selecting_ = true; + can_rubberband_select_ = (event->GetButton() == Qt::LeftButton // Only rubberband select from the primary mouse button + && (!selectable_item || drag_movement_mode_ == Timeline::kNone)); // And if no item was selected OR the item isn't draggable + if (can_rubberband_select_) { + drag_global_start_ = QCursor::pos(); } } void PointerTool::MouseMove(TimelineViewMouseEvent *event) { - if (rubberband_selecting_) { + if (can_rubberband_select_) { + + if (!rubberband_selecting_) { + + // If we clicked an item but are rubberband selecting anyway, deselect it now + if (clicked_item_) { + parent()->RemoveSelection(clicked_item_); + parent()->SignalDeselectedBlocks({clicked_item_->block()}); + clicked_item_ = nullptr; + } + + parent()->StartRubberBandSelect(drag_global_start_); + + rubberband_selecting_ = true; + + } + // Process rubberband select parent()->MoveRubberBandSelect(true, !(event->GetModifiers() & Qt::AltModifier)); + } else { // Process drag if (!dragging_) { @@ -219,13 +238,13 @@ void SetGhostToSlideMode(TimelineViewGhostItem* g) } void PointerTool::InitiateDragInternal(TimelineViewBlockItem *clicked_item, - Timeline::MovementMode trim_mode, - bool dont_roll_trims, - bool allow_nongap_rolling, - bool slide_instead_of_moving) + Timeline::MovementMode trim_mode, + bool dont_roll_trims, + bool allow_nongap_rolling, + bool slide_instead_of_moving) { // Get list of selected blocks - QList clips = parent()->GetSelectedBlocks(); + QVector clips = parent()->GetSelectedBlocks(); if (trim_mode == Timeline::kMove) { @@ -469,7 +488,7 @@ void PointerTool::ProcessDrag(const TimelineCoordinate &mouse_pos) } // Validate ghosts that are being moved (clips from other track types do NOT get moved) - { + if (track_movement != 0) { QVector validate_track_ghosts = parent()->GetGhostItems(); for (int i=0;iGetTrack().type() != drag_track_type_) { @@ -508,10 +527,11 @@ void PointerTool::ProcessDrag(const TimelineCoordinate &mouse_pos) // Regenerate tooltip and force it to update (otherwise the tooltip won't move as written in the // documentation, and could get in the way of the cursor) + rational tooltip_timebase = parent()->GetTimebaseForTrackType(drag_start_.GetTrack().type()); QToolTip::hideText(); QToolTip::showText(QCursor::pos(), - Timecode::timestamp_to_timecode(Timecode::time_to_timestamp(time_movement, parent()->GetToolTipTimebase()), - parent()->GetToolTipTimebase(), + Timecode::timestamp_to_timecode(Timecode::time_to_timestamp(time_movement, tooltip_timebase), + tooltip_timebase, Core::instance()->GetTimecodeDisplay(), true), parent()); @@ -590,10 +610,10 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event) // If we're not duplicating, "remove" the clips and replace them with gaps if (!duplicate_clips) { - QList blocks_to_delete; + QVector blocks_to_delete(blocks_moving.size()); - foreach (const GhostBlockPair& p, blocks_moving) { - blocks_to_delete.append(p.block); + for (int i=0; iReplaceBlocksWithGaps(blocks_to_delete, false, command); @@ -610,13 +630,23 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event) if (duplicate_clips) { // Duplicate rather than move - Node* copy = block->copy(); + Node* copy; - new NodeAddCommand(static_cast(block->parent()), - copy, - command); + if (Config::Current()[QStringLiteral("SplitClipsCopyNodes")].toBool()) { + QVector nodes_to_clone; + nodes_to_clone.append(block); + nodes_to_clone.append(block->GetDependencies()); + QVector duplicated = Node::CopyDependencyGraph(nodes_to_clone, command); + copy = duplicated.first(); + } else { + copy = block->copy(); - new NodeCopyInputsCommand(block, copy, true, command); + new NodeAddCommand(static_cast(block->parent()), + copy, + command); + + new NodeCopyInputsCommand(block, copy, true, command); + } // Place the copy instead of the original block block = static_cast(copy); @@ -707,7 +737,7 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event) Timeline::MovementMode PointerTool::IsCursorInTrimHandle(TimelineViewBlockItem *block, qreal cursor_x) { - double kTrimHandle = QFontMetricsWidth(parent()->fontMetrics(), "H"); + double kTrimHandle = QtUtils::QFontMetricsWidth(parent()->fontMetrics(), "H"); // Block is too narrow, no trimming allowed if (block->rect().width() <= kTrimHandle * 2) { @@ -724,7 +754,7 @@ Timeline::MovementMode PointerTool::IsCursorInTrimHandle(TimelineViewBlockItem * } void PointerTool::InitiateDrag(TimelineViewBlockItem* clicked_item, - Timeline::MovementMode trim_mode) + Timeline::MovementMode trim_mode) { InitiateDragInternal(clicked_item, trim_mode, false, false, false); } @@ -795,8 +825,8 @@ void PointerTool::AddGhostInternal(TimelineViewGhostItem* ghost, Timeline::Movem } bool PointerTool::IsClipTrimmable(TimelineViewBlockItem* clip, - const QList& items, - const Timeline::MovementMode& mode) + const QVector& items, + const Timeline::MovementMode& mode) { foreach (TimelineViewBlockItem* compare, items) { if (clip->Track() == compare->Track() @@ -811,9 +841,9 @@ bool PointerTool::IsClipTrimmable(TimelineViewBlockItem* clip, } bool PointerTool::AddMovingTransitionsToClipGhost(Block* block, - const TrackReference& track, - Timeline::MovementMode movement, - const QList& selected_items) + const TrackReference& track, + Timeline::MovementMode movement, + const QList& selected_items) { // Assume block is a clip and see if it has any transitions TransitionBlock* transitions[2]; @@ -862,6 +892,8 @@ bool PointerTool::AddMovingTransitionsToClipGhost(Block* block, rational PointerTool::ValidateInTrimming(rational movement) { + bool first_ghost = true; + foreach (TimelineViewGhostItem* ghost, parent()->GetGhostItems()) { if (ghost->GetMode() != Timeline::kTrimIn) { continue; @@ -870,8 +902,11 @@ rational PointerTool::ValidateInTrimming(rational movement) rational earliest_in = RATIONAL_MIN; rational latest_in = ghost->GetOut(); + rational ghost_timebase = parent()->GetTimebaseForTrackType(ghost->GetTrack().type()); + + // If the ghost must be at least one frame in size, limit the latest allowed in point if (!ghost->CanHaveZeroLength()) { - latest_in -= parent()->timebase(); + latest_in -= ghost_timebase; } // Clamp adjusted value between the earliest and latest values @@ -881,6 +916,11 @@ rational PointerTool::ValidateInTrimming(rational movement) if (clamped != adjusted) { movement = clamped - ghost->GetIn(); } + + if (first_ghost) { + movement = SnapMovementToTimebase(ghost->GetIn(), movement, ghost_timebase); + first_ghost = false; + } } return movement; @@ -888,6 +928,8 @@ rational PointerTool::ValidateInTrimming(rational movement) rational PointerTool::ValidateOutTrimming(rational movement) { + bool first_ghost = true; + foreach (TimelineViewGhostItem* ghost, parent()->GetGhostItems()) { if (ghost->GetMode() != Timeline::kTrimOut) { continue; @@ -896,8 +938,10 @@ rational PointerTool::ValidateOutTrimming(rational movement) // Determine earliest and latest out points rational earliest_out = ghost->GetIn(); + rational ghost_timebase = parent()->GetTimebaseForTrackType(ghost->GetTrack().type()); + if (!ghost->CanHaveZeroLength()) { - earliest_out += parent()->timebase(); + earliest_out += ghost_timebase; } rational latest_out = RATIONAL_MAX; @@ -909,9 +953,14 @@ rational PointerTool::ValidateOutTrimming(rational movement) if (clamped != adjusted) { movement = clamped - ghost->GetOut(); } + + if (first_ghost) { + movement = SnapMovementToTimebase(ghost->GetOut(), movement, ghost_timebase); + first_ghost = false; + } } return movement; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/tool/pointer.h b/app/widget/timelinewidget/tool/pointer.h index 31ec8b455..aa96059e6 100644 --- a/app/widget/timelinewidget/tool/pointer.h +++ b/app/widget/timelinewidget/tool/pointer.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "tool.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class PointerTool : public TimelineTool { @@ -100,7 +100,7 @@ private: void AddGhostInternal(TimelineViewGhostItem* ghost, Timeline::MovementMode mode); bool IsClipTrimmable(TimelineViewBlockItem* clip, - const QList& items, + const QVector &items, const Timeline::MovementMode& mode); void ProcessGhostsForSliding(); @@ -113,6 +113,7 @@ private: bool trimming_allowed_; bool track_movement_allowed_; bool gap_trimming_allowed_; + bool can_rubberband_select_; bool rubberband_selecting_; Timeline::TrackType drag_track_type_; @@ -120,8 +121,10 @@ private: TimelineViewBlockItem* clicked_item_; + QPoint drag_global_start_; + }; -OLIVE_NAMESPACE_EXIT +} #endif // POINTERTIMELINETOOL_H diff --git a/app/widget/timelinewidget/tool/razor.cpp b/app/widget/timelinewidget/tool/razor.cpp index fb6244ee8..102f2cd1d 100644 --- a/app/widget/timelinewidget/tool/razor.cpp +++ b/app/widget/timelinewidget/tool/razor.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,7 +21,7 @@ #include "razor.h" #include "widget/timelinewidget/timelinewidget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { RazorTool::RazorTool(TimelineWidget* parent) : BeamTool(parent) @@ -94,4 +94,4 @@ void RazorTool::MouseRelease(TimelineViewMouseEvent *event) dragging_ = false; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/tool/razor.h b/app/widget/timelinewidget/tool/razor.h index d2da08ac3..ee6da1d49 100644 --- a/app/widget/timelinewidget/tool/razor.h +++ b/app/widget/timelinewidget/tool/razor.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "beam.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class RazorTool : public BeamTool { @@ -38,6 +38,6 @@ private: QVector split_tracks_; }; -OLIVE_NAMESPACE_EXIT +} #endif // RAZORTIMELINETOOL_H diff --git a/app/widget/timelinewidget/tool/record.cpp b/app/widget/timelinewidget/tool/record.cpp new file mode 100644 index 000000000..4a904fb14 --- /dev/null +++ b/app/widget/timelinewidget/tool/record.cpp @@ -0,0 +1,11 @@ +#include "record.h" + +namespace olive { + +RecordTool::RecordTool(TimelineWidget *parent) : + BeamTool(parent) +{ + +} + +} diff --git a/app/render/backend/decodercache.h b/app/widget/timelinewidget/tool/record.h similarity index 72% rename from app/render/backend/decodercache.h rename to app/widget/timelinewidget/tool/record.h index 6e0890f43..4ad234245 100644 --- a/app/render/backend/decodercache.h +++ b/app/widget/timelinewidget/tool/record.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -18,16 +18,19 @@ ***/ -#ifndef DECODERCACHE_H -#define DECODERCACHE_H +#ifndef RECORDTIMELINETOOL_H +#define RECORDTIMELINETOOL_H -#include "codec/decoder.h" -#include "project/item/footage/stream.h" +#include "beam.h" -OLIVE_NAMESPACE_ENTER +namespace olive { -using DecoderCache = QHash; +class RecordTool : public BeamTool +{ +public: + RecordTool(TimelineWidget* parent); +}; -OLIVE_NAMESPACE_EXIT +} -#endif // DECODERCACHE_H +#endif // RECORDTOOL_H diff --git a/app/widget/timelinewidget/tool/ripple.cpp b/app/widget/timelinewidget/tool/ripple.cpp index f9455483e..06e094451 100644 --- a/app/widget/timelinewidget/tool/ripple.cpp +++ b/app/widget/timelinewidget/tool/ripple.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "ripple.h" #include "widget/nodeview/nodeviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { RippleTool::RippleTool(TimelineWidget* parent) : PointerTool(parent) @@ -147,4 +147,4 @@ void RippleTool::FinishDrag(TimelineViewMouseEvent *event) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/tool/ripple.h b/app/widget/timelinewidget/tool/ripple.h index bb946eaa3..c51436dae 100644 --- a/app/widget/timelinewidget/tool/ripple.h +++ b/app/widget/timelinewidget/tool/ripple.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "pointer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class RippleTool : public PointerTool { @@ -36,6 +36,6 @@ protected: Timeline::MovementMode trim_mode) override; }; -OLIVE_NAMESPACE_EXIT +} #endif // RIPPLETIMELINETOOL_H diff --git a/app/widget/timelinewidget/tool/rolling.cpp b/app/widget/timelinewidget/tool/rolling.cpp index 4f340991a..4baa8a8fc 100644 --- a/app/widget/timelinewidget/tool/rolling.cpp +++ b/app/widget/timelinewidget/tool/rolling.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "rolling.h" #include "widget/nodeview/nodeviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { RollingTool::RollingTool(TimelineWidget* parent) : PointerTool(parent) @@ -39,4 +39,4 @@ void RollingTool::InitiateDrag(TimelineViewBlockItem *clicked_item, InitiateDragInternal(clicked_item, trim_mode, false, true, false); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/tool/rolling.h b/app/widget/timelinewidget/tool/rolling.h index f804b9118..3e8bb9940 100644 --- a/app/widget/timelinewidget/tool/rolling.h +++ b/app/widget/timelinewidget/tool/rolling.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "pointer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class RollingTool : public PointerTool { @@ -35,6 +35,6 @@ protected: Timeline::MovementMode trim_mode) override; }; -OLIVE_NAMESPACE_EXIT +} #endif // ROLLINGTIMELINETOOL_H diff --git a/app/widget/timelinewidget/tool/slide.cpp b/app/widget/timelinewidget/tool/slide.cpp index 0dc7d1482..e5e9b3b04 100644 --- a/app/widget/timelinewidget/tool/slide.cpp +++ b/app/widget/timelinewidget/tool/slide.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "slide.h" #include "widget/nodeview/nodeviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { SlideTool::SlideTool(TimelineWidget* parent) : PointerTool(parent) @@ -40,4 +40,4 @@ void SlideTool::InitiateDrag(TimelineViewBlockItem *clicked_item, InitiateDragInternal(clicked_item, trim_mode, false, true, true); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/tool/slide.h b/app/widget/timelinewidget/tool/slide.h index 326f78d8b..904e0f8ca 100644 --- a/app/widget/timelinewidget/tool/slide.h +++ b/app/widget/timelinewidget/tool/slide.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "pointer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SlideTool : public PointerTool { @@ -36,6 +36,6 @@ protected: }; -OLIVE_NAMESPACE_EXIT +} #endif // SLIDETIMELINETOOL_H diff --git a/app/widget/timelinewidget/tool/slip.cpp b/app/widget/timelinewidget/tool/slip.cpp index e7636048f..1570791df 100644 --- a/app/widget/timelinewidget/tool/slip.cpp +++ b/app/widget/timelinewidget/tool/slip.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "config/config.h" #include "slip.h" -OLIVE_NAMESPACE_ENTER +namespace olive { SlipTool::SlipTool(TimelineWidget *parent) : PointerTool(parent) @@ -54,10 +54,11 @@ void SlipTool::ProcessDrag(const TimelineCoordinate &mouse_pos) // Generate tooltip and force it to to update (otherwise the tooltip won't move as written in the // documentation, and could get in the way of the cursor) + rational tooltip_timebase = parent()->GetTimebaseForTrackType(drag_start_.GetTrack().type()); QToolTip::hideText(); QToolTip::showText(QCursor::pos(), - Timecode::timestamp_to_timecode(Timecode::time_to_timestamp(time_movement, parent()->GetToolTipTimebase()), - parent()->GetToolTipTimebase(), + Timecode::timestamp_to_timecode(Timecode::time_to_timestamp(time_movement, tooltip_timebase), + tooltip_timebase, Core::instance()->GetTimecodeDisplay(), true), parent()); @@ -79,4 +80,4 @@ void SlipTool::FinishDrag(TimelineViewMouseEvent *event) Core::instance()->undo_stack()->pushIfHasChildren(command); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/tool/slip.h b/app/widget/timelinewidget/tool/slip.h index bf358e5fc..8de6bfb69 100644 --- a/app/widget/timelinewidget/tool/slip.h +++ b/app/widget/timelinewidget/tool/slip.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "pointer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SlipTool : public PointerTool { @@ -35,6 +35,6 @@ protected: virtual void FinishDrag(TimelineViewMouseEvent *event) override; }; -OLIVE_NAMESPACE_EXIT +} #endif // SLIPTIMELINETOOL_H diff --git a/app/widget/timelinewidget/tool/tool.cpp b/app/widget/timelinewidget/tool/tool.cpp index 388b4edaf..082054443 100644 --- a/app/widget/timelinewidget/tool/tool.cpp +++ b/app/widget/timelinewidget/tool/tool.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "node/block/transition/transition.h" #include "widget/nodeview/nodeviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimelineTool::TimelineTool(TimelineWidget *parent) : dragging_(false), @@ -53,8 +53,22 @@ Timeline::MovementMode TimelineTool::FlipTrimMode(const Timeline::MovementMode & return trim_mode; } +rational TimelineTool::SnapMovementToTimebase(const rational &start, rational movement, const rational &timebase) +{ + rational proposed_position = start + movement; + rational snapped = Timecode::snap_time_to_timebase(proposed_position, timebase); + + if (proposed_position != snapped) { + movement += snapped - proposed_position; + } + + return movement; +} + rational TimelineTool::ValidateTimeMovement(rational movement) { + bool first_ghost = true; + foreach (TimelineViewGhostItem* ghost, parent()->GetGhostItems()) { if (ghost->GetMode() != Timeline::kMove) { continue; @@ -63,6 +77,11 @@ rational TimelineTool::ValidateTimeMovement(rational movement) // Prevents any ghosts from going below 0:00:00 time if (ghost->GetIn() + movement < 0) { movement = -ghost->GetIn(); + } else if (first_ghost) { + // Ensure ghost is snapped to a grid + movement = SnapMovementToTimebase(ghost->GetIn(), movement, parent()->GetTimebaseForTrackType(ghost->GetTrack().type())); + + first_ghost = false; } } @@ -119,4 +138,4 @@ void TimelineTool::InsertGapsAtGhostDestination(QUndoCommand *command) parent()->InsertGapsAt(earliest_point, latest_point - earliest_point, command); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/tool/tool.h b/app/widget/timelinewidget/tool/tool.h index a0ffce17f..ffb5f185b 100644 --- a/app/widget/timelinewidget/tool/tool.h +++ b/app/widget/timelinewidget/tool/tool.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "widget/timelinewidget/view/timelineviewghostitem.h" #include "widget/timelinewidget/view/timelineviewmouseevent.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimelineWidget; @@ -53,6 +53,8 @@ public: static Timeline::MovementMode FlipTrimMode(const Timeline::MovementMode& trim_mode); + static rational SnapMovementToTimebase(const rational& start, rational movement, const rational& timebase); + protected: /** * @brief Validates Ghosts that are moving horizontally (time-based) @@ -84,6 +86,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINETOOL_H diff --git a/app/widget/timelinewidget/tool/transition.cpp b/app/widget/timelinewidget/tool/transition.cpp index 942e7a6b2..335d6652f 100644 --- a/app/widget/timelinewidget/tool/transition.cpp +++ b/app/widget/timelinewidget/tool/transition.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "transition.h" #include "widget/nodeview/nodeviewundo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TransitionTool::TransitionTool(TimelineWidget *parent) : AddTool(parent) @@ -181,4 +181,4 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/tool/transition.h b/app/widget/timelinewidget/tool/transition.h index 89d77253e..70ac8de08 100644 --- a/app/widget/timelinewidget/tool/transition.h +++ b/app/widget/timelinewidget/tool/transition.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "add.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TransitionTool : public AddTool { @@ -37,6 +37,6 @@ private: bool dual_transition_; }; -OLIVE_NAMESPACE_EXIT +} #endif // TRANSITIONTIMELINETOOL_H diff --git a/app/widget/timelinewidget/tool/zoom.cpp b/app/widget/timelinewidget/tool/zoom.cpp index 3b4f30e54..063a4afc6 100644 --- a/app/widget/timelinewidget/tool/zoom.cpp +++ b/app/widget/timelinewidget/tool/zoom.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,7 +21,7 @@ #include "widget/timelinewidget/timelinewidget.h" #include "zoom.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ZoomTool::ZoomTool(TimelineWidget *parent) : TimelineTool(parent) @@ -31,19 +31,21 @@ ZoomTool::ZoomTool(TimelineWidget *parent) : void ZoomTool::MousePress(TimelineViewMouseEvent *event) { Q_UNUSED(event) + + drag_global_start_ = QCursor::pos(); } void ZoomTool::MouseMove(TimelineViewMouseEvent *event) { Q_UNUSED(event) - if (dragging_) { - parent()->MoveRubberBandSelect(false, false); - } else { - parent()->StartRubberBandSelect(false, false); + if (!dragging_) { + parent()->StartRubberBandSelect(drag_global_start_); dragging_ = true; } + + parent()->MoveRubberBandSelect(false, false); } void ZoomTool::MouseRelease(TimelineViewMouseEvent *event) @@ -96,4 +98,4 @@ void ZoomTool::MouseRelease(TimelineViewMouseEvent *event) parent()->QueueScroll(scroll_value); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/tool/zoom.h b/app/widget/timelinewidget/tool/zoom.h index a98823a20..6557ca0b2 100644 --- a/app/widget/timelinewidget/tool/zoom.h +++ b/app/widget/timelinewidget/tool/zoom.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "tool.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ZoomTool : public TimelineTool { @@ -34,8 +34,11 @@ public: virtual void MouseMove(TimelineViewMouseEvent *event) override; virtual void MouseRelease(TimelineViewMouseEvent *event) override; +private: + QPoint drag_global_start_; + }; -OLIVE_NAMESPACE_EXIT +} #endif // ZOOMTIMELINETOOL_H diff --git a/app/widget/timelinewidget/trackview/CMakeLists.txt b/app/widget/timelinewidget/trackview/CMakeLists.txt index a569b27c9..4a3186453 100644 --- a/app/widget/timelinewidget/trackview/CMakeLists.txt +++ b/app/widget/timelinewidget/trackview/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/timelinewidget/trackview/trackview.cpp b/app/widget/timelinewidget/trackview/trackview.cpp index c079a0b9b..d594787ad 100644 --- a/app/widget/timelinewidget/trackview/trackview.cpp +++ b/app/widget/timelinewidget/trackview/trackview.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "trackviewitem.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TrackView::TrackView(Qt::Alignment vertical_alignment, QWidget *parent) : QScrollArea(parent), @@ -132,4 +132,4 @@ void TrackView::RemoveTrack(TrackOutput *track) splitter_->Remove(track->Index()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/trackview/trackview.h b/app/widget/timelinewidget/trackview/trackview.h index 184ad51df..1ee2e3aab 100644 --- a/app/widget/timelinewidget/trackview/trackview.h +++ b/app/widget/timelinewidget/trackview/trackview.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "trackviewitem.h" #include "trackviewsplitter.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TrackView : public QScrollArea { @@ -63,6 +63,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // TRACKVIEW_H diff --git a/app/widget/timelinewidget/trackview/trackviewitem.cpp b/app/widget/timelinewidget/trackview/trackviewitem.cpp index ed394c24e..9d2b68904 100644 --- a/app/widget/timelinewidget/trackview/trackviewitem.cpp +++ b/app/widget/timelinewidget/trackview/trackviewitem.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include #include -OLIVE_NAMESPACE_ENTER +namespace olive { TrackViewItem::TrackViewItem(TrackOutput* track, QWidget *parent) : QWidget(parent), @@ -117,4 +117,4 @@ void TrackViewItem::UpdateLabel() } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/trackview/trackviewitem.h b/app/widget/timelinewidget/trackview/trackviewitem.h index f67479380..01a237f2d 100644 --- a/app/widget/timelinewidget/trackview/trackviewitem.h +++ b/app/widget/timelinewidget/trackview/trackviewitem.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,7 +29,7 @@ #include "widget/clickablelabel/clickablelabel.h" #include "widget/focusablelineedit/focusablelineedit.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TrackViewItem : public QWidget { @@ -63,6 +63,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // TRACKVIEWITEM_H diff --git a/app/widget/timelinewidget/trackview/trackviewsplitter.cpp b/app/widget/timelinewidget/trackview/trackviewsplitter.cpp index ea42629e2..e0226016b 100644 --- a/app/widget/timelinewidget/trackview/trackviewsplitter.cpp +++ b/app/widget/timelinewidget/trackview/trackviewsplitter.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "node/output/track/track.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TrackViewSplitter::TrackViewSplitter(Qt::Alignment vertical_alignment, QWidget* parent) : QSplitter(Qt::Vertical, parent), @@ -192,4 +192,4 @@ void TrackViewSplitterHandle::paintEvent(QPaintEvent *) p.fillRect(rect(), palette().base()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/trackview/trackviewsplitter.h b/app/widget/timelinewidget/trackview/trackviewsplitter.h index 0a617e301..b478159ac 100644 --- a/app/widget/timelinewidget/trackview/trackviewsplitter.h +++ b/app/widget/timelinewidget/trackview/trackviewsplitter.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TrackViewSplitterHandle : public QSplitterHandle { @@ -77,6 +77,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TRACKVIEWSPLITTER_H diff --git a/app/widget/timelinewidget/undo/CMakeLists.txt b/app/widget/timelinewidget/undo/CMakeLists.txt index e88f2279e..91cf6fa71 100644 --- a/app/widget/timelinewidget/undo/CMakeLists.txt +++ b/app/widget/timelinewidget/undo/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/timelinewidget/undo/undo.cpp b/app/widget/timelinewidget/undo/undo.cpp index 7f968e29e..3195aa709 100644 --- a/app/widget/timelinewidget/undo/undo.cpp +++ b/app/widget/timelinewidget/undo/undo.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,6 +20,7 @@ #include "undo.h" +#include "config/config.h" #include "core.h" #include "node/block/clip/clip.h" #include "node/block/transition/transition.h" @@ -27,7 +28,7 @@ #include "widget/nodeview/nodeviewundo.h" #include "widget/timelinewidget/timelinewidget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Node* TakeNodeFromParentGraph(Node* n, QObject* new_parent = nullptr) { @@ -164,6 +165,7 @@ TrackRippleRemoveAreaCommand::TrackRippleRemoveAreaCommand(TrackOutput *track, r in_(in), out_(out), splice_(false), + splice_split_command_(nullptr), trim_out_(nullptr), trim_in_(nullptr), insert_(nullptr) @@ -208,18 +210,38 @@ void TrackRippleRemoveAreaCommand::redo_internal() // If we picked up a block to splice if (splice_) { - // Split the block here - trim_in_ = static_cast(trim_out_->copy()); + if (trim_out_->type() == Block::kGap && !insert_) { - static_cast(track_->parent())->AddNode(trim_in_); - Node::CopyInputs(trim_out_, trim_in_); + // Gaps shouldn't be split, just trim the difference + trim_out_->set_length_and_media_out(trim_out_->length() - (out_ - in_)); - trim_out_old_length_ = trim_out_->length(); - trim_out_->set_length_and_media_out(in_ - trim_out_->in()); + } else { - trim_in_->set_length_and_media_in(trim_out_old_length_ - (out_ - trim_out_->in())); + // Split the block here + splice_split_command_ = new QUndoCommand(); - track_->InsertBlockAfter(trim_in_, trim_out_); + if (Config::Current()[QStringLiteral("SplitClipsCopyNodes")].toBool()) { + QVector nodes_to_clone; + nodes_to_clone.append(trim_out_); + nodes_to_clone.append(trim_out_->GetDependencies()); + QVector duplicated = Node::CopyDependencyGraph(nodes_to_clone, splice_split_command_); + trim_in_ = static_cast(duplicated.first()); + } else { + trim_in_ = static_cast(trim_out_->copy()); + new NodeAddCommand(static_cast(track_->parent()), trim_in_, splice_split_command_); + new NodeCopyInputsCommand(trim_out_, trim_in_, true, splice_split_command_); + } + + splice_split_command_->redo(); + + trim_out_old_length_ = trim_out_->length(); + trim_out_->set_length_and_media_out(in_ - trim_out_->in()); + + trim_in_->set_length_and_media_in(trim_out_old_length_ - (out_ - trim_out_->in())); + + track_->InsertBlockAfter(trim_in_, trim_out_); + + } } else { @@ -272,9 +294,9 @@ void TrackRippleRemoveAreaCommand::redo_internal() track_->EndOperation(); - track_->InvalidateCache(TimeRange(in_, insert_ ? out_ : RATIONAL_MAX), - track_->block_input(), - track_->block_input()); + track_->Node::InvalidateCache(TimeRange(in_, insert_ ? out_ : RATIONAL_MAX), + track_->block_input(), + track_->block_input()); } void TrackRippleRemoveAreaCommand::undo_internal() @@ -288,11 +310,20 @@ void TrackRippleRemoveAreaCommand::undo_internal() if (splice_) { - // trim_in_ is our copy and trim_out_ is our original - track_->RippleRemoveBlock(trim_in_); - trim_out_->set_length_and_media_out(trim_out_old_length_); + if (trim_out_->type() == Block::kGap && !insert_) { - TakeNodeFromParentGraph(trim_in_, &memory_manager_); + // Just restore the length + trim_out_->set_length_and_media_out(trim_out_->length() + (out_ - in_)); + + } else { + + // trim_in_ is our copy and trim_out_ is our original + track_->RippleRemoveBlock(trim_in_); + trim_out_->set_length_and_media_out(trim_out_old_length_); + + splice_split_command_->undo(); + + } } else { @@ -329,7 +360,13 @@ void TrackRippleRemoveAreaCommand::undo_internal() track_->EndOperation(); - track_->InvalidateCache(TimeRange(in_, insert_ ? out_ : RATIONAL_MAX), track_->block_input(), track_->block_input()); + track_->Node::InvalidateCache(TimeRange(in_, insert_ ? out_ : RATIONAL_MAX), + track_->block_input(), track_->block_input()); + + if (splice_split_command_) { + delete splice_split_command_; + splice_split_command_ = nullptr; + } } TrackPlaceBlockCommand::TrackPlaceBlockCommand(TrackList *timeline, int track, Block *block, rational in, QUndoCommand *parent) : @@ -428,8 +465,33 @@ void BlockSplitCommand::redo_internal() { track_->BeginOperation(); - static_cast(block_->parent())->AddNode(new_block_); - Node::CopyInputs(block_, new_block_); + NodeGraph* graph = static_cast(block_->parent()); + + add_command_ = new QUndoCommand(); + new NodeAddCommand(graph, new_block_, add_command_); + new NodeCopyInputsCommand(block_, new_block_, true, add_command_); + + if (Config::Current()[QStringLiteral("SplitClipsCopyNodes")].toBool()) { + + QVector src_nodes; + QVector dst_nodes; + + src_nodes.append(block_); + src_nodes.append(block_->GetDependencies()); + + dst_nodes.resize(src_nodes.size()); + dst_nodes[0] = new_block_; + for (int i=1; icopy(); + new NodeAddCommand(graph, dst_nodes[i], add_command_); + Node::CopyInputs(src_nodes[i], dst_nodes[i], false); + } + + Node::CopyDependencyGraph(src_nodes, dst_nodes, add_command_); + + } + + add_command_->redo(); rational new_part_length = block_->length() - (point_ - block_->in()); @@ -451,16 +513,18 @@ void BlockSplitCommand::undo_internal() { track_->BeginOperation(); - block_->set_length_and_media_out(old_length_); - track_->RippleRemoveBlock(new_block_); - - TakeNodeFromParentGraph(new_block_, &memory_manager_); - foreach (NodeInput* transition, transitions_to_move_) { NodeParam::DisconnectEdge(new_block_->output(), transition); NodeParam::ConnectEdge(block_->output(), transition); } + block_->set_length_and_media_out(old_length_); + track_->RippleRemoveBlock(new_block_); + + add_command_->undo(); + new_block_->setParent(&memory_manager_); + delete add_command_; + track_->EndOperation(); } @@ -765,7 +829,7 @@ void BlockUnlinkAllCommand::undo_internal() unlinked_.clear(); } -BlockLinkManyCommand::BlockLinkManyCommand(const QList blocks, bool link, QUndoCommand *parent) : +BlockLinkManyCommand::BlockLinkManyCommand(const QVector blocks, bool link, QUndoCommand *parent) : UndoCommand(parent), blocks_(blocks) { @@ -901,7 +965,7 @@ void BlockTrimCommand::redo_internal() invalidate_range = TimeRange(block_->in(), block_->out()); } - track_->InvalidateCache(invalidate_range, track_->block_input(), track_->block_input()); + track_->Node::InvalidateCache(invalidate_range, track_->block_input(), track_->block_input()); } void BlockTrimCommand::undo_internal() @@ -968,7 +1032,7 @@ void BlockTrimCommand::undo_internal() track_->EndOperation(); - track_->InvalidateCache(invalidate_range, track_->block_input(), track_->block_input()); + track_->Node::InvalidateCache(invalidate_range, track_->block_input(), track_->block_input()); } TrackReplaceBlockWithGapCommand::TrackReplaceBlockWithGapCommand(TrackOutput *track, Block *block, QUndoCommand *command) : @@ -1052,7 +1116,7 @@ void TrackReplaceBlockWithGapCommand::redo_internal() track_->EndOperation(); - track_->InvalidateCache(invalidate_range, track_->block_input(), track_->block_input()); + track_->Node::InvalidateCache(invalidate_range, track_->block_input(), track_->block_input()); } void TrackReplaceBlockWithGapCommand::undo_internal() @@ -1097,20 +1161,20 @@ void TrackReplaceBlockWithGapCommand::undo_internal() // required no gap extension/replacement // However, we may have removed an unnecessary gap that preceded it - if (existing_merged_gap_) { - static_cast(track_->parent())->AddNode(existing_merged_gap_); - track_->AppendBlock(existing_merged_gap_); - existing_merged_gap_ = nullptr; - } + if (existing_merged_gap_) { + static_cast(track_->parent())->AddNode(existing_merged_gap_); + track_->AppendBlock(existing_merged_gap_); + existing_merged_gap_ = nullptr; + } - // Restore block - track_->AppendBlock(block_); + // Restore block + track_->AppendBlock(block_); } track_->EndOperation(); - track_->InvalidateCache(TimeRange(block_->in(), block_->out()), track_->block_input(), track_->block_input()); + track_->Node::InvalidateCache(TimeRange(block_->in(), block_->out()), track_->block_input(), track_->block_input()); } TrackSlideCommand::TrackSlideCommand(TrackOutput* track, const QList& moving_blocks, Block *in_adjacent, Block *out_adjacent, const rational& movement, QUndoCommand* parent) : @@ -1532,18 +1596,21 @@ void TrackListInsertGaps::redo_internal() } QVector blocks_to_split; - QList blocks_to_append_gap_to; + QVector blocks_to_append_gap_to; foreach (TrackOutput* track, working_tracks_) { foreach (Block* b, track->Blocks()) { if (b->type() == Block::kGap && b->in() <= point_ && b->out() >= point_) { + // Found a gap at the location gaps_to_extend_.append(b); + break; } else if (b->type() == Block::kClip && b->out() >= point_) { if (b->out() > point_) { blocks_to_split.append(b); } blocks_to_append_gap_to.append(b); + break; } } } @@ -1711,4 +1778,4 @@ void TimelineSetSelectionsCommand::undo() timeline_->SetSelections(old_); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/undo/undo.h b/app/widget/timelinewidget/undo/undo.h index 220f4133d..adb670e99 100644 --- a/app/widget/timelinewidget/undo/undo.h +++ b/app/widget/timelinewidget/undo/undo.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -32,7 +32,7 @@ #include "undo/undocommand.h" #include "widget/timelinewidget/timelinewidgetselections.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class BlockResizeCommand : public UndoCommand { public: @@ -192,6 +192,7 @@ protected: rational out_; bool splice_; + QUndoCommand* splice_split_command_; Block* trim_out_; Block* trim_in_; @@ -329,17 +330,18 @@ protected: private: TrackOutput* track_; Block* block_; + Block* new_block_; rational new_length_; rational old_length_; rational point_; - Block* new_block_; - QList transitions_to_move_; QObject memory_manager_; + QUndoCommand* add_command_; + }; class TrackSplitAtTimeCommand : public UndoCommand { @@ -471,12 +473,12 @@ private: class BlockLinkManyCommand : public UndoCommand { public: - BlockLinkManyCommand(const QList blocks, bool link, QUndoCommand* parent = nullptr); + BlockLinkManyCommand(const QVector blocks, bool link, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; private: - QList blocks_; + QVector blocks_; }; @@ -631,6 +633,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEUNDOABLE_H diff --git a/app/widget/timelinewidget/view/CMakeLists.txt b/app/widget/timelinewidget/view/CMakeLists.txt index 5a57efbc1..929652ed7 100644 --- a/app/widget/timelinewidget/view/CMakeLists.txt +++ b/app/widget/timelinewidget/view/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/timelinewidget/view/handmovableview.cpp b/app/widget/timelinewidget/view/handmovableview.cpp index f0995eb7b..6c3362e3c 100644 --- a/app/widget/timelinewidget/view/handmovableview.cpp +++ b/app/widget/timelinewidget/view/handmovableview.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "core.h" -OLIVE_NAMESPACE_ENTER +namespace olive { HandMovableView::HandMovableView(QWidget* parent) : QGraphicsView(parent), @@ -115,4 +115,4 @@ const QGraphicsView::DragMode &HandMovableView::GetDefaultDragMode() const return default_drag_mode_; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/view/handmovableview.h b/app/widget/timelinewidget/view/handmovableview.h index 9224069c7..c39f20730 100644 --- a/app/widget/timelinewidget/view/handmovableview.h +++ b/app/widget/timelinewidget/view/handmovableview.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "tool/tool.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class HandMovableView : public QGraphicsView { @@ -54,6 +54,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // HANDMOVABLEVIEW_H diff --git a/app/widget/timelinewidget/view/timelineview.cpp b/app/widget/timelinewidget/view/timelineview.cpp index 63ae9c643..cb2930866 100644 --- a/app/widget/timelinewidget/view/timelineview.cpp +++ b/app/widget/timelinewidget/view/timelineview.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -33,7 +33,7 @@ #include "node/input/media/media.h" #include "project/item/footage/footage.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimelineView::TimelineView(Qt::Alignment vertical_alignment, QWidget *parent) : TimelineViewBase(parent), @@ -115,13 +115,14 @@ void TimelineView::wheelEvent(QWheelEvent *event) return; } else { #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) - + QPoint angle_delta = event->angleDelta(); - if (Config::Current()["InvertTimelineScrollAxes"].toBool()) { + if (Config::Current()["InvertTimelineScrollAxes"].toBool() // Check if config is set to invert timeline axes + && event->source() != Qt::MouseEventSynthesizedBySystem) { // Never flip axes on Apple trackpads though angle_delta = QPoint(angle_delta.y(), angle_delta.x()); } - + QWheelEvent e( #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) event->position(), @@ -228,8 +229,6 @@ void TimelineView::drawBackground(QPainter *painter, const QRectF &rect) void TimelineView::drawForeground(QPainter *painter, const QRectF &rect) { - TimelineViewBase::drawForeground(painter, rect); - // Draw selections if (selections_ && !selections_->isEmpty()) { painter->setPen(Qt::NoPen); @@ -255,7 +254,8 @@ void TimelineView::drawForeground(QPainter *painter, const QRectF &rect) painter->setBrush(Qt::NoBrush); foreach (TimelineViewGhostItem* ghost, (*ghosts_)) { - if (ghost->GetTrack().type() == connected_track_list_->type()) { + if (ghost->GetTrack().type() == connected_track_list_->type() + && !ghost->IsInvisible()) { int track_index = ghost->GetAdjustedTrack().index(); painter->drawRect(TimeToScene(ghost->GetAdjustedIn()), @@ -281,6 +281,9 @@ void TimelineView::drawForeground(QPainter *painter, const QRectF &rect) cursor_x, track_y + GetTrackHeight(track_index)); } + + // Draw standard TimelineViewBase things (such as playhead) + TimelineViewBase::drawForeground(painter, rect); } void TimelineView::ToolChangedEvent(Tool::Item tool) @@ -480,4 +483,4 @@ void TimelineView::UserSetTime(const int64_t &time) emit TimeChanged(time); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/view/timelineview.h b/app/widget/timelinewidget/view/timelineview.h index 88740a93e..71d6eb1d8 100644 --- a/app/widget/timelinewidget/view/timelineview.h +++ b/app/widget/timelinewidget/view/timelineview.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -35,7 +35,7 @@ #include "widget/timelinewidget/undo/undo.h" #include "undo/undostack.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A widget for viewing and interacting Sequences @@ -130,6 +130,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEVIEW_H diff --git a/app/widget/timelinewidget/view/timelineviewbase.cpp b/app/widget/timelinewidget/view/timelineviewbase.cpp index b42978e26..a252a867a 100644 --- a/app/widget/timelinewidget/view/timelineviewbase.cpp +++ b/app/widget/timelinewidget/view/timelineviewbase.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,11 +25,10 @@ #include #include -#include "common/autoscroll.h" #include "common/timecodefunctions.h" #include "config/config.h" -OLIVE_NAMESPACE_ENTER +namespace olive { const double TimelineViewBase::kMaximumScale = 8192; @@ -115,18 +114,6 @@ void TimelineViewBase::SetTime(const int64_t time) { playhead_ = time; - switch (static_cast(Config::Current()["Autoscroll"].toInt())) { - case AutoScroll::kNone: - // Do nothing - break; - case AutoScroll::kPage: - QMetaObject::invokeMethod(this, "PageScrollToPlayhead", Qt::QueuedConnection); - break; - case AutoScroll::kSmooth: - emit RequestCenterScrollOnPlayhead(); - break; - } - // Force redraw for playhead viewport()->update(); } @@ -246,7 +233,7 @@ void TimelineViewBase::UpdateSceneRect() bounding_rect.setLeft(0); // Ensure the scene is always the full length of the timeline with a gap at the end to work with - bounding_rect.setRight(TimeToScene(end_time_) + width() / 2); + bounding_rect.setRight(TimeToScene(end_time_) + width()); // Any further rect processing from derivatives can be done here SceneRectUpdateEvent(bounding_rect); @@ -257,21 +244,6 @@ void TimelineViewBase::UpdateSceneRect() } } -void TimelineViewBase::PageScrollToPlayhead() -{ - int playhead_pos = qRound(GetPlayheadX()); - - int viewport_padding = viewport()->width() / 16; - - if (playhead_pos < horizontalScrollBar()->value()) { - // Anchor the playhead to the RIGHT of where we scroll to - horizontalScrollBar()->setValue(playhead_pos - viewport()->width() + viewport_padding); - } else if (playhead_pos > horizontalScrollBar()->value() + viewport()->width()) { - // Anchor the playhead to the LEFT of where we scroll to - horizontalScrollBar()->setValue(playhead_pos - viewport_padding); - } -} - void TimelineViewBase::resizeEvent(QResizeEvent *event) { QGraphicsView::resizeEvent(event); @@ -359,4 +331,4 @@ bool TimelineViewBase::WheelEventIsAZoomEvent(QWheelEvent *event) return (static_cast(event->modifiers() & Qt::ControlModifier) == !Config::Current()["ScrollZooms"].toBool()); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/view/timelineviewbase.h b/app/widget/timelinewidget/view/timelineviewbase.h index f8da914e7..4ae847391 100644 --- a/app/widget/timelinewidget/view/timelineviewbase.h +++ b/app/widget/timelinewidget/view/timelineviewbase.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "widget/timelinewidget/snapservice.h" #include "widget/timelinewidget/timelinescaledobject.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimelineViewBase : public HandMovableView, public TimelineScaledObject { @@ -60,8 +60,6 @@ signals: void ScaleChanged(double scale); - void RequestCenterScrollOnPlayhead(); - protected: virtual void drawForeground(QPainter *painter, const QRectF &rect) override; @@ -124,16 +122,8 @@ private slots: */ void UpdateSceneRect(); - /** - * @brief Slot to handle page scrolling of the playhead - * - * If the playhead is outside the current scroll bounds, this function will scroll to where it is. Otherwise it will - * do nothing. - */ - void PageScrollToPlayhead(); - }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEVIEWBASE_H diff --git a/app/widget/timelinewidget/view/timelineviewblockitem.cpp b/app/widget/timelinewidget/view/timelineviewblockitem.cpp index 9c3a6ceba..20efa28fe 100644 --- a/app/widget/timelinewidget/view/timelineviewblockitem.cpp +++ b/app/widget/timelinewidget/view/timelineviewblockitem.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -35,7 +35,7 @@ #include "node/block/transition/transition.h" #include "widget/viewer/audiowaveformview.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimelineViewBlockItem::TimelineViewBlockItem(Block *block, QGraphicsItem* parent) : TimelineViewRect(parent), @@ -94,8 +94,6 @@ void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsI painter->setPen(QColor(64, 64, 64)); TrackOutput* track = TrackOutput::TrackFromBlock(block_); if (track) { - QMutexLocker locker(track->waveform_lock()); - AudioVisualWaveform::DrawWaveform(painter, rect().toRect(), this->GetScale(), @@ -122,7 +120,7 @@ void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsI // Linked clips are underlined if (block_->HasLinks()) { QFontMetrics fm = painter->fontMetrics(); - int text_width = qMin(qRound(rect().width()), QFontMetricsWidth(fm, block_->GetLabel())); + int text_width = qMin(qRound(rect().width()), QtUtils::QFontMetricsWidth(fm, block_->GetLabel())); QPointF underline_start = rect().topLeft() + QPointF(0, text_top + fm.height()); QPointF underline_end = underline_start + QPointF(text_width, 0); @@ -194,4 +192,4 @@ void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsI } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/view/timelineviewblockitem.h b/app/widget/timelinewidget/view/timelineviewblockitem.h index fa091e78b..83cef5c0d 100644 --- a/app/widget/timelinewidget/view/timelineviewblockitem.h +++ b/app/widget/timelinewidget/view/timelineviewblockitem.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "timelineviewrect.h" #include "node/block/clip/clip.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A graphical representation of a ClipBlock @@ -46,6 +46,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEVIEWCLIPITEM_H diff --git a/app/widget/timelinewidget/view/timelineviewghostitem.cpp b/app/widget/timelinewidget/view/timelineviewghostitem.cpp index b2a0c86e8..7762fbafb 100644 --- a/app/widget/timelinewidget/view/timelineviewghostitem.cpp +++ b/app/widget/timelinewidget/view/timelineviewghostitem.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { TimelineViewGhostItem::TimelineViewGhostItem() : track_adj_(0), @@ -74,17 +74,6 @@ void TimelineViewGhostItem::SetCanMoveTracks(bool e) can_move_tracks_ = e; } -/*void TimelineViewGhostItem::SetInvisible(bool invisible) -{ - setBrush(Qt::NoBrush); - - if (invisible) { - setPen(Qt::NoPen); - } else { - setPen(QPen(Qt::yellow, 2)); // FIXME: Make customizable via CSS - } -}*/ - const rational &TimelineViewGhostItem::GetIn() const { return in_; @@ -203,4 +192,4 @@ bool TimelineViewGhostItem::HasBeenAdjusted() const || GetTrackAdjustment() != 0; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/view/timelineviewghostitem.h b/app/widget/timelinewidget/view/timelineviewghostitem.h index d13ad7d7c..9f734e45f 100644 --- a/app/widget/timelinewidget/view/timelineviewghostitem.h +++ b/app/widget/timelinewidget/view/timelineviewghostitem.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "timelineviewblockitem.h" #include "timelineviewrect.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A graphical representation of changes the user is making before they apply it */ @@ -142,6 +142,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEVIEWGHOSTITEM_H diff --git a/app/widget/timelinewidget/view/timelineviewmouseevent.cpp b/app/widget/timelinewidget/view/timelineviewmouseevent.cpp index 4e4dc183c..61e697d63 100644 --- a/app/widget/timelinewidget/view/timelineviewmouseevent.cpp +++ b/app/widget/timelinewidget/view/timelineviewmouseevent.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -24,7 +24,7 @@ #include "widget/timelinewidget/timelinescaledobject.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimelineViewMouseEvent::TimelineViewMouseEvent(const qreal &scene_x, const double &scale_x, @@ -100,4 +100,4 @@ void TimelineViewMouseEvent::ignore() source_event_->ignore(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/view/timelineviewmouseevent.h b/app/widget/timelinewidget/view/timelineviewmouseevent.h index b99db096f..f4371660e 100644 --- a/app/widget/timelinewidget/view/timelineviewmouseevent.h +++ b/app/widget/timelinewidget/view/timelineviewmouseevent.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "timeline/timelinecoordinate.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimelineViewMouseEvent { @@ -84,6 +84,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEVIEWMOUSEEVENT_H diff --git a/app/widget/timelinewidget/view/timelineviewrect.cpp b/app/widget/timelinewidget/view/timelineviewrect.cpp index 1948b4f5e..1145671ea 100644 --- a/app/widget/timelinewidget/view/timelineviewrect.cpp +++ b/app/widget/timelinewidget/view/timelineviewrect.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "timelineviewrect.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimelineViewRect::TimelineViewRect(QGraphicsItem* parent) : QGraphicsRectItem(parent), @@ -62,4 +62,4 @@ void TimelineViewRect::TimebaseChangedEvent(const rational &tb) UpdateRect(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timelinewidget/view/timelineviewrect.h b/app/widget/timelinewidget/view/timelineviewrect.h index bfd31d6ab..14311264a 100644 --- a/app/widget/timelinewidget/view/timelineviewrect.h +++ b/app/widget/timelinewidget/view/timelineviewrect.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "timeline/timelinecoordinate.h" #include "../timelinescaledobject.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A base class for graphical representations of Block nodes @@ -55,6 +55,6 @@ protected: TrackReference track_; }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMELINEVIEWRECT_H diff --git a/app/widget/timeruler/CMakeLists.txt b/app/widget/timeruler/CMakeLists.txt index 9c7882713..c1f4f8351 100644 --- a/app/widget/timeruler/CMakeLists.txt +++ b/app/widget/timeruler/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/timeruler/seekablewidget.cpp b/app/widget/timeruler/seekablewidget.cpp index 9c066acf1..b80d332ff 100644 --- a/app/widget/timeruler/seekablewidget.cpp +++ b/app/widget/timeruler/seekablewidget.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/qtutils.h" #include "core.h" -OLIVE_NAMESPACE_ENTER +namespace olive { SeekableWidget::SeekableWidget(QWidget* parent) : TimelineScaledWidget(parent), @@ -41,7 +41,7 @@ SeekableWidget::SeekableWidget(QWidget* parent) : text_height_ = fm.height(); // Set width of playhead marker - playhead_width_ = QFontMetricsWidth(fm, "H"); + playhead_width_ = QtUtils::QFontMetricsWidth(fm, "H"); setContextMenuPolicy(Qt::CustomContextMenu); } @@ -51,6 +51,8 @@ void SeekableWidget::ConnectTimelinePoints(TimelinePoints *points) if (timeline_points_) { disconnect(timeline_points_->workarea(), &TimelineWorkArea::RangeChanged, this, static_cast(&SeekableWidget::update)); disconnect(timeline_points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast(&SeekableWidget::update)); + disconnect(timeline_points_->markers(), &TimelineMarkerList::MarkerAdded, this, static_cast(&SeekableWidget::update)); + disconnect(timeline_points_->markers(), &TimelineMarkerList::MarkerRemoved, this, static_cast(&SeekableWidget::update)); } timeline_points_ = points; @@ -58,6 +60,8 @@ void SeekableWidget::ConnectTimelinePoints(TimelinePoints *points) if (timeline_points_) { connect(timeline_points_->workarea(), &TimelineWorkArea::RangeChanged, this, static_cast(&SeekableWidget::update)); connect(timeline_points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast(&SeekableWidget::update)); + connect(timeline_points_->markers(), &TimelineMarkerList::MarkerAdded, this, static_cast(&SeekableWidget::update)); + connect(timeline_points_->markers(), &TimelineMarkerList::MarkerRemoved, this, static_cast(&SeekableWidget::update)); } update(); @@ -125,27 +129,27 @@ void SeekableWidget::SetScroll(int s) update(); } -double SeekableWidget::ScreenToUnitFloat(int screen) +double SeekableWidget::ScreenToUnitFloat(int screen) const { return (screen + scroll_) / GetScale() / timebase_dbl(); } -int64_t SeekableWidget::ScreenToUnit(int screen) +int64_t SeekableWidget::ScreenToUnit(int screen) const { return qFloor(ScreenToUnitFloat(screen)); } -int64_t SeekableWidget::ScreenToUnitRounded(int screen) +int64_t SeekableWidget::ScreenToUnitRounded(int screen) const { return qRound64(ScreenToUnitFloat(screen)); } -int SeekableWidget::UnitToScreen(int64_t unit) +int SeekableWidget::UnitToScreen(int64_t unit) const { return qFloor(static_cast(unit) * GetScale() * timebase_dbl()) - scroll_; } -int SeekableWidget::TimeToScreen(const rational &time) +int SeekableWidget::TimeToScreen(const rational &time) const { return qFloor(time.toDouble() * GetScale()) - scroll_; } @@ -256,4 +260,4 @@ void SeekableWidget::DrawPlayhead(QPainter *p, int x, int y) p->setRenderHint(QPainter::Antialiasing, false); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timeruler/seekablewidget.h b/app/widget/timeruler/seekablewidget.h index eabd1ccaf..b508e688c 100644 --- a/app/widget/timeruler/seekablewidget.h +++ b/app/widget/timeruler/seekablewidget.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "widget/timelinewidget/snapservice.h" #include "widget/timelinewidget/timelinescaledobject.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class SeekableWidget : public TimelineScaledWidget { @@ -60,14 +60,14 @@ protected: TimelinePoints* timeline_points() const; - double ScreenToUnitFloat(int screen); + double ScreenToUnitFloat(int screen) const; - int64_t ScreenToUnit(int screen); - int64_t ScreenToUnitRounded(int screen); + int64_t ScreenToUnit(int screen) const; + int64_t ScreenToUnitRounded(int screen) const; - int UnitToScreen(int64_t unit); + int UnitToScreen(int64_t unit) const; - int TimeToScreen(const rational& time); + int TimeToScreen(const rational& time) const; void DrawPlayhead(QPainter* p, int x, int y); @@ -100,6 +100,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // SEEKABLEWIDGET_H diff --git a/app/widget/timeruler/timeruler.cpp b/app/widget/timeruler/timeruler.cpp index c9f3d03bd..3b3f92635 100644 --- a/app/widget/timeruler/timeruler.cpp +++ b/app/widget/timeruler/timeruler.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -30,7 +30,7 @@ #include "widget/menu/menu.h" #include "widget/menu/menushared.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimeRuler::TimeRuler(bool text_visible, bool cache_status_visible, QWidget* parent) : SeekableWidget(parent), @@ -48,7 +48,7 @@ TimeRuler::TimeRuler(bool text_visible, bool cache_status_visible, QWidget* pare // Get the "minimum" space allowed between two line markers on the ruler (in screen pixels) // Mediocre but reliable way of scaling UI objects by font/DPI size - minimum_gap_between_lines_ = QFontMetricsWidth(fm, "H"); + minimum_gap_between_lines_ = QtUtils::QFontMetricsWidth(fm, "H"); // Text visibility affects height, so we set that here UpdateHeight(); @@ -209,7 +209,7 @@ void TimeRuler::paintEvent(QPaintEvent *) QRect text_rect; Qt::Alignment text_align; QString timecode_str = Timecode::timestamp_to_timecode(ScreenToUnit(i), timebase(), Core::instance()->GetTimecodeDisplay()); - int timecode_width = QFontMetricsWidth(fm, timecode_str); + int timecode_width = QtUtils::QFontMetricsWidth(fm, timecode_str); int timecode_left; if (centered_text_) { @@ -332,4 +332,4 @@ void TimeRuler::UpdateHeight() setFixedHeight(height); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timeruler/timeruler.h b/app/widget/timeruler/timeruler.h index 131a3c6cc..400bd640f 100644 --- a/app/widget/timeruler/timeruler.h +++ b/app/widget/timeruler/timeruler.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "seekablewidget.h" #include "render/playbackcache.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimeRuler : public SeekableWidget { @@ -69,6 +69,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMERULER_H diff --git a/app/widget/timetarget/CMakeLists.txt b/app/widget/timetarget/CMakeLists.txt index 98f834bd1..5cbea7437 100644 --- a/app/widget/timetarget/CMakeLists.txt +++ b/app/widget/timetarget/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/timetarget/timetarget.cpp b/app/widget/timetarget/timetarget.cpp index 51ec506d3..eb8830bd6 100644 --- a/app/widget/timetarget/timetarget.cpp +++ b/app/widget/timetarget/timetarget.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "timetarget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { TimeTargetObject::TimeTargetObject() : time_target_(nullptr), @@ -60,7 +60,7 @@ TimeRange TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const TimeRang return r; } - QList adjusted = from->TransformTimeTo(r, to, direction); + QVector adjusted = from->TransformTimeTo(r, to, direction); if (adjusted.isEmpty()) { return r; @@ -80,4 +80,4 @@ TimeRange TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const TimeRang return adjusted.size(); }*/ -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/timetarget/timetarget.h b/app/widget/timetarget/timetarget.h index 66ae3a7ca..5826bfd61 100644 --- a/app/widget/timetarget/timetarget.h +++ b/app/widget/timetarget/timetarget.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,7 +23,7 @@ #include "node/node.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class TimeTargetObject { @@ -50,6 +50,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // TIMETARGETOBJECT_H diff --git a/app/widget/toolbar/CMakeLists.txt b/app/widget/toolbar/CMakeLists.txt index 329a59d74..ec3ebbd14 100644 --- a/app/widget/toolbar/CMakeLists.txt +++ b/app/widget/toolbar/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/toolbar/toolbar.cpp b/app/widget/toolbar/toolbar.cpp index 62bb3f5ab..2a6aaac39 100644 --- a/app/widget/toolbar/toolbar.cpp +++ b/app/widget/toolbar/toolbar.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -29,7 +29,7 @@ #include "ui/icons/icons.h" #include "widget/menu/menu.h" -OLIVE_NAMESPACE_ENTER +namespace olive { Toolbar::Toolbar(QWidget *parent) : QWidget(parent) @@ -206,4 +206,4 @@ void Toolbar::TransitionMenuItemTriggered(QAction *a) emit SelectedTransitionChanged(NodeFactory::GetIDFromMenuAction(a)); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/toolbar/toolbar.h b/app/widget/toolbar/toolbar.h index 74c48167d..076a7850e 100644 --- a/app/widget/toolbar/toolbar.h +++ b/app/widget/toolbar/toolbar.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "widget/toolbar/toolbarbutton.h" #include "tool/tool.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A widget containing buttons for all of Olive's application-wide tools. @@ -234,6 +234,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // TOOLBAR_H diff --git a/app/widget/toolbar/toolbarbutton.cpp b/app/widget/toolbar/toolbarbutton.cpp index b1e5630db..df65826c3 100644 --- a/app/widget/toolbar/toolbarbutton.cpp +++ b/app/widget/toolbar/toolbarbutton.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "toolbarbutton.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ToolbarButton::ToolbarButton(QWidget *parent, const Tool::Item &tool) : QPushButton(parent), @@ -34,4 +34,4 @@ const Tool::Item &ToolbarButton::tool() return tool_; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/toolbar/toolbarbutton.h b/app/widget/toolbar/toolbarbutton.h index 0c36136bb..a8ca88dd4 100644 --- a/app/widget/toolbar/toolbarbutton.h +++ b/app/widget/toolbar/toolbarbutton.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "tool/tool.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief Simple derived class of QPushButton to contain an Tool ID. Used as the main widget through Toolbar. @@ -59,6 +59,6 @@ private: Tool::Item tool_; }; -OLIVE_NAMESPACE_EXIT +} #endif // TOOLBARBUTTON_H diff --git a/app/widget/viewer/CMakeLists.txt b/app/widget/viewer/CMakeLists.txt index f745ca0d6..2c7a0a171 100644 --- a/app/widget/viewer/CMakeLists.txt +++ b/app/widget/viewer/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/widget/viewer/audiowaveformview.cpp b/app/widget/viewer/audiowaveformview.cpp index 8d5140b16..d251dd690 100644 --- a/app/widget/viewer/audiowaveformview.cpp +++ b/app/widget/viewer/audiowaveformview.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -28,7 +28,7 @@ #include "config/config.h" #include "timeline/timelinecommon.h" -OLIVE_NAMESPACE_ENTER +namespace olive { AudioWaveformView::AudioWaveformView(QWidget *parent) : SeekableWidget(parent), @@ -36,12 +36,14 @@ AudioWaveformView::AudioWaveformView(QWidget *parent) : { setAutoFillBackground(true); setBackgroundRole(QPalette::Base); + + cached_waveform_.resize(QThread::idealThreadCount()); } void AudioWaveformView::SetViewer(AudioPlaybackCache *playback) { if (playback_) { - disconnect(playback_, &AudioPlaybackCache::Validated, this, &AudioWaveformView::ForceUpdate); + disconnect(playback_, &AudioPlaybackCache::Validated, this, &AudioWaveformView::ForceUpdateOfRange); disconnect(playback_, &AudioPlaybackCache::ParametersChanged, this, &AudioWaveformView::BackendParamsChanged); SetTimebase(0); @@ -50,7 +52,7 @@ void AudioWaveformView::SetViewer(AudioPlaybackCache *playback) playback_ = playback; if (playback_) { - connect(playback_, &AudioPlaybackCache::Validated, this, &AudioWaveformView::ForceUpdate); + connect(playback_, &AudioPlaybackCache::Validated, this, &AudioWaveformView::ForceUpdateOfRange); connect(playback_, &AudioPlaybackCache::ParametersChanged, this, &AudioWaveformView::BackendParamsChanged); SetTimebase(playback_->GetParameters().time_base()); @@ -73,66 +75,45 @@ void AudioWaveformView::paintEvent(QPaintEvent *event) return; } - if (cached_size_ != size() - || cached_scale_ != GetScale() - || cached_scroll_ != GetScroll()) { - - cached_waveform_ = QPixmap(size()); - cached_waveform_.fill(Qt::transparent); - - QIODevice* fs = playback_->CreatePlaybackDevice(); - - if (fs->open(QFile::ReadOnly)) { - - QPainter wave_painter(&cached_waveform_); - - // FIXME: Hardcoded color - wave_painter.setPen(QColor(64, 255, 160)); - - int drew = 0; - - fs->seek(params.samples_to_bytes(ScreenToUnitRounded(0))); - - for (int x=0; xatEnd(); x++) { - int samples_len = ScreenToUnitRounded(x+1) - ScreenToUnitRounded(x); - int max_read_size = params.samples_to_bytes(samples_len); - - QByteArray read_buffer = fs->read(max_read_size); - - // Detect whether we've reached EOF and recalculate sample count if so - if (read_buffer.size() < max_read_size) { - samples_len = params.bytes_to_samples(read_buffer.size()); - } - - QVector samples = AudioVisualWaveform::SumSamples(reinterpret_cast(read_buffer.constData()), - samples_len, - params.channel_count()); - - for (int i=0;iclose(); - - } - - delete fs; - } - QPainter p(this); // Draw in/out points DrawTimelinePoints(&p); - // Draw cached waveform pixmap - p.drawPixmap(0, 0, cached_waveform_); + CachedWaveformInfo wanted_info = {size(), GetScale(), GetScroll(), params}; + + for (int i=0; i(); + connect(cache.watcher, &QFutureWatcher::finished, this, &AudioWaveformView::BackgroundCacheFinished); + cache.watcher->setFuture(QtConcurrent::run(this, + &AudioWaveformView::DrawWaveform, + playback_->CreatePlaybackDevice(), + wanted_info, + slice_start, + slice_end)); + + } + } // Draw playhead p.setPen(PLAYHEAD_COLOR); @@ -141,6 +122,53 @@ void AudioWaveformView::paintEvent(QPaintEvent *event) p.drawLine(playhead_x, 0, playhead_x, height()); } +QPixmap AudioWaveformView::DrawWaveform(QIODevice* fs, CachedWaveformInfo info, int slice_start, int slice_end) const +{ + QPixmap pixmap(slice_end - slice_start, info.size.height()); + pixmap.fill(Qt::transparent); + + if (fs->open(QFile::ReadOnly)) { + + QPainter wave_painter(&pixmap); + + // FIXME: Hardcoded color + wave_painter.setPen(QColor(64, 255, 160)); + + int drew = 0; + + fs->seek(info.params.samples_to_bytes(ScreenToUnitRounded(slice_start))); + + for (int x=slice_start; xatEnd(); x++) { + int samples_len = ScreenToUnitRounded(x+1) - ScreenToUnitRounded(x); + int max_read_size = info.params.samples_to_bytes(samples_len); + + QByteArray read_buffer = fs->read(max_read_size); + + // Detect whether we've reached EOF and recalculate sample count if so + if (read_buffer.size() < max_read_size) { + samples_len = info.params.bytes_to_samples(read_buffer.size()); + } + + QVector samples = AudioVisualWaveform::SumSamples(reinterpret_cast(read_buffer.constData()), + samples_len, + info.params.channel_count()); + + for (int i=0;iclose(); + + } + + delete fs; + + return pixmap; +} + void AudioWaveformView::BackendParamsChanged() { SetTimebase(playback_->GetParameters().time_base()); @@ -148,8 +176,64 @@ void AudioWaveformView::BackendParamsChanged() void AudioWaveformView::ForceUpdate() { - cached_size_ = QSize(); + // Forces the cache to invalidate + for (int i=0; i= width()) { + return; + } + + int start_invalidate = qMax(0, in/cached_waveform_.size()); + int end_invalidate = qMin(cached_waveform_.size()-1, out/cached_waveform_.size()); + + for (int i=start_invalidate; i<=end_invalidate; i++) { + // Invalidate these + cached_waveform_[i].info.size = QSize(); + } + + update(); +} + +void AudioWaveformView::BackgroundCacheFinished() +{ + // Retrieve sender + QFutureWatcher* watcher = static_cast*>(sender()); + + // Determine index + int index = -1; + for (int i=0; i -1) { + // Store generated pixmap + cached_waveform_[index].info = cached_waveform_[index].caching_info; + cached_waveform_[index].pixmap = watcher->result(); + cached_waveform_[index].watcher = nullptr; + + // Reset size + cached_waveform_[index].caching_info.size = QSize(); + + // Update with new pixmap + update(); + } + + // Clean up + delete watcher; +} + +} diff --git a/app/widget/viewer/audiowaveformview.h b/app/widget/viewer/audiowaveformview.h index 13540d394..b8f1ebd49 100644 --- a/app/widget/viewer/audiowaveformview.h +++ b/app/widget/viewer/audiowaveformview.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,6 +21,7 @@ #ifndef AUDIOWAVEFORMVIEW_H #define AUDIOWAVEFORMVIEW_H +#include #include #include "audio/audiovisualwaveform.h" @@ -28,7 +29,7 @@ #include "render/audioplaybackcache.h" #include "widget/timeruler/seekablewidget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class AudioWaveformView : public SeekableWidget { @@ -44,20 +45,50 @@ protected: virtual void paintEvent(QPaintEvent* event) override; private: + struct CachedWaveformInfo { + QSize size; + double scale; + int scroll; + AudioParams params; + + bool operator==(const CachedWaveformInfo& rhs) const + { + return size == rhs.size + && qFuzzyCompare(scale, rhs.scale) + && scroll == rhs.scroll + && params == rhs.params; + } + + bool operator!=(const CachedWaveformInfo& rhs) const + { + return !(*this == rhs); + } + }; + + struct ActiveCache { + QPixmap pixmap; + CachedWaveformInfo info; + CachedWaveformInfo caching_info; + QFutureWatcher* watcher = nullptr; + }; + + QPixmap DrawWaveform(QIODevice *fs, CachedWaveformInfo info, int slice_start, int slice_end) const; + AudioPlaybackCache *playback_; - QPixmap cached_waveform_; - QSize cached_size_; - double cached_scale_; - int cached_scroll_; + QVector cached_waveform_; private slots: void BackendParamsChanged(); void ForceUpdate(); + void ForceUpdateOfRange(const TimeRange& range); + + void BackgroundCacheFinished(); + }; -OLIVE_NAMESPACE_EXIT +} #endif // AUDIOWAVEFORMVIEW_H diff --git a/app/widget/viewer/footageviewer.cpp b/app/widget/viewer/footageviewer.cpp index 9cdccd1b9..2dc2b2f7b 100644 --- a/app/widget/viewer/footageviewer.cpp +++ b/app/widget/viewer/footageviewer.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,16 +26,16 @@ #include "config/config.h" #include "project/project.h" -OLIVE_NAMESPACE_ENTER +namespace olive { FootageViewerWidget::FootageViewerWidget(QWidget *parent) : ViewerWidget(parent), footage_(nullptr) { - video_node_ = new VideoInput(); + video_node_ = new MediaInput(); sequence_.AddNode(video_node_); - audio_node_ = new AudioInput(); + audio_node_ = new MediaInput(); sequence_.AddNode(audio_node_); connect(display_widget(), &ViewerDisplayWidget::DragStarted, this, &FootageViewerWidget::StartFootageDrag); @@ -175,4 +175,4 @@ void FootageViewerWidget::StartAudioDrag() StartFootageDragInternal(false, true); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/viewer/footageviewer.h b/app/widget/viewer/footageviewer.h index af093eb8f..036a96c1f 100644 --- a/app/widget/viewer/footageviewer.h +++ b/app/widget/viewer/footageviewer.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -21,12 +21,11 @@ #ifndef FOOTAGEVIEWERWIDGET_H #define FOOTAGEVIEWERWIDGET_H -#include "node/input/media/audio/audio.h" -#include "node/input/media/video/video.h" +#include "node/input/media/media.h" #include "node/output/viewer/viewer.h" #include "viewer.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class FootageViewerWidget : public ViewerWidget { @@ -49,9 +48,9 @@ private: Sequence sequence_; - VideoInput* video_node_; + MediaInput* video_node_; - AudioInput* audio_node_; + MediaInput* audio_node_; QHash cached_timestamps_; @@ -64,6 +63,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // FOOTAGEVIEWERWIDGET_H diff --git a/app/widget/viewer/gizmotraverser.cpp b/app/widget/viewer/gizmotraverser.cpp index b28128d7f..8105a7338 100644 --- a/app/widget/viewer/gizmotraverser.cpp +++ b/app/widget/viewer/gizmotraverser.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -20,7 +20,7 @@ #include "gizmotraverser.h" -OLIVE_NAMESPACE_ENTER +namespace olive { QVariant GizmoTraverser::ProcessVideoFootage(StreamPtr stream, const rational &input_time) { @@ -28,7 +28,8 @@ QVariant GizmoTraverser::ProcessVideoFootage(StreamPtr stream, const rational &i VideoStreamPtr image_stream = std::static_pointer_cast(stream); - return QSize(image_stream->width(), image_stream->height()); + return QVector2D(image_stream->width() * image_stream->pixel_aspect_ratio().toDouble(), + image_stream->height()); } QVariant GizmoTraverser::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) @@ -37,7 +38,14 @@ QVariant GizmoTraverser::ProcessShader(const Node *node, const TimeRange &range, Q_UNUSED(range) Q_UNUSED(job) - return size_; + return GenerateResolution(); } -OLIVE_NAMESPACE_EXIT +QVariant GizmoTraverser::ProcessFrameGeneration(const Node *node, const GenerateJob &job) +{ + Q_UNUSED(node) + Q_UNUSED(job) + + return GenerateResolution(); +} +} diff --git a/app/widget/viewer/gizmotraverser.h b/app/widget/viewer/gizmotraverser.h index af6601882..3f3e5b715 100644 --- a/app/widget/viewer/gizmotraverser.h +++ b/app/widget/viewer/gizmotraverser.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -23,28 +23,35 @@ #include "node/traverser.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class GizmoTraverser : public NodeTraverser { public: - GizmoTraverser(const QSize& sequence_resolution) : + GizmoTraverser(const QVector2D& sequence_resolution) : size_(sequence_resolution) { } protected: - virtual QVariant ProcessVideoFootage(StreamPtr stream, const rational &input_time); + virtual QVariant ProcessVideoFootage(StreamPtr stream, const rational &input_time) override; - virtual QVariant ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job); + virtual QVariant ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job) override; + + virtual QVector2D GenerateResolution() const override + { + return size_; + } + + virtual QVariant ProcessFrameGeneration(const Node *node, const GenerateJob& job) override; // FIXME: Do something about audio? private: - QSize size_; + QVector2D size_; }; -OLIVE_NAMESPACE_EXIT +} #endif // GIZMOTRAVERSER_H diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 5d6bdca82..bf746dcd9 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -37,12 +37,12 @@ #include "config/config.h" #include "project/item/sequence/sequence.h" #include "project/project.h" -#include "render/pixelformat.h" +#include "render/rendermanager.h" #include "task/taskmanager.h" #include "widget/menu/menu.h" #include "window/mainwindow/mainwindow.h" -OLIVE_NAMESPACE_ENTER +namespace olive { QVector ViewerWidget::instances_; @@ -82,6 +82,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : // Create waveform view when audio is connected and video isn't waveform_view_ = new AudioWaveformView(); + PassWheelEventsToScrollBar(waveform_view_); stack_->addWidget(waveform_view_); // Create time ruler @@ -108,19 +109,10 @@ ViewerWidget::ViewerWidget(QWidget *parent) : // FIXME: Magic number SetScale(48.0); - // Start background renderer - renderer_ = new OpenGLBackend(this); - renderer_->SetAutoCacheEnabled(true); - renderer_->SetRenderMode(RenderMode::kOffline); - renderer_->SetPreviewGenerationEnabled(true); - // Ensures that seeking on the waveform view updates the time as expected connect(waveform_view_, &AudioWaveformView::TimeChanged, this, &ViewerWidget::TimeChangedFromWaveform); connect(waveform_view_, &AudioWaveformView::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu); - // Ensures renderer is updated if the global pixel format is changed - connect(PixelFormat::instance(), &PixelFormat::FormatChanged, this, &ViewerWidget::UpdateRendererVideoParameters); - connect(&playback_backup_timer_, &QTimer::timeout, this, &ViewerWidget::PlaybackTimerUpdate); SetAutoMaxScrollBar(true); @@ -167,7 +159,7 @@ void ViewerWidget::TimeChangedEvent(const int64_t &i) } if (!pause_autocache_during_playback_ || !IsPlaying()) { - renderer_->SetAutoCachePlayhead(time_set); + auto_cacher_.SetPlayhead(time_set); } display_widget_->SetTime(time_set); @@ -192,8 +184,6 @@ void ViewerWidget::ConnectNodeInternal(ViewerOutput *n) ruler()->SetPlaybackCache(n->video_frame_cache()); - n->audio_playback_cache()->SetParameters(n->audio_params()); - SetViewerResolution(n->video_params().width(), n->video_params().height()); SetViewerPixelAspect(n->video_params().pixel_aspect_ratio()); last_length_ = rational(); @@ -209,6 +199,8 @@ void ViewerWidget::ConnectNodeInternal(ViewerOutput *n) using_manager = nullptr; } + auto_cacher_.SetColorManager(using_manager); + display_widget_->ConnectColorManager(using_manager); foreach (ViewerWindow* window, windows_) { window->display_widget()->ConnectColorManager(using_manager); @@ -251,6 +243,7 @@ void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n) foreach (ViewerWindow* window, windows_) { window->display_widget()->DisconnectColorManager(); } + auto_cacher_.SetColorManager(nullptr); waveform_view_->SetViewer(nullptr); waveform_view_->ConnectTimelinePoints(nullptr); @@ -261,7 +254,7 @@ void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n) void ViewerWidget::ConnectedNodeChanged(ViewerOutput *n) { - renderer_->SetViewerNode(n); + auto_cacher_.SetViewerNode(n); } void ViewerWidget::ScaleChangedEvent(const double &s) @@ -355,18 +348,18 @@ void ViewerWidget::ForceUpdate() void ViewerWidget::SetAutoCacheEnabled(bool e) { - renderer_->SetAutoCachePaused(!e); + auto_cacher_.SetPaused(!e); } void ViewerWidget::CacheEntireSequence() { - renderer_->AutoCacheRange(TimeRange(rational(), GetConnectedNode()->video_frame_cache()->GetLength())); + auto_cacher_.ForceCacheRange(TimeRange(rational(), GetConnectedNode()->video_frame_cache()->GetLength())); } void ViewerWidget::CacheSequenceInOut() { if (GetConnectedTimelinePoints() && GetConnectedTimelinePoints()->workarea()->enabled()) { - renderer_->AutoCacheRange(GetConnectedTimelinePoints()->workarea()->range()); + auto_cacher_.ForceCacheRange(GetConnectedTimelinePoints()->workarea()->range()); } else { QMessageBox::warning(this, tr("Error"), @@ -396,7 +389,8 @@ FramePtr ViewerWidget::DecodeCachedImage(const QString &fn, const rational& time void ViewerWidget::DecodeCachedImage(RenderTicketPtr ticket, const QString &fn, const rational& time) const { - ticket->Finish(QVariant::fromValue(DecodeCachedImage(fn, time))); + ticket->Start(); + ticket->Finish(QVariant::fromValue(DecodeCachedImage(fn, time)), false); } bool ViewerWidget::ShouldForceWaveform() const @@ -472,7 +466,7 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only) // Kindly tell all viewers to stop caching if (pause_autocache_during_playback_) { foreach (ViewerWidget* viewer, instances_) { - viewer->renderer_->ClearVideoQueue(); + viewer->auto_cacher_.ClearVideoQueue(); } } @@ -619,11 +613,6 @@ void ViewerWidget::RequestNextFrameForQueue() watcher->SetTicket(GetFrame(next_time, false)); } -PixelFormat::Format ViewerWidget::GetCurrentPixelFormat() const -{ - return PixelFormat::instance()->GetConfiguredFormatForMode(RenderMode::kOffline); -} - RenderTicketPtr ViewerWidget::GetFrame(const rational &t, bool clear_render_queue) { QByteArray cached_hash = GetConnectedNode()->video_frame_cache()->GetHash(t); @@ -633,14 +622,14 @@ RenderTicketPtr ViewerWidget::GetFrame(const rational &t, bool clear_render_queu if (cached_hash.isEmpty() || !QFileInfo::exists(cache_fn)) { // Frame hasn't been cached, start render job if (clear_render_queue) { - renderer_->ClearVideoQueue(); + auto_cacher_.ClearVideoQueue(); } - return renderer_->RenderFrame(t, true); + return auto_cacher_.GetSingleFrame(t); } else { // Frame has been cached, grab the frame - RenderTicketPtr ticket = std::make_shared(RenderTicket::kTypeVideo, - QVariant::fromValue(t)); + RenderTicketPtr ticket = std::make_shared(); + ticket->setProperty("time", QVariant::fromValue(t)); QtConcurrent::run(this, &ViewerWidget::DecodeCachedImage, ticket, cache_fn, t); return ticket; @@ -896,7 +885,7 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos) // Auto-cache QAction* autocache_action = cache_menu->addAction(tr("Auto-Cache")); autocache_action->setCheckable(true); - autocache_action->setChecked(!renderer_->IsAutoCachePaused()); + autocache_action->setChecked(!auto_cacher_.IsPaused()); connect(autocache_action, &QAction::triggered, this, &ViewerWidget::SetAutoCacheEnabled); cache_menu->addSeparator(); @@ -981,7 +970,7 @@ void ViewerWidget::Pause() { PauseInternal(); - renderer_->SetAutoCachePlayhead(GetTime()); + auto_cacher_.SetPlayhead(GetTime()); } void ViewerWidget::ShuttleLeft() @@ -1162,25 +1151,14 @@ void ViewerWidget::InterlacingChangedSlot(VideoParams::Interlacing interlacing) void ViewerWidget::UpdateRendererVideoParameters() { - renderer_->ClearVideoQueue(); - - renderer_->SetVideoParams(GetConnectedNode()->video_params()); - - // In case the user is pressing the mouse at this exact moment - renderer_->IgnoreNextMouseButton(); - - GetConnectedNode()->video_frame_cache()->InvalidateAll(); - display_widget_->SetVideoParams(GetConnectedNode()->video_params()); + foreach (ViewerWindow* window, windows_) { + window->display_widget()->SetVideoParams(GetConnectedNode()->video_params()); + } } void ViewerWidget::UpdateRendererAudioParameters() { - renderer_->ClearAudioQueue(); - - renderer_->SetAudioParams(GetConnectedNode()->audio_params()); - - GetConnectedNode()->audio_playback_cache()->InvalidateAll(); } void ViewerWidget::SetZoomFromMenu(QAction *action) @@ -1222,4 +1200,4 @@ void ViewerWidget::ViewerShiftedRange(const rational &from, const rational &to) } } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 06b096d7d..40bdc7053 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -32,8 +32,8 @@ #include "common/rational.h" #include "node/output/viewer/viewer.h" #include "panel/scope/scope.h" -#include "render/backend/opengl/openglbackend.h" -#include "render/backend/renderticketwatcher.h" +#include "render/previewautocacher.h" +#include "threading/threadticketwatcher.h" #include "viewerdisplay.h" #include "viewerplaybacktimer.h" #include "viewerqueue.h" @@ -42,7 +42,7 @@ #include "widget/playbackcontrols/playbackcontrols.h" #include "widget/timebased/timebased.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief An OpenGL-based viewer widget with playback controls (a PlaybackControls widget). @@ -82,11 +82,6 @@ public: */ void SetFullScreen(QScreen* screen = nullptr); - RenderBackend* renderer() const - { - return renderer_; - } - ColorManager* color_manager() const { return display_widget_->color_manager(); @@ -196,8 +191,6 @@ private: void RequestNextFrameForQueue(); - PixelFormat::Format GetCurrentPixelFormat() const; - RenderTicketPtr GetFrame(const rational& t, bool clear_render_queue); void FinishPlayPreprocess(); @@ -246,8 +239,6 @@ private: ViewerQueue playback_queue_; int64_t playback_queue_next_frame_; - RenderBackend* renderer_; - bool prequeuing_; QList nonqueue_watchers_; @@ -256,6 +247,8 @@ private: int prequeue_length_; + PreviewAutoCacher auto_cacher_; + static QVector instances_; private slots: @@ -273,7 +266,7 @@ private slots: void SetZoomFromMenu(QAction* action); - void ViewerShiftedRange(const OLIVE_NAMESPACE::rational& from, const OLIVE_NAMESPACE::rational& to); + void ViewerShiftedRange(const olive::rational& from, const olive::rational& to); void UpdateStack(); @@ -293,7 +286,7 @@ private slots: void RendererGeneratedFrameForQueue(); - void ViewerInvalidatedVideoRange(const OLIVE_NAMESPACE::TimeRange &range); + void ViewerInvalidatedVideoRange(const olive::TimeRange &range); void ManualSwitchToWaveform(bool e); @@ -301,6 +294,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // VIEWER_WIDGET_H diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 983f422e1..f2ca65a63 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -31,16 +31,15 @@ #include "common/define.h" #include "common/functiontimer.h" -#include "gizmotraverser.h" -#include "render/backend/opengl/openglrenderfunctions.h" -#include "render/backend/opengl/openglshader.h" -#include "render/pixelformat.h" +#include "config/config.h" #include "core.h" +#include "gizmotraverser.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) : ManagedDisplayWidget(parent), + deinterlace_texture_(nullptr), signal_cursor_color_(false), gizmos_(nullptr), gizmo_click_(false), @@ -50,13 +49,15 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) : { connect(Core::instance(), &Core::ToolChanged, this, &ViewerDisplayWidget::UpdateCursor); + connect(this, &ViewerDisplayWidget::InnerWidgetMouseMove, this, &ViewerDisplayWidget::EmitColorAtCursor); + // Initializes cursor based on tool UpdateCursor(); } ViewerDisplayWidget::~ViewerDisplayWidget() { - ContextCleanup(); + OnDestroy(); } void ViewerDisplayWidget::SetMatrixTranslate(const QMatrix4x4 &mat) @@ -82,19 +83,10 @@ void ViewerDisplayWidget::UpdateCursor() } } -QMatrix4x4 ViewerDisplayWidget::GetCompleteMatrixFlippedYTranslation() -{ - QMatrix4x4 mat = combined_matrix_; - - mat.data()[13] *= -1.0f; - - return mat; -} - void ViewerDisplayWidget::SetSignalCursorColorEnabled(bool e) { signal_cursor_color_ = e; - setMouseTracking(e); + inner_widget()->setMouseTracking(e); } void ViewerDisplayWidget::SetImage(FramePtr in_buffer) @@ -104,13 +96,14 @@ void ViewerDisplayWidget::SetImage(FramePtr in_buffer) if (last_loaded_buffer_) { makeCurrent(); - if (!texture_.IsCreated() - || texture_.width() != in_buffer->width() - || texture_.height() != in_buffer->height() - || texture_.format() != in_buffer->format()) { - texture_.Create(context(), in_buffer->video_params(), in_buffer->data(), in_buffer->linesize_pixels()); + if (!texture_ + || texture_->width() != in_buffer->width() + || texture_->height() != in_buffer->height() + || texture_->format() != in_buffer->format() + || texture_->channel_count() != in_buffer->channel_count()) { + texture_ = renderer()->CreateTexture(in_buffer->video_params(), in_buffer->data(), in_buffer->linesize_pixels()); } else { - texture_.Upload(in_buffer); + texture_->Upload(in_buffer->data(), in_buffer->linesize_pixels()); } doneCurrent(); @@ -122,6 +115,14 @@ void ViewerDisplayWidget::SetImage(FramePtr in_buffer) void ViewerDisplayWidget::SetDeinterlacing(bool e) { deinterlace_ = e; + + if (deinterlace_) { + deinterlace_shader_ = renderer()->CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/deinterlace.frag")))); + } else { + renderer()->DestroyNativeShader(deinterlace_shader_); + deinterlace_texture_ = nullptr; + } + update(); } @@ -177,18 +178,18 @@ QPoint ViewerDisplayWidget::TransformViewerSpaceToBufferSpace(QPoint pos) * Inversion will only fail if the viewer has been scaled by 0 in any direction * which I think should never happen. */ - return pos * GenerateWorldTransform().inverted(); + return pos * GenerateGizmoTransform().inverted(); } void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton && gizmos_ - && gizmos_->GizmoPress(gizmo_db_, TransformViewerSpaceToBufferSpace(event->pos()), - QVector2D(GetTexturePosition(size())), size())) { + && gizmos_->GizmoPress(gizmo_db_, TransformViewerSpaceToBufferSpace(event->pos()))) { // Handle gizmo click gizmo_click_ = true; gizmo_drag_time_ = GetGizmoTime(); + gizmo_start_drag_ = event->pos(); } else if (IsHandDrag(event)) { @@ -205,34 +206,13 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) emit DragStarted(); } - QOpenGLWidget::mousePressEvent(event); + ManagedDisplayWidget::mousePressEvent(event); } } void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) { - // Do this no matter what, emits signal to any pixel samplers - if (signal_cursor_color_) { - Color reference, display; - - if (last_loaded_buffer_) { - QVector3D pixel_pos(static_cast(event->x()) / static_cast(width()) * 2.0f - 1.0f, - static_cast(event->y()) / static_cast(height()) * 2.0f - 1.0f, - 0); - - pixel_pos = GenerateWorldTransform().inverted() * pixel_pos; - - int frame_x = qRound((pixel_pos.x() + 1.0f) * 0.5f * last_loaded_buffer_->width()); - int frame_y = qRound((pixel_pos.y() + 1.0f) * 0.5f * last_loaded_buffer_->height()); - - reference = last_loaded_buffer_->get_pixel(frame_x, frame_y); - display = color_service()->ConvertColor(reference); - } - - emit CursorColor(reference, display); - } - // Handle hand dragging if (hand_dragging_) { @@ -246,13 +226,14 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) // Signal movement gizmos_->GizmoMove(TransformViewerSpaceToBufferSpace(event->pos()), - QVector2D(GetTexturePosition(size())), gizmo_drag_time_); + gizmo_drag_time_); + gizmo_start_drag_ = event->pos(); update(); } else { // Default behavior - QOpenGLWidget::mouseMoveEvent(event); + ManagedDisplayWidget::mouseMoveEvent(event); } } @@ -275,70 +256,68 @@ void ViewerDisplayWidget::mouseReleaseEvent(QMouseEvent *event) } else { // Default behavior - QOpenGLWidget::mouseReleaseEvent(event); + ManagedDisplayWidget::mouseReleaseEvent(event); } } -QMatrix4x4 ViewerDisplayWidget::GetMatrixTranslate() +void ViewerDisplayWidget::OnPaint() { - return translate_matrix_; -} - -void ViewerDisplayWidget::initializeGL() -{ - ManagedDisplayWidget::initializeGL(); - - connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ViewerDisplayWidget::ContextCleanup, Qt::DirectConnection); -} - -void ViewerDisplayWidget::paintGL() -{ - // Get functions attached to this context (they will already be initialized) - QOpenGLFunctions* f = context()->functions(); - // Clear background to empty - f->glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - f->glClear(GL_COLOR_BUFFER_BIT); + QColor bg_color = palette().window().color(); + renderer()->ClearDestination(bg_color.redF(), bg_color.greenF(), bg_color.blueF()); // We only draw if we have a pipeline if (last_loaded_buffer_ && color_service()) { - // Bind retrieved texture - f->glBindTexture(GL_TEXTURE_2D, texture_.texture()); + TexturePtr texture_to_draw = texture_; - // Set some parameters - color_service()->pipeline()->bind(); - color_service()->pipeline()->setUniformValue("ove_resolution", texture_.width(), texture_.height()); - color_service()->pipeline()->setUniformValue("ove_deinterlace", deinterlace_); - color_service()->pipeline()->release(); + if (deinterlace_) { + if (!deinterlace_texture_ + || deinterlace_texture_->params() != texture_to_draw->params()) { + // (Re)create texture + deinterlace_texture_ = renderer()->CreateTexture(texture_to_draw->params()); + } - // Blit using the color service - color_service()->ProcessOpenGL(true, GetCompleteMatrixFlippedYTranslation()); + ShaderJob job; + job.InsertValue(QStringLiteral("resolution_in"), ShaderValue(QVector2D(texture_to_draw->width(), texture_to_draw->height()), NodeParam::kVec2)); + job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(texture_to_draw), NodeParam::kTexture)); - // Release retrieved texture - f->glBindTexture(GL_TEXTURE_2D, 0); + renderer()->BlitToTexture(deinterlace_shader_, job, deinterlace_texture_.get()); + texture_to_draw = deinterlace_texture_; + } + + // Draw texture through color transform + int device_width = width() * devicePixelRatioF(); + int device_height = height() * devicePixelRatioF(); + VideoParams::Format device_format = static_cast(Config::Current()["OfflinePixelFormat"].toInt()); + VideoParams device_params(device_width, device_height, device_format, VideoParams::kInternalChannelCount); + + renderer()->BlitColorManaged(color_service(), texture_to_draw, true, device_params, false, + combined_matrix_flipped_); } QTransform world_transform = GenerateWorldTransform(); // Draw gizmos if we have any if (gizmos_) { - GizmoTraverser gt(QSize(gizmo_params_.width(), gizmo_params_.height())); + GizmoTraverser gt(QVector2D(gizmo_params_.width() * gizmo_params_.pixel_aspect_ratio().toDouble(), + gizmo_params_.height())); rational node_time = GetGizmoTime(); - gizmo_db_ = gt.GenerateDatabase(gizmos_, TimeRange(node_time, node_time)); + gizmo_db_ = gt.GenerateDatabase(gizmos_, TimeRange(node_time, + node_time + gizmo_params_.time_base())); - QPainter p(this); - p.setWorldTransform(world_transform); - gizmos_->DrawGizmos(gizmo_db_, &p, QVector2D(GetTexturePosition(size())), size()); + QPainter p(inner_widget()); + p.setWorldTransform(GenerateGizmoTransform()); + gizmos_->DrawGizmos(gizmo_db_, &p); } // Draw action/title safe areas if (safe_margin_.is_enabled()) { - QPainter p(this); + QPainter p(inner_widget()); p.setWorldTransform(world_transform); p.setPen(Qt::lightGray); @@ -371,6 +350,13 @@ void ViewerDisplayWidget::paintGL() } } +void ViewerDisplayWidget::OnDestroy() +{ + ManagedDisplayWidget::OnDestroy(); + + texture_ = nullptr; +} + QPointF ViewerDisplayWidget::GetTexturePosition(const QPoint &screen_pos) { return GetTexturePosition(screen_pos.x(), screen_pos.y()); @@ -401,6 +387,10 @@ void ViewerDisplayWidget::UpdateMatrix() { combined_matrix_ = scale_matrix_ * translate_matrix_; + combined_matrix_flipped_.setToIdentity(); + combined_matrix_flipped_.scale(1.0, -1.0, 1.0); + combined_matrix_flipped_ *= combined_matrix_; + update(); } @@ -426,13 +416,32 @@ QTransform ViewerDisplayWidget::GenerateWorldTransform() return world; } -void ViewerDisplayWidget::ContextCleanup() +QTransform ViewerDisplayWidget::GenerateGizmoTransform() { - makeCurrent(); - - texture_.Destroy(); - - doneCurrent(); + QVector2D viewer_scale(GetTexturePosition(size())); + QTransform gizmo_transform = GenerateWorldTransform(); + gizmo_transform.scale(viewer_scale.x(), viewer_scale.y()); + gizmo_transform.scale(gizmo_params_.pixel_aspect_ratio().flipped().toDouble(), 1); + return gizmo_transform; } -OLIVE_NAMESPACE_EXIT +void ViewerDisplayWidget::EmitColorAtCursor(QMouseEvent *e) +{ + // Do this no matter what, emits signal to any pixel samplers + if (signal_cursor_color_) { + Color reference, display; + + if (last_loaded_buffer_) { + QPointF pixel_pos = GenerateGizmoTransform().inverted().map(e->pos()); + + pixel_pos /= last_loaded_buffer_->video_params().divider(); + + reference = last_loaded_buffer_->get_pixel(qRound(pixel_pos.x()), qRound(pixel_pos.y())); + display = color_service()->ConvertColor(reference); + } + + emit CursorColor(reference, display); + } +} + +} diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index 0f8f6866f..3c3c6ad98 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,12 +22,9 @@ #define VIEWERGLWIDGET_H #include +#include #include "node/node.h" -#include "render/backend/opengl/openglcolorprocessor.h" -#include "render/backend/opengl/openglframebuffer.h" -#include "render/backend/opengl/openglshader.h" -#include "render/backend/opengl/opengltexture.h" #include "render/color.h" #include "render/colormanager.h" #include "tool/tool.h" @@ -35,7 +32,7 @@ #include "widget/manageddisplay/manageddisplay.h" #include "widget/timetarget/timetarget.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief The inner display/rendering widget of a Viewer class. @@ -67,17 +64,6 @@ public: virtual ~ViewerDisplayWidget() override; - /** - * @brief Return the translation only matrix. - */ - QMatrix4x4 GetMatrixTranslate(); - - /** - * @brief Return the complete translation and scale matrix but with the Y translation flipped - * as OpenGL stores textures "upside down". - */ - QMatrix4x4 GetCompleteMatrixFlippedYTranslation(); - const ViewerSafeMarginInfo& GetSafeMargin() const; void SetSafeMargins(const ViewerSafeMarginInfo& safe_margin); @@ -181,19 +167,14 @@ protected: */ virtual void mouseReleaseEvent(QMouseEvent* event) override; - /** - * @brief Initialize function to set up the OpenGL context upon its construction - * - * Currently primarily used to regenerate the pipeline shader used for drawing. - */ - virtual void initializeGL() override; - /** * @brief Paint function to display the texture (received in SetTexture()) on screen. * * Simple OpenGL drawing function for painting the texture on screen. Standardized around OpenGL ES 3.2 Core. */ - virtual void paintGL() override; + virtual void OnPaint() override; + + virtual void OnDestroy() override; private: QPointF GetTexturePosition(const QPoint& screen_pos); @@ -208,10 +189,22 @@ private: QTransform GenerateWorldTransform(); + QTransform GenerateGizmoTransform(); + /** * @brief Internal reference to the OpenGL texture to draw. Set in SetTexture() and used in paintGL(). */ - OpenGLTexture texture_; + TexturePtr texture_; + + /** + * @brief Internal texture to deinterlace to + */ + TexturePtr deinterlace_texture_; + + /** + * @brief Deinterlace shader + */ + QVariant deinterlace_shader_; /** * @brief Translation only matrix (defaults to identity). @@ -227,6 +220,7 @@ private: * @brief Cached result of translate_matrix_ and scale_matrix_ multiplied */ QMatrix4x4 combined_matrix_; + QMatrix4x4 combined_matrix_flipped_; bool signal_cursor_color_; @@ -236,6 +230,7 @@ private: NodeValueDatabase gizmo_db_; rational gizmo_drag_time_; VideoParams gizmo_params_; + QPoint gizmo_start_drag_; bool gizmo_click_; rational time_; @@ -251,13 +246,10 @@ private: bool deinterlace_; private slots: - /** - * @brief Slot to connect just before the OpenGL context is destroyed to clean up resources - */ - void ContextCleanup(); + void EmitColorAtCursor(QMouseEvent* e); }; -OLIVE_NAMESPACE_EXIT +} #endif // VIEWERGLWIDGET_H diff --git a/app/widget/viewer/viewerplaybacktimer.cpp b/app/widget/viewer/viewerplaybacktimer.cpp index e07e925c9..d2de65c77 100644 --- a/app/widget/viewer/viewerplaybacktimer.cpp +++ b/app/widget/viewer/viewerplaybacktimer.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { void ViewerPlaybackTimer::Start(const int64_t &start_timestamp, const int &playback_speed, const double &timebase) { @@ -41,4 +41,4 @@ int64_t ViewerPlaybackTimer::GetTimestampNow() const return start_timestamp_ + frames_since_start * playback_speed_; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/viewer/viewerplaybacktimer.h b/app/widget/viewer/viewerplaybacktimer.h index a4669a571..bd613d687 100644 --- a/app/widget/viewer/viewerplaybacktimer.h +++ b/app/widget/viewer/viewerplaybacktimer.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ViewerPlaybackTimer { public: @@ -43,6 +43,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // VIEWERPLAYBACKTIMER_H diff --git a/app/widget/viewer/viewerqueue.h b/app/widget/viewer/viewerqueue.h index 8a421d05c..3e0ddfdd8 100644 --- a/app/widget/viewer/viewerqueue.h +++ b/app/widget/viewer/viewerqueue.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "codec/frame.h" -OLIVE_NAMESPACE_ENTER +namespace olive { struct ViewerPlaybackFrame { rational timestamp; @@ -52,6 +52,6 @@ public: }; -OLIVE_NAMESPACE_EXIT +} #endif // VIEWERQUEUE_H diff --git a/app/widget/viewer/viewersafemargininfo.h b/app/widget/viewer/viewersafemargininfo.h index b208cfb12..73add3bea 100644 --- a/app/widget/viewer/viewersafemargininfo.h +++ b/app/widget/viewer/viewersafemargininfo.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/define.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ViewerSafeMarginInfo { public: @@ -70,6 +70,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // VIEWERSAFEMARGININFO_H diff --git a/app/widget/viewer/viewersizer.cpp b/app/widget/viewer/viewersizer.cpp index 33a1f211c..e53ec1088 100644 --- a/app/widget/viewer/viewersizer.cpp +++ b/app/widget/viewer/viewersizer.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { ViewerSizer::ViewerSizer(QWidget *parent) : QWidget(parent), @@ -107,117 +107,78 @@ void ViewerSizer::UpdateSize() return; } - widget_->setVisible(true); - - QSize child_size; - QMatrix4x4 child_matrix; - + // Calculate how much UI space is available (it will be less if we have to show scrollbars) int available_width = width(); int available_height = height(); - double sequence_aspect_ratio = static_cast(width_) / static_cast(height_) + + // Determine if we need scrollbars for the zoom we want + horiz_scrollbar_->setVisible(zoom_ > 0 && GetZoomedValue(width_) > available_width); + vert_scrollbar_->setVisible(zoom_ > 0 && GetZoomedValue(height_) > available_height); + + // Horizontal scrollbar will reduce the available height + if (horiz_scrollbar_->isVisible()) { + available_height -= horiz_scrollbar_->sizeHint().height(); + } + + // Vertical scrollbar will reduce the available width + if (vert_scrollbar_->isVisible()) { + available_width -= vert_scrollbar_->sizeHint().width(); + } + + // Set correct values on horizontal scrollbar + if (horiz_scrollbar_->isVisible()) { + horiz_scrollbar_->resize(available_width, horiz_scrollbar_->sizeHint().height()); + horiz_scrollbar_->move(0, this->height() - horiz_scrollbar_->height() - 1); + horiz_scrollbar_->setMaximum(GetZoomedValue(width_) - available_width); + horiz_scrollbar_->setPageStep(available_width); + } + + // Set correct values on vertical scrollbar + if (vert_scrollbar_->isVisible()) { + vert_scrollbar_->resize(vert_scrollbar_->sizeHint().width(), available_height); + vert_scrollbar_->move(this->width() - vert_scrollbar_->width() - 1, 0); + vert_scrollbar_->setMaximum(GetZoomedValue(height_) - available_height); + vert_scrollbar_->setPageStep(available_height); + } + + // Size widget to the UI space we've calculated + widget_->setVisible(true); + widget_->resize(available_width, available_height); + + // Adjust to aspect ratio + double sequence_aspect_ratio = double(width_) / double(height_) * pixel_aspect_.toDouble(); + double our_aspect_ratio = double(available_width) / double(available_height); - if (zoom_ <= 0) { + QMatrix4x4 child_matrix; + double current_scale; - // If zoom is zero or negative, we auto-fit - double our_aspect_ratio = static_cast(available_width) / static_cast(available_height); + if (our_aspect_ratio > sequence_aspect_ratio) { - child_size = size(); - - if (our_aspect_ratio > sequence_aspect_ratio) { - // This container is wider than the image, scale by height - child_size = QSize(qRound(child_size.height() * sequence_aspect_ratio), available_height); - } else { - // This container is taller than the image, scale by width - child_size = QSize(available_width, qRound(child_size.width() / sequence_aspect_ratio)); - } - - // No scrollbars necessary for auto-fit - horiz_scrollbar_->setVisible(false); - vert_scrollbar_->setVisible(false); + // This container is wider than the image, scale by height + child_matrix.scale(sequence_aspect_ratio / our_aspect_ratio, 1.0); + current_scale = double(available_height) / double(height_); } else { - float x_scale = 1.0f; - float y_scale = 1.0f; + // This container is taller than the image, scale by width + child_matrix.scale(1.0, our_aspect_ratio / sequence_aspect_ratio); + current_scale = double(available_width) / double(width_); - int zoomed_width = GetZoomedValue(width_); - int zoomed_height = GetZoomedValue(height_); - - bool child_exceeds_parent_width = (zoomed_width > available_width); - bool child_exceeds_parent_height = (zoomed_height > available_height); - - if (child_exceeds_parent_width != child_exceeds_parent_height) { - // One scrollbar definitely needs to be shown, so it's a matter of determining if the other - // does too since adding one scrollbar necessary limits the total area - - if (child_exceeds_parent_height) { - // A vertical scrollbar will need to be shown, which limits the width - child_exceeds_parent_width = (zoomed_width > available_width - vert_scrollbar_->sizeHint().width()); - } else { - // A horizontal scrollbar will need to be shown, which limits the height - child_exceeds_parent_height = (zoomed_height > available_height - horiz_scrollbar_->sizeHint().height()); - } - } - - horiz_scrollbar_->setVisible(child_exceeds_parent_width); - vert_scrollbar_->setVisible(child_exceeds_parent_height); - - if (vert_scrollbar_->isVisible()) { - // Limit available width for further calculations - available_width -= vert_scrollbar_->sizeHint().width(); - } - - if (horiz_scrollbar_->isVisible()) { - // Limit available height for further calculations - available_height -= horiz_scrollbar_->sizeHint().height(); - } - - if (horiz_scrollbar_->isVisible()) { - x_scale = static_cast(zoomed_width) / static_cast(available_width); - - // Update scrollbar sizes - int horiz_width = this->width(); - - if (vert_scrollbar_->isVisible()) { - horiz_width -= vert_scrollbar_->sizeHint().width(); - } - - horiz_scrollbar_->resize(horiz_width, horiz_scrollbar_->sizeHint().height()); - horiz_scrollbar_->move(0, this->height() - horiz_scrollbar_->height() - 1); - horiz_scrollbar_->setMaximum(zoomed_width - available_width); - horiz_scrollbar_->setPageStep(available_width); - - zoomed_width = available_width; - } - - if (vert_scrollbar_->isVisible()) { - y_scale = static_cast(zoomed_height) / static_cast(available_height); - - // Update scrollbar sizes - int vert_height = this->height(); - - if (horiz_scrollbar_->isVisible()) { - vert_height -= horiz_scrollbar_->sizeHint().height(); - } - - vert_scrollbar_->resize(vert_scrollbar_->sizeHint().width(), vert_height); - vert_scrollbar_->move(this->width() - vert_scrollbar_->width() - 1, 0); - vert_scrollbar_->setMaximum(zoomed_height - available_height); - vert_scrollbar_->setPageStep(available_height); - - zoomed_height = available_height; - } - - // Rather than make a huge surface, we still crop at our width/height and then signal a matrix - child_matrix.scale(x_scale, y_scale, 1.0F); - - child_size = QSize(zoomed_width, zoomed_height); } - widget_->resize(child_size); - widget_->move(available_width / 2 - child_size.width() / 2, - available_height / 2 - child_size.height() / 2); + if (zoom_ > 0) { + + // Scale to get to the requested zoom + double zoom_diff = (zoom_ * 0.01) / current_scale; + child_matrix.scale(zoom_diff, zoom_diff, 1.0); + + } else { + + // Fit - add a small amount of padding + child_matrix.scale(0.95f, 0.95f); + + } emit RequestScale(child_matrix); @@ -255,4 +216,4 @@ void ViewerSizer::ScrollBarMoved() emit RequestTranslate(mat); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/viewer/viewersizer.h b/app/widget/viewer/viewersizer.h index 44601e6c6..8833e9735 100644 --- a/app/widget/viewer/viewersizer.h +++ b/app/widget/viewer/viewersizer.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "common/define.h" #include "common/rational.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief A container widget that enforces the aspect ratio of a child widget @@ -120,6 +120,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif // VIEWERSIZER_H diff --git a/app/widget/viewer/viewerwindow.cpp b/app/widget/viewer/viewerwindow.cpp index d9a331676..57484da23 100644 --- a/app/widget/viewer/viewerwindow.cpp +++ b/app/widget/viewer/viewerwindow.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,7 +25,7 @@ #include "common/timecodefunctions.h" -OLIVE_NAMESPACE_ENTER +namespace olive { ViewerWindow::ViewerWindow(QWidget *parent) : QWidget(parent, Qt::Window | Qt::WindowStaysOnTopHint), @@ -140,4 +140,4 @@ void ViewerWindow::UpdateMatrix() display_widget_->SetMatrixZoom(mat); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/widget/viewer/viewerwindow.h b/app/widget/viewer/viewerwindow.h index 289f0ea87..a2cbc76ce 100644 --- a/app/widget/viewer/viewerwindow.h +++ b/app/widget/viewer/viewerwindow.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "viewerplaybacktimer.h" #include "viewerqueue.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class ViewerWindow : public QWidget { @@ -89,6 +89,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // VIEWERWINDOW_H diff --git a/app/window/CMakeLists.txt b/app/window/CMakeLists.txt index 488b0686e..2ed541163 100644 --- a/app/window/CMakeLists.txt +++ b/app/window/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/window/mainwindow/CMakeLists.txt b/app/window/mainwindow/CMakeLists.txt index 4b70b8f9e..5b36cc883 100644 --- a/app/window/mainwindow/CMakeLists.txt +++ b/app/window/mainwindow/CMakeLists.txt @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/app/window/mainwindow/mainmenu.cpp b/app/window/mainwindow/mainmenu.cpp index b33a3e604..a5d8c1dc2 100644 --- a/app/window/mainwindow/mainmenu.cpp +++ b/app/window/mainwindow/mainmenu.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -36,7 +36,7 @@ #include "widget/menu/menushared.h" #include "mainwindow.h" -OLIVE_NAMESPACE_ENTER +namespace olive { MainMenu::MainMenu(MainWindow *parent) : QMenuBar(parent) @@ -50,8 +50,7 @@ MainMenu::MainMenu(MainWindow *parent) : file_new_menu_ = new Menu(file_menu_); MenuShared::instance()->AddItemsForNewMenu(file_new_menu_); file_open_item_ = file_menu_->AddItem("openproj", Core::instance(), &Core::OpenProject, "Ctrl+O"); - file_open_recent_menu_ = new Menu(file_menu_, this, &MainMenu::PopulateOpenRecent); - connect(file_open_recent_menu_, &Menu::aboutToHide, this, &MainMenu::CloseOpenRecentMenu); + file_open_recent_menu_ = new Menu(file_menu_); file_open_recent_separator_ = file_open_recent_menu_->addSeparator(); file_open_recent_clear_item_ = file_open_recent_menu_->AddItem("clearopenrecent", Core::instance(), &Core::ClearOpenRecentList); file_save_item_ = file_menu_->AddItem("saveproj", Core::instance(), &Core::SaveActiveProject, "Ctrl+S"); @@ -255,6 +254,9 @@ MainMenu::MainMenu(MainWindow *parent) : help_menu_->addSeparator(); help_about_item_ = help_menu_->AddItem("about", Core::instance(), &Core::DialogAboutShow); + connect(Core::instance(), &Core::OpenRecentListChanged, this, &MainMenu::RepopulateOpenRecent); + PopulateOpenRecent(); + Retranslate(); } @@ -280,7 +282,7 @@ void MainMenu::ToolItemTriggered() void MainMenu::FileMenuAboutToShow() { - Project* active_project = Core::instance()->GetActiveProject().get(); + Project* active_project = Core::instance()->GetActiveProject(); file_project_properties_item_->setEnabled(active_project); file_save_item_->setEnabled(active_project); @@ -398,6 +400,12 @@ void MainMenu::PopulateOpenRecent() } } +void MainMenu::RepopulateOpenRecent() +{ + CloseOpenRecentMenu(); + PopulateOpenRecent(); +} + void MainMenu::CloseOpenRecentMenu() { while (file_open_recent_menu_->actions().first() != file_open_recent_separator_) { @@ -657,7 +665,7 @@ void MainMenu::Retranslate() sequence_cache_in_to_out_item_->setText(tr("Cache Sequence In/Out")); // Window menu - window_menu_->setTitle("&Window"); + window_menu_->setTitle(tr("&Window")); window_maximize_panel_item_->setText(tr("Maximize Panel")); window_lock_layout_item_->setText(tr("Lock Panels")); window_reset_layout_item_->setText(tr("Reset to Default Layout")); @@ -684,4 +692,4 @@ void MainMenu::Retranslate() help_about_item_->setText(tr("&About...")); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/window/mainwindow/mainmenu.h b/app/window/mainwindow/mainmenu.h index 622303900..b2e7c0546 100644 --- a/app/window/mainwindow/mainmenu.h +++ b/app/window/mainwindow/mainmenu.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -27,7 +27,7 @@ #include "dialog/actionsearch/actionsearch.h" #include "widget/menu/menu.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class MainWindow; @@ -96,6 +96,8 @@ private slots: */ void PopulateOpenRecent(); + void RepopulateOpenRecent(); + /** * @brief Clears open recent items when menu closes */ @@ -270,6 +272,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // MAINMENU_H diff --git a/app/window/mainwindow/mainstatusbar.cpp b/app/window/mainwindow/mainstatusbar.cpp index fada2d6e7..c16cbce81 100644 --- a/app/window/mainwindow/mainstatusbar.cpp +++ b/app/window/mainwindow/mainstatusbar.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -22,7 +22,7 @@ #include -OLIVE_NAMESPACE_ENTER +namespace olive { MainStatusBar::MainStatusBar(QWidget *parent) : QStatusBar(parent), @@ -71,7 +71,7 @@ void MainStatusBar::UpdateStatus() if (manager_->GetTaskCount() == 1) { showMessage(t->GetTitle()); } else { - showMessage(tr("Running %1 background tasks").arg(manager_->GetTaskCount())); + showMessage(tr("Running %1 background task(s)").arg(manager_->GetTaskCount())); } bar_->setVisible(true); @@ -104,4 +104,4 @@ void MainStatusBar::mouseDoubleClickEvent(QMouseEvent* e) emit DoubleClicked(); } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/window/mainwindow/mainstatusbar.h b/app/window/mainwindow/mainstatusbar.h index a1bd8fb27..dad53115d 100644 --- a/app/window/mainwindow/mainstatusbar.h +++ b/app/window/mainwindow/mainstatusbar.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -26,7 +26,7 @@ #include "task/taskmanager.h" -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief Shows abbreviated information from a TaskManager object @@ -61,6 +61,6 @@ private: }; -OLIVE_NAMESPACE_EXIT +} #endif // MAINSTATUSBAR_H diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index a071b3c39..662e31d75 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -25,10 +25,14 @@ #include #include +#ifdef Q_OS_LINUX +#include +#endif + #include "mainmenu.h" #include "mainstatusbar.h" -OLIVE_NAMESPACE_ENTER +namespace olive { MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) @@ -270,9 +274,14 @@ void MainWindow::ToggleMaximizedPanel() // Find the currently focused panel PanelWidget* currently_hovered = PanelManager::instance()->CurrentlyHovered(); - // If no panel is hovered, do nothing - if (currently_hovered == nullptr) { - return; + // If no panel is hovered, fallback to the currently active panel + if (!currently_hovered) { + currently_hovered = PanelManager::instance()->CurrentlyFocused(); + + // If no panel is hovered or focused, do nothing + if (!currently_hovered) { + return; + } } // If this panel is not actually on the main window, this is a no-op @@ -470,7 +479,7 @@ void MainWindow::ProjectCloseRequested() ProjectPanel* panel = static_cast(sender()); Project* p = panel->project(); - Core::instance()->CloseProject(Core::instance()->GetSharedPtrFromProject(p), true); + Core::instance()->CloseProject(p, true); } void MainWindow::FloatingPanelCloseRequested() @@ -693,4 +702,4 @@ T *MainWindow::AppendFloatingPanelInternal(QList &list) return panel; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/window/mainwindow/mainwindow.h b/app/window/mainwindow/mainwindow.h index 6846c469e..3b543880b 100644 --- a/app/window/mainwindow/mainwindow.h +++ b/app/window/mainwindow/mainwindow.h @@ -1,7 +1,7 @@ /*** Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Copyright (C) 2020 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 @@ -44,12 +44,13 @@ #include #endif -OLIVE_NAMESPACE_ENTER +namespace olive { /** * @brief Olive's main window responsible for docking widgets and the main menu bar. */ -class MainWindow : public QMainWindow { +class MainWindow : public QMainWindow +{ Q_OBJECT public: MainWindow(QWidget *parent = nullptr); @@ -174,6 +175,6 @@ private slots: }; -OLIVE_NAMESPACE_EXIT +} #endif diff --git a/app/window/mainwindow/mainwindowlayoutinfo.cpp b/app/window/mainwindow/mainwindowlayoutinfo.cpp index 0b75a957f..3466f26ea 100644 --- a/app/window/mainwindow/mainwindowlayoutinfo.cpp +++ b/app/window/mainwindow/mainwindowlayoutinfo.cpp @@ -1,6 +1,6 @@ #include "mainwindowlayoutinfo.h" -OLIVE_NAMESPACE_ENTER +namespace olive { void MainWindowLayoutInfo::toXml(QXmlStreamWriter *writer) const { @@ -101,4 +101,4 @@ void MainWindowLayoutInfo::set_state(const QByteArray &layout) state_ = layout; } -OLIVE_NAMESPACE_EXIT +} diff --git a/app/window/mainwindow/mainwindowlayoutinfo.h b/app/window/mainwindow/mainwindowlayoutinfo.h index 59f357935..bb14ab66e 100644 --- a/app/window/mainwindow/mainwindowlayoutinfo.h +++ b/app/window/mainwindow/mainwindowlayoutinfo.h @@ -4,7 +4,7 @@ #include "project/item/folder/folder.h" #include "project/item/sequence/sequence.h" -OLIVE_NAMESPACE_ENTER +namespace olive { class MainWindowLayoutInfo { @@ -50,8 +50,8 @@ private: }; -OLIVE_NAMESPACE_EXIT +} -Q_DECLARE_METATYPE(OLIVE_NAMESPACE::MainWindowLayoutInfo) +Q_DECLARE_METATYPE(olive::MainWindowLayoutInfo) #endif // MAINWINDOWLAYOUTINFO_H diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 436930972..000000000 --- a/appveyor.yml +++ /dev/null @@ -1,22 +0,0 @@ -version: "{build}" -image: Visual Studio 2017 -environment: - TRAVIS_REPO_SLUG: olive-editor/olive - -# Hack to not build the "continuous" tag (https://github.com/appveyor/ci/issues/486) -# FIXME: Will unfortunately skip release tags -skip_tags: true - -install: -- cd C:\Tools\vcpkg -- git pull -- .\bootstrap-vcpkg.bat -- cd %APPVEYOR_BUILD_FOLDER% -build_script: -- cmd: .appveyor\build.bat -#artifacts: -#- path: Olive*.zip -# name: Olive Portable -#- path: Olive*.exe -# name: Olive Installer -cache: c:\tools\vcpkg\installed\ diff --git a/cmake/FindGoogleCrashpad.cmake b/cmake/FindGoogleCrashpad.cmake index 8feca7930..574e4e8b5 100644 --- a/cmake/FindGoogleCrashpad.cmake +++ b/cmake/FindGoogleCrashpad.cmake @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/cmake/FindOpenColorIO.cmake b/cmake/FindOpenColorIO.cmake index 26b8229a1..09f0f271d 100644 --- a/cmake/FindOpenColorIO.cmake +++ b/cmake/FindOpenColorIO.cmake @@ -1,5 +1,6 @@ # # Copyright 2019 Pixar +# Modifications: Copyright (C) 2020 Olive Team # # Licensed under the Apache License, Version 2.0 (the "Apache License") # with the following modification; you may not use this file except in @@ -22,44 +23,14 @@ # language governing permissions and limitations under the Apache License. # -if(UNIX) - find_path(OCIO_BASE_DIR - include/OpenColorIO/OpenColorABI.h - HINTS - "${OCIO_LOCATION}" - "$ENV{OCIO_LOCATION}" - "/opt/ocio" - ) - find_path(OCIO_LIBRARY_DIR - libOpenColorIO.so - HINTS - "${OCIO_LOCATION}" - "$ENV{OCIO_LOCATION}" - "${OCIO_BASE_DIR}" - PATH_SUFFIXES - lib/ - DOC - "OpenColorIO library path" - ) -elseif(WIN32) - find_path(OCIO_BASE_DIR - include/OpenColorIO/OpenColorABI.h - HINTS - "${OCIO_LOCATION}" - "$ENV{OCIO_LOCATION}" - ) - find_path(OCIO_LIBRARY_DIR - OpenColorIO.lib - HINTS - "${OCIO_LOCATION}" - "$ENV{OCIO_LOCATION}" - "${OCIO_BASE_DIR}" - PATH_SUFFIXES - lib/ - DOC - "OpenColorIO library path" - ) -endif() +find_path(OCIO_BASE_DIR + include/OpenColorIO/OpenColorABI.h + HINTS + "${OCIO_LOCATION}" + "$ENV{OCIO_LOCATION}" + DOC + "OCIO root folder" +) find_path(OCIO_INCLUDE_DIR OpenColorIO/OpenColorABI.h @@ -70,13 +41,17 @@ find_path(OCIO_INCLUDE_DIR PATH_SUFFIXES include/ DOC - "OpenColorIO headers path" + "OCIO headers path" ) list(APPEND OCIO_INCLUDE_DIRS ${OCIO_INCLUDE_DIR}) find_library(OCIO_LIBRARY - OpenColorIO + NAMES + libOpenColorIO.so.2.0 # libOpenColorIO.so.2.0 (Linux) + OpenColorIO.2.0 # libOpenColorIO.2.0.dylib (macOS) + OpenColorIO_2_0 # OpenColorIO_2_0.lib (Windows) + OpenColorIO # (fallback) HINTS "${OCIO_LOCATION}" "$ENV{OCIO_LOCATION}" @@ -84,7 +59,7 @@ find_library(OCIO_LIBRARY PATH_SUFFIXES lib/ DOC - "OCIO's ${OCIO_LIB} library path" + "OCIO library path" ) list(APPEND OCIO_LIBRARIES ${OCIO_LIBRARY}) @@ -97,8 +72,8 @@ if(OCIO_INCLUDE_DIRS AND EXISTS "${OCIO_INCLUDE_DIR}/OpenColorIO/OpenColorABI.h" string(REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" OCIO_VERSION ${fullVersion}) endif() -# handle the QUIETLY and REQUIRED arguments and set OCIO_FOUND to TRUE if -# all listed variables are TRUE +# handle the QUIETLY and REQUIRED arguments and set OpenColorIO_FOUND to TRUE +# if all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(OpenColorIO diff --git a/cmake/FindOpenTimelineIO.cmake b/cmake/FindOpenTimelineIO.cmake index ee4131e45..04335a293 100644 --- a/cmake/FindOpenTimelineIO.cmake +++ b/cmake/FindOpenTimelineIO.cmake @@ -1,5 +1,5 @@ # Olive - Non-Linear Video Editor -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 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 diff --git a/docker/ci-ocio/Dockerfile b/docker/ci-ocio/Dockerfile new file mode 100644 index 000000000..2bd88f9d3 --- /dev/null +++ b/docker/ci-ocio/Dockerfile @@ -0,0 +1,47 @@ +# Copyright (C) 2020 Olive Team +# SPDX-License-Identifier: GPL-3.0-or-later + +# Build image (default): +# docker build -t olivevideoeditor/ci-package-ocio:2021-2.0 -f ci-ocio/Dockerfile . + +ARG OLIVE_ORG=olivevideoeditor +ARG ASWF_PKG_ORG=aswftesting +ARG CI_COMMON_VERSION=2 +ARG VFXPLATFORM_VERSION=2021 +# Latest configs ~3 GB because of ACES 1.0.x. +# Upstream only copies nuke-default, therefore we also use the older configs. +ARG OCIO_CONFIGS_VERSION=1.0_r2 + +FROM ${OLIVE_ORG}/ci-common:${CI_COMMON_VERSION} as ci-ocio + +ARG OLIVE_ORG +ARG CI_COMMON_VERSION +ARG VFXPLATFORM_VERSION +ARG OCIO_CONFIGS_VERSION + +LABEL maintainer="olivevideoeditor@gmail.com" +LABEL com.vfxplatform.version=$VFXPLATFORM_VERSION +LABEL org.opencontainers.image.name="$OLIVE_ORG/ci-otio" +LABEL org.opencontainers.image.description="CentOS OpenColorIO Build Image" +LABEL org.opencontainers.image.url="http://olivevideoeditor.org" +LABEL org.opencontainers.image.source="https://github.com/olive-editor/olive" +LABEL org.opencontainers.image.vendor="Olive Team" +LABEL org.opencontainers.image.version="1.0" +LABEL org.opencontainers.image.licenses="GPL-3.0-or-later" + +ENV OLIVE_ORG=${OLIVE_ORG} \ + CI_COMMON_VERSION=${CI_COMMON_VERSION} \ + VFXPLATFORM_VERSION=${VFXPLATFORM_VERSION} \ + OCIO_CONFIGS_VERSION=${OCIO_CONFIGS_VERSION} \ + OLIVE_INSTALL_PREFIX=/usr/local + +COPY scripts/build_ocio.sh \ + /tmp/ + +RUN /tmp/before_build.sh && \ + /tmp/build_ocio.sh && \ + /tmp/copy_new_files.sh + +FROM scratch as ci-package-ocio + +COPY --from=ci-ocio /package/. / diff --git a/docker/ci-olive/Dockerfile b/docker/ci-olive/Dockerfile index 09a2703d6..4a2f033a0 100644 --- a/docker/ci-olive/Dockerfile +++ b/docker/ci-olive/Dockerfile @@ -8,6 +8,7 @@ ARG OLIVE_ORG=olivevideoeditor ARG ASWF_PKG_ORG=aswftesting ARG CI_COMMON_VERSION=2 ARG VFXPLATFORM_VERSION=2021 +ARG OCIO_VERSION=2.0 ARG FFMPEG_VERSION=4.2.4 FROM ${ASWF_PKG_ORG}/ci-package-qt:${VFXPLATFORM_VERSION} as ci-package-qt @@ -15,7 +16,7 @@ FROM ${ASWF_PKG_ORG}/ci-package-python:${VFXPLATFORM_VERSION} as ci-package-pyth FROM ${ASWF_PKG_ORG}/ci-package-boost:${VFXPLATFORM_VERSION} as ci-package-boost FROM ${ASWF_PKG_ORG}/ci-package-openexr:${VFXPLATFORM_VERSION} as ci-package-openexr FROM ${ASWF_PKG_ORG}/ci-package-oiio:${VFXPLATFORM_VERSION} as ci-package-oiio -FROM ${ASWF_PKG_ORG}/ci-package-ocio:${VFXPLATFORM_VERSION} as ci-package-ocio +FROM ${OLIVE_ORG}/ci-package-ocio:${VFXPLATFORM_VERSION}-${OCIO_VERSION} as ci-package-ocio FROM ${OLIVE_ORG}/ci-package-ffmpeg:${FFMPEG_VERSION} as ci-package-ffmpeg FROM ${OLIVE_ORG}/ci-package-crashpad:latest as ci-package-crashpad FROM ${OLIVE_ORG}/ci-package-otio:latest as ci-package-otio diff --git a/docker/scripts/build_ocio.sh b/docker/scripts/build_ocio.sh new file mode 100644 index 000000000..6f8aaaf6f --- /dev/null +++ b/docker/scripts/build_ocio.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Copyright (C) 2020 Olive Team +# SPDX-License-Identifier: GPL-3.0-or-later + +set -ex + +mkdir ocio +cd ocio + +git clone --depth 1 https://github.com/AcademySoftwareFoundation/OpenColorIO.git +cd OpenColorIO + +mkdir build +cd build +cmake \ + -DCMAKE_INSTALL_PREFIX="${OLIVE_INSTALL_PREFIX}" \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DOCIO_BUILD_APPS=OFF \ + -DOCIO_BUILD_NUKE=OFF \ + -DOCIO_BUILD_DOCS=OFF \ + -DOCIO_BUILD_TESTS=OFF \ + -DOCIO_BUILD_GPU_TESTS=OFF \ + -DOCIO_USE_HEADLESS=OFF \ + -DOCIO_BUILD_PYTHON=OFF \ + -DOCIO_BUILD_JAVA=OFF \ + -DOCIO_WARNING_AS_ERROR=OFF \ + -DOCIO_INSTALL_EXT_PACKAGES=ALL \ + .. +make -j$(nproc) +make install + +cd ../.. + +curl --location "https://github.com/imageworks/OpenColorIO-Configs/archive/v${OCIO_CONFIGS_VERSION}.tar.gz" -o "ocio-configs.tar.gz" +tar -zxf ocio-configs.tar.gz +cd "OpenColorIO-Configs-${OCIO_CONFIGS_VERSION}" + +mkdir "${OLIVE_INSTALL_PREFIX}/openColorIO" +cp nuke-default/config.ocio "${OLIVE_INSTALL_PREFIX}/openColorIO/" +cp -r nuke-default/luts "${OLIVE_INSTALL_PREFIX}/openColorIO/" + +cd ../.. +rm -rf ocio diff --git a/docker/scripts/common/install_yumpackages.sh b/docker/scripts/common/install_yumpackages.sh index 064c5e1f1..c0dfe6e62 100644 --- a/docker/scripts/common/install_yumpackages.sh +++ b/docker/scripts/common/install_yumpackages.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Copyright (C) 2019 Olive Team +# Copyright (C) 2020 Olive Team # Copyright (c) Contributors to the aswf-docker Project. All rights reserved. # SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later