diff --git a/.gitignore b/.gitignore index c02a2fb9c..58848653c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ .project .cproject /.metadata/ +tags *~ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f998c3d45..1835040c6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,13 +16,11 @@ linux-builder: - unzip artifacts.zip - export LIBOPENSHOT_AUDIO_DIR=$CI_PROJECT_DIR/build/install-x64 - mkdir -p build; cd build; - - mkdir -p install-x64/python; - - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -D"CMAKE_BUILD_TYPE:STRING=Release" -D"USE_SYSTEM_JSONCPP=0" ../ + - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -D"PYTHON_MODULE_PATH=python" -D"RUBY_MODULE_PATH=ruby" -DCMAKE_BUILD_TYPE:STRING=Release -DUSE_SYSTEM_JSONCPP=0 ../ - make - make install - make doc - ~/auto-update-docs "$CI_PROJECT_DIR/build" "$CI_COMMIT_REF_NAME" - - mv install-x64/lib/python3.4/site-packages/*openshot* install-x64/python - echo -e "CI_PROJECT_NAME:$CI_PROJECT_NAME\nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME\nCI_COMMIT_SHA:$CI_COMMIT_SHA\nCI_JOB_ID:$CI_JOB_ID" > "install-x64/share/$CI_PROJECT_NAME" - git log $(git describe --tags --abbrev=0 @^)..@ --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log" when: always @@ -45,11 +43,9 @@ mac-builder: - unzip artifacts.zip - export LIBOPENSHOT_AUDIO_DIR=$CI_PROJECT_DIR/build/install-x64 - mkdir -p build; cd build; - - mkdir -p install-x64/python; - - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -DCMAKE_CXX_COMPILER=/usr/local/opt/gcc48/bin/g++-4.8 -DCMAKE_C_COMPILER=/usr/local/opt/gcc48/bin/gcc-4.8 -DCMAKE_PREFIX_PATH=/usr/local/qt5/5.5/clang_64 -DPYTHON_INCLUDE_DIR=/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m -DPYTHON_LIBRARY=/Library/Frameworks/Python.framework/Versions/3.6/lib/libpython3.6.dylib -DPython_FRAMEWORKS=/Library/Frameworks/Python.framework/ -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk" -D"CMAKE_OSX_DEPLOYMENT_TARGET=10.9" -D"CMAKE_INSTALL_RPATH_USE_LINK_PATH=1" -D"ENABLE_RUBY=0" ../ + - cmake -DCMAKE_CXX_FLAGS=-I\ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -DCMAKE_CXX_COMPILER=/usr/local/opt/gcc@8/bin/g++-8 -DCMAKE_C_COMPILER=/usr/local/opt/gcc@8/bin/gcc-8 -DCMAKE_PREFIX_PATH=/usr/local/qt5/5.5/clang_64 -DPYTHON_INCLUDE_DIR=/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m -DPYTHON_LIBRARY=/Library/Frameworks/Python.framework/Versions/3.6/lib/libpython3.6.dylib -DPYTHON_MODULE_PATH=python -DPython_FRAMEWORKS=/Library/Frameworks/Python.framework/ -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk" -D"CMAKE_OSX_DEPLOYMENT_TARGET=10.9" -D"CMAKE_INSTALL_RPATH_USE_LINK_PATH=1" -D"ENABLE_RUBY=0" ../ - make - make install - - mv install-x64/lib/python3.6/site-packages/*openshot* install-x64/python - echo -e "CI_PROJECT_NAME:$CI_PROJECT_NAME\nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME\nCI_COMMIT_SHA:$CI_COMMIT_SHA\nCI_JOB_ID:$CI_JOB_ID" > "install-x64/share/$CI_PROJECT_NAME" - git log $(git describe --tags --abbrev=0 @^)..@ --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log" when: always @@ -73,11 +69,9 @@ windows-builder-x64: - $env:RESVGDIR = "C:\msys64\usr" - $env:Path = "C:\msys64\mingw64\bin;C:\msys64\mingw64\lib;C:\msys64\usr\lib\cmake\UnitTest++;C:\msys64\home\jonathan\depot_tools;C:\msys64\usr;C:\msys64\usr\lib;" + $env:Path; - New-Item -ItemType Directory -Force -Path build - - New-Item -ItemType Directory -Force -Path build\install-x64\python - cd build - - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR\build\install-x64" -G "MSYS Makefiles" -DCMAKE_MAKE_PROGRAM=mingw32-make -D"CMAKE_BUILD_TYPE:STRING=Release" ../ + - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR\build\install-x64" -D"PYTHON_MODULE_PATH=python" -D"RUBY_MODULE_PATH=ruby" -G "MSYS Makefiles" -DCMAKE_MAKE_PROGRAM=mingw32-make -D"CMAKE_BUILD_TYPE:STRING=Release" ../ - mingw32-make install - - Move-Item -Force -path "install-x64\lib\python3.7\site-packages\*openshot*" -destination "install-x64\python\" - New-Item -path "install-x64/share/" -Name "$CI_PROJECT_NAME" -Value "CI_PROJECT_NAME:$CI_PROJECT_NAME`nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME`nCI_COMMIT_SHA:$CI_COMMIT_SHA`nCI_JOB_ID:$CI_JOB_ID" -ItemType file -force - $PREV_GIT_LABEL=(git describe --tags --abbrev=0 '@^') - git log "$PREV_GIT_LABEL..@" --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log" @@ -102,11 +96,9 @@ windows-builder-x86: - $env:RESVGDIR = "C:\msys32\usr" - $env:Path = "C:\msys32\mingw32\bin;C:\msys32\mingw32\lib;C:\msys32\usr\lib\cmake\UnitTest++;C:\msys32\home\jonathan\depot_tools;C:\msys32\usr;C:\msys32\usr\lib;" + $env:Path; - New-Item -ItemType Directory -Force -Path build - - New-Item -ItemType Directory -Force -Path build\install-x86\python - cd build - - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR\build\install-x86" -G "MSYS Makefiles" -DCMAKE_MAKE_PROGRAM=mingw32-make -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_CXX_FLAGS=-m32" -D"CMAKE_EXE_LINKER_FLAGS=-Wl,--large-address-aware" -D"CMAKE_C_FLAGS=-m32" ../ + - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR\build\install-x86" -D"PYTHON_MODULE_PATH=python" -D"RUBY_MODULE_PATH=ruby" -G "MSYS Makefiles" -DCMAKE_MAKE_PROGRAM=mingw32-make -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_CXX_FLAGS=-m32" -D"CMAKE_EXE_LINKER_FLAGS=-Wl,--large-address-aware" -D"CMAKE_C_FLAGS=-m32" ../ - mingw32-make install - - Move-Item -Force -path "install-x86\lib\python3.7\site-packages\*openshot*" -destination "install-x86\python\" - New-Item -path "install-x86/share/" -Name "$CI_PROJECT_NAME" -Value "CI_PROJECT_NAME:$CI_PROJECT_NAME`nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME`nCI_COMMIT_SHA:$CI_COMMIT_SHA`nCI_JOB_ID:$CI_JOB_ID" -ItemType file -force - $PREV_GIT_LABEL=(git describe --tags --abbrev=0 '@^') - git log "$PREV_GIT_LABEL..@" --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x86/share/$CI_PROJECT_NAME.log" diff --git a/.travis.yml b/.travis.yml index e2c3d5f15..241d5be3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: cpp compiler: gcc +os: linux +dist: xenial # This section uses a rather esoteric (and tricky!) feature of YAML, # &aliases and *anchors, to build package lists out of sublists without @@ -9,18 +11,12 @@ addons: apt: packages: &p_common # Packages common to all Ubuntu builds - cmake - - swig - libopenshot-audio-dev - libmagick++-dev - libunittest++-dev - libzmq3-dev - qtbase5-dev - qtmultimedia5-dev - - doxygen - - graphviz - - curl - packages: &ff_common # Common set of FFmpeg packages - - *p_common - libfdk-aac-dev - libavcodec-dev - libavformat-dev @@ -29,12 +25,19 @@ addons: - libavfilter-dev - libswscale-dev - libpostproc-dev - - libavresample-dev - libswresample-dev + - swig + - doxygen + - graphviz + - curl -matrix: - include: +jobs: + + # The FFmpeg 3.2 backport PPA has gone missing + allow_failures: + - name: "FFmpeg 3.2 GCC (Ubuntu 16.04 Xenial)" + include: - name: "Coverage + FFmpeg 3.4 GCC (Ubuntu 18.04 Bionic)" env: - BUILD_VERSION=coverage_ffmpeg34 @@ -46,29 +49,27 @@ matrix: apt: sources: - sourceline: 'ppa:openshot.developers/libopenshot-daily' - - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic' packages: - - *ff_common + - *p_common - qt5-default + - libavresample-dev - libjsoncpp-dev - lcov - binutils-common # For c++filt - - name: "FFmpeg 4 GCC (Ubuntu 18.04 Bionic)" + - name: "FFmpeg 4 GCC (Ubuntu 20.04 Focal)" env: - BUILD_VERSION=ffmpeg4 - CMAKE_EXTRA_ARGS="" - TEST_TARGET=test os: linux - dist: bionic + dist: focal addons: apt: sources: - sourceline: 'ppa:openshot.developers/libopenshot-daily' - - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic' - - sourceline: 'ppa:jonathonf/ffmpeg-4' packages: - - *ff_common + - *p_common - qt5-default - libjsoncpp-dev - libavcodec58 @@ -78,7 +79,6 @@ matrix: - libavfilter7 - libswscale5 - libpostproc55 - - libavresample4 - libswresample3 - name: "FFmpeg 3.4 Clang (Ubuntu 18.04 Bionic)" @@ -93,10 +93,10 @@ matrix: apt: sources: - sourceline: 'ppa:openshot.developers/libopenshot-daily' - - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic' packages: - - *ff_common + - *p_common - qt5-default + - libavresample-dev - libomp-dev - name: "FFmpeg 3.2 GCC (Ubuntu 16.04 Xenial)" @@ -110,10 +110,10 @@ matrix: apt: sources: - sourceline: 'ppa:openshot.developers/libopenshot-daily' - - sourceline: 'ppa:beineri/opt-qt-5.10.0-xenial' - sourceline: 'ppa:jon-hedgerows/ffmpeg-backports' packages: - - *ff_common + - *p_common + - libavresample-dev - libavcodec57 - libavdevice57 - libavfilter6 @@ -137,14 +137,15 @@ matrix: - sourceline: 'ppa:openshot.developers/libopenshot-daily' - sourceline: 'ppa:beineri/opt-qt-5.10.0-xenial' packages: - - *ff_common + - *p_common + - libavresample-dev script: - mkdir -p build; cd build; - - cmake -DCMAKE_BUILD_TYPE:STRING="Debug" ${CMAKE_EXTRA_ARGS} ../ + - cmake -DCMAKE_INSTALL_PREFIX:PATH="$TRAVIS_OS_NAME-x64" -DCMAKE_BUILD_TYPE:STRING="Debug" ${CMAKE_EXTRA_ARGS} ../ - make VERBOSE=1 - make ${TEST_TARGET} - - make install DESTDIR="$BUILD_VERSION" + - make install - cd .. after_success: diff --git a/CMakeLists.txt b/CMakeLists.txt index a0e8a5feb..bb3fe8cc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,10 +113,6 @@ IF (WIN32) SET_PROPERTY(GLOBAL PROPERTY WIN32 "WIN32") ENDIF(WIN32) -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/include - ${CMAKE_CURRENT_BINARY_DIR}/include) - ############## Code Coverage ######################### if (DISABLE_TESTS AND ENABLE_COVERAGE) message(WARNING "ENABLE_COVERAGE requires tests, overriding DISABLE_TESTS") @@ -133,6 +129,16 @@ if (ENABLE_COVERAGE) endif() add_feature_info("Coverage" ENABLE_COVERAGE "analyze test coverage and generate report") +# Juce requires either DEBUG or NDEBUG to be defined on MacOS. +# -DNDEBUG is set by cmake for all release configs, so add +# -DDEBUG for debug builds. We'll do this for all OSes, even +# though only MacOS requires it. +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") +# Make sure we've picked some build type, default to debug +if(NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "") + set(CMAKE_BUILD_TYPE "Debug") +endif() + ############## PROCESS src/ DIRECTORIES ############## add_subdirectory(src) diff --git a/INSTALL.md b/INSTALL.md index 474fb9c29..f2d0dda77 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -2,91 +2,69 @@ Operating system specific install instructions are located in: -* doc/INSTALL-LINUX.md -* doc/INSTALL-MAC.md -* doc/INSTALL-WINDOWS.md +* [doc/INSTALL-LINUX.md][INSTALL-LINUX] +* [doc/INSTALL-MAC.md][INSTALL-MAC] +* [doc/INSTALL-WINDOWS.md][INSTALL-WINDOWS] ## Getting Started -The best way to get started with libopenshot, is to learn about our build system, obtain all the source code, -install a development IDE and tools, and better understand our dependencies. So, please read through the -following sections, and follow the instructions. And keep in mind, that your computer is likely different -than the one used when writing these instructions. Your file paths and versions of applications might be +The best way to get started with libopenshot, is to learn about our build system, obtain all the source code, +install a development IDE and tools, and better understand our dependencies. So, please read through the +following sections, and follow the instructions. And keep in mind, that your computer is likely different +than the one used when writing these instructions. Your file paths and versions of applications might be slightly different, so keep an eye out for subtle file path differences in the commands you type. -## Build Tools - -CMake is the backbone of our build system. It is a cross-platform build system, which checks for dependencies, -locates header files and libraries, generates makefiles, and supports the cross-platform compiling of -libopenshot and libopenshot-audio. CMake uses an out-of-source build concept, where all temporary build -files, such as makefiles, object files, and even the final binaries, are created outside of the source -code folder, inside a /build/ sub-folder. This prevents the build process from cluttering up the source -code. These instructions have only been tested with the GNU compiler (including MSYS2/MinGW for Windows). - ## Dependencies -The following libraries are required to build libopenshot. Instructions on how to install these -dependencies vary for each operating system. Libraries and Executables have been labeled in the -list below to help distinguish between them. +The following libraries are required to build libopenshot. +Instructions on how to install these dependencies vary for each operating system. +Libraries and Executables have been labeled in the list below to help distinguish between them. + +#### FFmpeg (libavformat, libavcodec, libavutil, libavdevice, libavresample, libswscale) -* ### FFmpeg (libavformat, libavcodec, libavutil, libavdevice, libavresample, libswscale) - * http://www.ffmpeg.org/ `(Library)` + * http://www.ffmpeg.org/ **(Library)** * This library is used to decode and encode video, audio, and image files. It is also used to obtain information about media files, such as frame rate, sample rate, aspect ratio, and other common attributes. -* ### ImageMagick++ (libMagick++, libMagickWand, libMagickCore) - * http://www.imagemagick.org/script/magick++.php `(Library)` +#### ImageMagick++ (libMagick++, libMagickWand, libMagickCore) + * http://www.imagemagick.org/script/magick++.php **(Library)** * This library is **optional**, and used to decode and encode images. -* ### OpenShot Audio Library (libopenshot-audio) - * https://github.com/OpenShot/libopenshot-audio/ `(Library)` +#### OpenShot Audio Library (libopenshot-audio) + * https://github.com/OpenShot/libopenshot-audio/ **(Library)** * This library is used to mix, resample, host plug-ins, and play audio. It is based on the JUCE project, which is an outstanding audio library used by many different applications -* ### Qt 5 (libqt5) - * http://www.qt.io/qt5/ `(Library)` +#### Qt 5 (libqt5) + * http://www.qt.io/qt5/ **(Library)** * Qt5 is used to display video, store image data, composite images, apply image effects, and many other utility functions, such as file system manipulation, high resolution timers, etc... -* ### CMake (cmake) - * http://www.cmake.org/ `(Executable)` +#### ZeroMQ (libzmq) + * http://zeromq.org/ **(Library)** + * This library is used to communicate between libopenshot and other applications (publisher / subscriber). Primarily used to send debug data from libopenshot. + +#### OpenMP (`-fopenmp`) + * http://openmp.org/wp/ **(Compiler Flag)** + * If your compiler supports this flag (GCC, Clang, and most other compilers), it provides libopenshot with easy methods of using parallel programming techniques to improve performance and take advantage of multi-core processors. + +#### CMake (`cmake`) + * http://www.cmake.org/ **(Executable)** * This executable is used to automate the generation of Makefiles, check for dependencies, and is the backbone of libopenshot’s cross-platform build process. -* ### SWIG (swig) - * http://www.swig.org/ `(Executable)` +#### SWIG (`swig`) + * http://www.swig.org/ **(Executable)** * This executable is used to generate the Python and Ruby bindings for libopenshot. It is a simple and powerful wrapper for C++ libraries, and supports many languages. -* ### Python 3 (libpython) - * http://www.python.org/ `(Executable and Library)` +#### Python 3 (libpython) + * http://www.python.org/ **(Executable and Library)** * This library is used by swig to create the Python (version 3+) bindings for libopenshot. This is also the official language used by OpenShot Video Editor (a graphical interface to libopenshot). -* ### Doxygen (doxygen) - * http://www.stack.nl/~dimitri/doxygen/ `(Executable)` +#### Doxygen (doxygen) + * http://www.stack.nl/~dimitri/doxygen/ **(Executable)** * This executable is used to auto-generate the documentation used by libopenshot. -* ### UnitTest++ (libunittest++) - * https://github.com/unittest-cpp/ `(Library)` +#### UnitTest++ (libunittest++) + * https://github.com/unittest-cpp/ **(Library)** * This library is used to execute unit tests for libopenshot. It contains many macros used to keep our unit testing code very clean and simple. -* ### ZeroMQ (libzmq) - * http://zeromq.org/ `(Library)` - * This library is used to communicate between libopenshot and other applications (publisher / subscriber). Primarily used to send debug data from libopenshot. - -* ### OpenMP (-fopenmp) - * http://openmp.org/wp/ `(Compiler Flag)` - * If your compiler supports this flag (GCC, Clang, and most other compilers), it provides libopenshot with easy methods of using parallel programming techniques to improve performance and take advantage of multi-core processors. - -## CMake Flags (Optional) -There are many different build flags that can be passed to cmake to adjust how libopenshot is compiled. Some of these flags might be required when compiling on certain OSes, just depending on how your build environment is setup. To add a build flag, follow this general syntax: $ cmake -DMAGICKCORE_HDRI_ENABLE=1 -DENABLE_TESTS=1 ../ - -* MAGICKCORE_HDRI_ENABLE (default 0) -* MAGICKCORE_QUANTUM_DEPTH (default 0) -* OPENSHOT_IMAGEMAGICK_COMPATIBILITY (default 0) -* DISABLE_TESTS (default 0) -* CMAKE_PREFIX_PATH (`/location/to/missing/library/`) -* PYTHON_INCLUDE_DIR (`/location/to/python/include/`) -* PYTHON_LIBRARY (`/location/to/python/lib.a`) -* PYTHON_FRAMEWORKS (`/usr/local/Cellar/python3/3.3.2/Frameworks/Python.framework/`) -* CMAKE_CXX_COMPILER (`/location/to/mingw/g++`) -* CMAKE_C_COMPILER (`/location/to/mingw/gcc`) - ## Obtaining Source Code The first step in installing libopenshot is to obtain the most recent source code. The source code is available on [GitHub](https://github.com/OpenShot/libopenshot). Use the following command to obtain the latest libopenshot source code. @@ -96,30 +74,87 @@ git clone https://github.com/OpenShot/libopenshot.git git clone https://github.com/OpenShot/libopenshot-audio.git ``` -## Folder Structure (libopenshot) +### Folder Structure (libopenshot) The source code is divided up into the following folders. -* ### build/ - * This folder needs to be manually created, and is used by cmake to store the temporary build files, such as makefiles, as well as the final binaries (library and test executables). +#### `build/` +This folder needs to be manually created, and is used by cmake to store the temporary build files, such as makefiles, as well as the final binaries (library and test executables). + +#### `cmake/` +This folder contains custom modules not included by default in cmake. +CMake find modules are used to discover dependency libraries on the system, and to incorporate their headers and object files. +CMake code modules are used to implement build features such as test coverage scanning. -* ### cmake/ - * This folder contains custom modules not included by default in cmake, used to find dependency libraries and headers and determine if these libraries are installed. +#### `doc/` +This folder contains documentation and related files. +This includes logos and images required by the doxygen-generated API documentation. -* ### doc/ - * This folder contains documentation and related files, such as logos and images required by the doxygen auto-generated documentation. +#### `include/` +This folder contains all headers (*.h) used by libopenshot. -* ### include/ - * This folder contains all headers (*.h) used by libopenshot. +#### `src/` +This folder contains all source code (*.cpp) used by libopenshot. -* ### src/ - * This folder contains all source code (*.cpp) used by libopenshot. +#### `tests/` +This folder contains all unit test code. +Each test file (`_Tests.cpp`) contains the tests for the named class. +We use UnitTest++ macros to keep the test code simple and manageable. -* ### tests/ - * This folder contains all unit test code. Each class has it’s own test file (*.cpp), and uses UnitTest++ macros to keep the test code simple and manageable. +#### `thirdparty/` +This folder contains code not written by the OpenShot team. +For example, `jsoncpp`, an open-source JSON parser. -* ### thirdparty/ - * This folder contains code not written by the OpenShot team. For example, jsoncpp, an open-source JSON parser. +## Build Tools + +CMake is the backbone of our build system. +It is a cross-platform build system, which checks for dependencies, +locates header files and libraries, and generates a build system in various formats. +We use CMake's Makefile generators to compile libopenshot and libopenshot-audio. + +CMake uses an out-of-source build concept. +This means that the build system, all temporary files, and all generated products are kept separate from the source code. +This includes Makefiles, object files, and even the final binaries. +While it is possible to build in-tree, we highly recommend you use a `/build/` sub-folder to compile each library. +This prevents the build process from cluttering up the source +code. +These instructions have only been tested with the GNU compiler suite (including MSYS2/MinGW for Windows), and the Clang compiler (including AppleClang on MacOS). + +## CMake Flags (Optional) +There are many different build flags that can be passed to cmake to adjust how libopenshot is compiled. Some of these flags might be required when compiling on certain OSes, just depending on how your build environment is setup. + +To add a build flag, follow this general syntax: + +```sh +$ cmake -DMAGICKCORE_HDRI_ENABLE=1 -DENABLE_TESTS=1 .. +``` + +Following are some of the flags you might need to set when generating your build system. + +##### Optional behavior: +* `-DENABLE_TESTS=0` (default: `ON`) +* `-DENABLE_COVERAGE=1` (default: `OFF`) +* `-DENABLE_DOCS=0` (default: `ON` if doxygen found) + +##### Compiler configuration: +* `-DCMAKE_BUILD_TYPE=Release`, `-DCMAKE_BUILD_TYPE=Debug` (default: `Debug` if unset) +* `-DCMAKE_CXX_FLAGS="-Wall -Wextra"` (default: CMake builtin defaults for build type) +* `-DCMAKE_CXX_COMPILER=/path/to/g++`, `-DCMAKE_CXX_COMPILER=/path/to/clang++` +* `-DCMAKE_C_COMPILER=/path/to/gcc`, `-DCMAKE_CXX_COMPILER=/path/to/clang` (used by CMake for OS probes) + +##### Dependency configuration: +* `-DCMAKE_PREFIX_PATH=/extra/path/to/search/for/libraries/` +* `-DUSE_SYSTEM_JSONCPP=0` (default: auto if discovered) +* `-DImageMagick_FOUND=0` (default: auto if discovered) + +##### To compile bindings for a specific Python installation: +* `-DPYTHON_INCLUDE_DIR=/location/of/python/includes/` +* `-DPYTHON_LIBRARY=/location/of/libpython*.so` +* `-DPYTHON_FRAMEWORKS=/usr/local/Cellar/python3/3.3.2/Frameworks/Python.framework/` (MacOS only) + +##### Only used when building with ImageMagick enabled: +* `-DMAGICKCORE_HDRI_ENABLE=1` (default `0`) +* `-DMAGICKCORE_QUANTUM_DEPTH=8` (default `16`) ## Linux Build Instructions (libopenshot-audio) To compile libopenshot-audio, we need to go through a few additional steps to manually build and install it. Launch a terminal and enter: @@ -148,6 +183,10 @@ make install For more detailed instructions, please see: -* doc/INSTALL-LINUX.md -* doc/INSTALL-MAC.md -* doc/INSTALL-WINDOWS.md +* [doc/INSTALL-LINUX.md][INSTALL-LINUX] +* [doc/INSTALL-MAC.md][INSTALL-MAC] +* [doc/INSTALL-WINDOWS.md][INSTALL-WINDOWS] + +[INSTALL-LINUX]: https://github.com/OpenShot/libopenshot/blob/develop/doc/INSTALL-LINUX.md +[INSTALL-MAC]: https://github.com/OpenShot/libopenshot/blob/develop/doc/INSTALL-MAC.md +[INSTALL-WINDOWS]: https://github.com/OpenShot/libopenshot/blob/develop/doc/INSTALL-WINDOWS.md diff --git a/cmake/Modules/FindJsonCpp.cmake b/cmake/Modules/FindJsonCpp.cmake deleted file mode 100644 index 6ce9887ec..000000000 --- a/cmake/Modules/FindJsonCpp.cmake +++ /dev/null @@ -1,64 +0,0 @@ -# - Try to find JsonCpp -# -# Once done this will define -# JSONCPP_INCLUDE_DIRS, where to find header, etc. -# JSONCPP_LIBRARIES, the libraries needed to use jsoncpp. -# JSONCPP_FOUND, If false, do not try to use jsoncpp. -# JSONCPP_INCLUDE_PREFIX, include prefix for jsoncpp - -# try to detect using pkg-config, and use as hints later -find_package(PkgConfig) -pkg_check_modules(PC_jsoncpp QUIET jsoncpp) - -find_path( - JSONCPP_INCLUDE_DIR - NAMES json/json.h - HINTS ${PC_jsoncpp_INCLUDE_DIRS} - DOC "jsoncpp include dir" -) - -find_library( - JSONCPP_LIBRARY - NAMES jsoncpp - HINTS ${PC_jsoncpp_LIBRARY_DIR} - DOC "jsoncpp library" -) - -set(JSONCPP_INCLUDE_DIRS ${JSONCPP_INCLUDE_DIR}) -set(JSONCPP_LIBRARIES ${JSONCPP_LIBRARY}) - -# debug library on windows -# same naming convention as in qt (appending debug library with d) -# boost is using the same "hack" as us with "optimized" and "debug" -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - find_library( - JSONCPP_LIBRARY_DEBUG - NAMES jsoncppd - HINTS ${PC_jsoncpp_LIBDIR} ${PC_jsoncpp_LIBRARY_DIRS} - DOC "jsoncpp debug library" - ) - - set(JSONCPP_LIBRARIES optimized ${JSONCPP_LIBRARIES} debug ${JSONCPP_LIBRARY_DEBUG}) - -endif() - -# find JSONCPP_INCLUDE_PREFIX -find_path( - JSONCPP_INCLUDE_PREFIX - NAMES json.h - PATH_SUFFIXES jsoncpp/json json -) - -if (${JSONCPP_INCLUDE_PREFIX} MATCHES "jsoncpp") - set(JSONCPP_INCLUDE_PREFIX "jsoncpp/json") -else() - set(JSONCPP_INCLUDE_PREFIX "json") -endif() - -# handle the QUIETLY and REQUIRED arguments and set JSONCPP_FOUND to TRUE -# if all listed variables are TRUE, hide their existence from configuration view -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(jsoncpp DEFAULT_MSG - JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY) -mark_as_advanced (JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY) - diff --git a/cmake/Modules/FindZeroMQ.cmake b/cmake/Modules/FindZeroMQ.cmake index 6c3669199..1f1dc083e 100644 --- a/cmake/Modules/FindZeroMQ.cmake +++ b/cmake/Modules/FindZeroMQ.cmake @@ -5,14 +5,16 @@ pkg_check_modules(PC_LIBZMQ QUIET libzmq) set(ZeroMQ_VERSION ${PC_LIBZMQ_VERSION}) find_path(ZeroMQ_INCLUDE_DIR zmq.h - PATHS ${ZeroMQ_DIR}/include - ${PC_LIBZMQ_INCLUDE_DIRS}) + PATHS + ${ZeroMQ_DIR}/include + ${PC_LIBZMQ_INCLUDE_DIRS}) find_library(ZeroMQ_LIBRARY - NAMES zmq - PATHS ${ZeroMQ_DIR}/lib - ${PC_LIBZMQ_LIBDIR} - ${PC_LIBZMQ_LIBRARY_DIRS}) + NAMES zmq + PATHS + ${ZeroMQ_DIR}/lib + ${PC_LIBZMQ_LIBDIR} + ${PC_LIBZMQ_LIBRARY_DIRS}) if(ZeroMQ_LIBRARY) set(ZeroMQ_FOUND ON) @@ -31,4 +33,9 @@ endif() include ( FindPackageHandleStandardArgs ) # handle the QUIETLY and REQUIRED arguments and set ZMQ_FOUND to TRUE # if all listed variables are TRUE -find_package_handle_standard_args ( ZeroMQ DEFAULT_MSG ZeroMQ_LIBRARIES ZeroMQ_INCLUDE_DIRS ) +find_package_handle_standard_args(ZeroMQ + REQUIRED_VARS + ZeroMQ_LIBRARIES + ZeroMQ_INCLUDE_DIRS + VERSION_VAR + ZeroMQ_VERSION) diff --git a/cmake/Modules/Findjsoncpp.cmake b/cmake/Modules/Findjsoncpp.cmake new file mode 100644 index 000000000..75f7db4a4 --- /dev/null +++ b/cmake/Modules/Findjsoncpp.cmake @@ -0,0 +1,133 @@ +# - Try to find jsoncpp +# +# IMPORTED target +# This module will create the target jsoncpp_lib if jsoncpp is found +# +# Legacy Config Variables +# The following variables are defined for backwards compatibility: +# +# JSONCPP_INCLUDE_DIRS, where to find header, etc. +# JSONCPP_LIBRARIES, the libraries needed to use jsoncpp. +# JSONCPP_FOUND, If false, do not try to use jsoncpp. +# JSONCPP_INCLUDE_PREFIX, include prefix for jsoncpp + +# try to detect using pkg-config, and use as hints later +find_package(PkgConfig) +pkg_check_modules(PC_jsoncpp QUIET jsoncpp) + +find_path( + jsoncpp_INCLUDE_DIR + NAMES json/json.h + HINTS ${PC_jsoncpp_INCLUDE_DIRS} + DOC "jsoncpp include dir" +) + +find_library( + jsoncpp_LIBRARY + NAMES jsoncpp + HINTS ${PC_jsoncpp_LIBRARY_DIR} + DOC "jsoncpp library" +) + +set(jsoncpp_INCLUDE_DIRS ${jsoncpp_INCLUDE_DIR}) +set(jsoncpp_LIBRARIES ${jsoncpp_LIBRARY}) + +if (jsoncpp_INCLUDE_DIRS AND jsoncpp_LIBRARIES) + set(jsoncpp_FOUND TRUE) +endif() + +# Create the IMPORTED target +if (jsoncpp_FOUND AND NOT TARGET jsoncpp_lib) + add_library(jsoncpp_lib UNKNOWN IMPORTED) + + set_property(TARGET jsoncpp_lib PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${jsoncpp_INCLUDE_DIR}) + + set_property(TARGET jsoncpp_lib PROPERTY + IMPORTED_LOCATION ${jsoncpp_LIBRARY}) +endif() + +# debug library on windows +# same naming convention as in qt (appending debug library with d) +# boost is using the same "hack" as us with "optimized" and "debug" +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + find_library( + jsoncpp_LIBRARY_DEBUG + NAMES jsoncppd + HINTS ${PC_jsoncpp_LIBDIR} ${PC_jsoncpp_LIBRARY_DIRS} + DOC "jsoncpp debug library" + ) + + set(jsoncpp_LIBRARIES optimized ${jsoncpp_LIBRARIES} debug ${jsoncpp_LIBRARY_DEBUG}) + + # Add Debug location to IMPORTED target + if(TARGET jsoncpp_lib) + set_property(TARGET jsoncpp_lib APPEND PROPERTY + IMPORTED_LOCATION_Debug ${jsoncpp_LIBRARY_DEBUG}) + endif() +endif() + +# find jsoncpp_INCLUDE_PREFIX +find_path( + jsoncpp_INCLUDE_PREFIX + NAMES json.h + HINTS ${jsoncpp_INCLUDE_DIR} + PATH_SUFFIXES jsoncpp/json json +) + +if (${jsoncpp_INCLUDE_PREFIX} MATCHES "jsoncpp") + set(jsoncpp_INCLUDE_PREFIX "jsoncpp/json") +else() + set(jsoncpp_INCLUDE_PREFIX "json") +endif() + +# Check the available version +set(_version_file "${jsoncpp_INCLUDE_DIR}/${jsoncpp_INCLUDE_PREFIX}/version.h") +if (jsoncpp_INCLUDE_DIR AND EXISTS ${_version_file}) + file(STRINGS "${_version_file}" jsoncpp_version_str + REGEX "JSONCPP_VERSION_STRING.*\"[^\"]+\"") + if(jsoncpp_version_str MATCHES "JSONCPP_VERSION_STRING.*\"([^\"]+)\"") + set(jsoncpp_VERSION_STRING ${CMAKE_MATCH_1}) + endif() + unset(jsoncpp_version_str) + string(REGEX REPLACE "^([0-9]+\.[0-9]+\.[0-9]+).*$" "\\1" + jsoncpp_VERSION "${jsoncpp_VERSION_STRING}") +endif() + +if(NOT jsoncpp_VERSION) + unset(jsoncpp_VERSION) + unset(jsoncpp_VERSION_STRING) +endif() + +# Check version requirement, if specified +if(jsoncpp_FIND_VERSION AND jsoncpp_VERSION) + if("${jsoncpp_FIND_VERSION}" STREQUAL "${jsoncpp_VERSION}") + set(jsoncpp_VERSION_EXACT TRUE) + endif() + if("${jsoncpp_FIND_VERSION}" VERSION_GREATER "${jsoncpp_VERSION}") + set(jsoncpp_VERSION_COMPATIBLE FALSE) + else() + set(jsoncpp_VERSION_COMPATIBLE TRUE) + endif() +endif() + +# Legacy +set(JSONCPP_LIBRARY ${jsoncpp_LIBRARY}) +set(JSONCPP_LIBRARIES ${jsoncpp_LIBRARIES}) +set(JSONCPP_INCLUDE_DIR ${jsoncpp_INCLUDE_DIR}) +set(JSONCPP_INCLUDE_DIRS ${jsoncpp_INCLUDE_DIRS}) +set(JSONCPP_INCLUDE_PREFIX ${jsoncpp_INCLUDE_PREFIX}) +set(JSONCPP_VERSION ${jsoncpp_VERSION}) +set(JSONCPP_FOUND ${jsoncpp_FOUND}) + +# handle the QUIETLY and REQUIRED arguments and set jsoncpp_FOUND to TRUE +# if all listed variables are TRUE, hide their existence from configuration view +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(jsoncpp + REQUIRED_VARS + jsoncpp_INCLUDE_DIR + jsoncpp_LIBRARY + VERSION_VAR + jsoncpp_VERSION +) +mark_as_advanced (jsoncpp_INCLUDE_DIR jsoncpp_LIBRARY) diff --git a/include/AudioBufferSource.h b/include/AudioBufferSource.h index 3a17feb3c..ae5ce014f 100644 --- a/include/AudioBufferSource.h +++ b/include/AudioBufferSource.h @@ -48,7 +48,6 @@ namespace openshot { private: int position; - int start; bool repeat; juce::AudioSampleBuffer *buffer; diff --git a/include/AudioReaderSource.h b/include/AudioReaderSource.h index c4e2d2480..d049e1b37 100644 --- a/include/AudioReaderSource.h +++ b/include/AudioReaderSource.h @@ -54,7 +54,6 @@ namespace openshot int speed; /// The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...) ReaderBase *reader; /// The reader to pull samples from - int64_t original_frame_number; /// The current frame to read from int64_t frame_number; /// The current frame number std::shared_ptr frame; /// The current frame object that is being read int64_t frame_position; /// The position of the current frame's buffer diff --git a/include/ChunkReader.h b/include/ChunkReader.h index 4d72c31da..cd7cd67f1 100644 --- a/include/ChunkReader.h +++ b/include/ChunkReader.h @@ -132,7 +132,7 @@ namespace openshot ChunkReader(std::string path, ChunkVersion chunk_version); /// Close the reader - void Close(); + void Close() override; /// @brief Get the chunk size (number of frames to write in each chunk) /// @returns The number of frames in this chunk @@ -143,27 +143,27 @@ namespace openshot void SetChunkSize(int64_t new_size) { chunk_size = new_size; }; /// Get the cache object used by this reader (always return NULL for this reader) - openshot::CacheMemory* GetCache() { return NULL; }; + openshot::CacheMemory* GetCache() override { return NULL; }; /// @brief Get an openshot::Frame object for a specific frame number of this reader. /// @returns The requested frame (containing the image and audio) /// @param requested_frame The frame number you want to retrieve - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "ChunkReader"; }; + std::string Name() override { return "ChunkReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open the reader. This is required before you can access frames or data from the reader. - void Open(); + void Open() override; }; } diff --git a/include/Clip.h b/include/Clip.h index 68d4622a1..0fbed1599 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -103,7 +103,6 @@ namespace openshot { // Audio resampler (if time mapping) openshot::AudioResampler *resampler; - juce::AudioSampleBuffer *audio_cache; // File Reader object openshot::ReaderBase* reader; @@ -140,11 +139,11 @@ namespace openshot { void reverse_buffer(juce::AudioSampleBuffer* buffer); public: - openshot::GravityType gravity; ///< The gravity of a clip determines where it snaps to its parent - openshot::ScaleType scale; ///< The scale determines how a clip should be resized to fit its parent - openshot::AnchorType anchor; ///< The anchor determines what parent a clip should snap to - openshot::FrameDisplayType display; ///< The format to display the frame number (if any) - openshot::VolumeMixType mixing; ///< What strategy should be followed when mixing audio with other clips + openshot::GravityType gravity; ///< The gravity of a clip determines where it snaps to its parent + openshot::ScaleType scale; ///< The scale determines how a clip should be resized to fit its parent + openshot::AnchorType anchor; ///< The anchor determines what parent a clip should snap to + openshot::FrameDisplayType display; ///< The format to display the frame number (if any) + openshot::VolumeMixType mixing; ///< What strategy should be followed when mixing audio with other clips /// Default Constructor Clip(); @@ -192,9 +191,9 @@ namespace openshot { /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) @@ -208,15 +207,19 @@ namespace openshot { bool Waveform() { return waveform; } ///< Get the waveform property of this clip void Waveform(bool value) { waveform = value; } ///< Set the waveform property of this clip - // Scale and Location curves + // Scale, Location, and Alpha curves openshot::Keyframe scale_x; ///< Curve representing the horizontal scaling in percent (0 to 1) openshot::Keyframe scale_y; ///< Curve representing the vertical scaling in percent (0 to 1) openshot::Keyframe location_x; ///< Curve representing the relative X position in percent based on the gravity (-1 to 1) openshot::Keyframe location_y; ///< Curve representing the relative Y position in percent based on the gravity (-1 to 1) - - // Alpha and Rotation curves openshot::Keyframe alpha; ///< Curve representing the alpha (1 to 0) + + // Rotation and Shear curves (origin point (x,y) is adjustable for both rotation and shear) openshot::Keyframe rotation; ///< Curve representing the rotation (0 to 360) + openshot::Keyframe shear_x; ///< Curve representing X shear angle in degrees (-45.0=left, 45.0=right) + openshot::Keyframe shear_y; ///< Curve representing Y shear angle in degrees (-45.0=down, 45.0=up) + openshot::Keyframe origin_x; ///< Curve representing X origin point (0.0=0% (left), 1.0=100% (right)) + openshot::Keyframe origin_y; ///< Curve representing Y origin point (0.0=0% (top), 1.0=100% (bottom)) // Time and Volume curves openshot::Keyframe time; ///< Curve representing the frames over time to play (used for speed and direction of video) @@ -232,9 +235,7 @@ namespace openshot { openshot::Keyframe crop_x; ///< Curve representing X offset in percent (-1.0=-100%, 0.0=0%, 1.0=100%) openshot::Keyframe crop_y; ///< Curve representing Y offset in percent (-1.0=-100%, 0.0=0%, 1.0=100%) - // Shear and perspective curves - openshot::Keyframe shear_x; ///< Curve representing X shear angle in degrees (-45.0=left, 45.0=right) - openshot::Keyframe shear_y; ///< Curve representing Y shear angle in degrees (-45.0=down, 45.0=up) + // Perspective curves openshot::Keyframe perspective_c1_x; ///< Curves representing X for coordinate 1 openshot::Keyframe perspective_c1_y; ///< Curves representing Y for coordinate 1 openshot::Keyframe perspective_c2_x; ///< Curves representing X for coordinate 2 diff --git a/include/DummyReader.h b/include/DummyReader.h index fd17bed1c..9a75751d0 100644 --- a/include/DummyReader.h +++ b/include/DummyReader.h @@ -46,17 +46,71 @@ namespace openshot { /** - * @brief This class is used as a simple, dummy reader, which always returns a blank frame. + * @brief This class is used as a simple, dummy reader, which can be very useful when writing + * unit tests. It can return a single blank frame or it can return custom frame objects + * which were passed into the constructor with a Cache object. * * A dummy reader can be created with any framerate or samplerate. This is useful in unit * tests that need to test different framerates or samplerates. + * + * @note Timeline does buffering by requesting more frames than it + * strictly needs. Thus if you use this DummyReader with a custom + * cache in a Timeline, make sure it has enough + * frames. Specifically you need some frames after the last frame + * you plan to access through the Timeline. + * + * @code + * // Create cache object to store fake Frame objects + * CacheMemory cache; + * + * // Now let's create some test frames + * for (int64_t frame_number = 1; frame_number <= 30; frame_number++) + * { + * // Create blank frame (with specific frame #, samples, and channels) + * // Sample count should be 44100 / 30 fps = 1470 samples per frame + * int sample_count = 1470; + * std::shared_ptr f(new openshot::Frame(frame_number, sample_count, 2)); + * + * // Create test samples with incrementing value + * float *audio_buffer = new float[sample_count]; + * for (int64_t sample_number = 0; sample_number < sample_count; sample_number++) + * { + * // Generate an incrementing audio sample value (just as an example) + * audio_buffer[sample_number] = float(frame_number) + (float(sample_number) / float(sample_count)); + * } + * + * // Add custom audio samples to Frame (bool replaceSamples, int destChannel, int destStartSample, const float* source, + * // int numSamples, float gainToApplyToSource = 1.0f) + * f->AddAudio(true, 0, 0, audio_buffer, sample_count, 1.0); // add channel 1 + * f->AddAudio(true, 1, 0, audio_buffer, sample_count, 1.0); // add channel 2 + * + * // Add test frame to cache + * cache.Add(f); + * } + * + * // Create a reader (Fraction fps, int width, int height, int sample_rate, int channels, float duration, CacheBase* cache) + * openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0, &cache); + * r.Open(); // Open the reader + * + * // Now let's verify our DummyReader works + * std::shared_ptr f = r.GetFrame(1); + * // r.GetFrame(1)->GetAudioSamples(0)[1] should equal 1.00068033 based on our above calculations + * + * // Clean up + * r.Close(); + * cache.Clear() + * @endcode */ class DummyReader : public ReaderBase { private: + CacheBase* dummy_cache; std::shared_ptr image_frame; bool is_open; + /// Initialize variables used by constructor + void init(Fraction fps, int width, int height, int sample_rate, int channels, float duration); + public: /// Blank constructor for DummyReader, with default settings. @@ -65,35 +119,38 @@ namespace openshot /// Constructor for DummyReader. DummyReader(openshot::Fraction fps, int width, int height, int sample_rate, int channels, float duration); + /// Constructor for DummyReader which takes a frame cache object. + DummyReader(openshot::Fraction fps, int width, int height, int sample_rate, int channels, float duration, CacheBase* cache); + virtual ~DummyReader(); /// Close File - void Close(); + void Close() override; /// Get the cache object used by this reader (always returns NULL for this reader) - CacheMemory* GetCache() { return NULL; }; + CacheMemory* GetCache() override { return NULL; }; /// Get an openshot::Frame object for a specific frame number of this reader. All numbers /// return the same Frame, since they all share the same image data. /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "DummyReader"; }; + std::string Name() override { return "DummyReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open File - which is called by the constructor automatically - void Open(); + void Open() override; }; } diff --git a/include/Exceptions.h b/include/Exceptions.h index 28942050b..f23cda7a1 100644 --- a/include/Exceptions.h +++ b/include/Exceptions.h @@ -38,16 +38,16 @@ namespace openshot { /** * @brief Base exception class with a custom message variable. * - * A custom error message field has been added to the std::exception base class. All - * OpenShot exception classes inherit from this class. + * A std::exception-derived exception class with custom message. + * All OpenShot exception classes inherit from this class. */ - class BaseException : public std::exception //: public exception + class ExceptionBase : public std::exception //: public exception { protected: std::string m_message; public: - BaseException(std::string message) : m_message(message) { } - virtual ~BaseException() noexcept {} + ExceptionBase(std::string message) : m_message(message) { } + virtual ~ExceptionBase() noexcept {} virtual const char* what() const noexcept { // return custom message return m_message.c_str(); @@ -55,7 +55,7 @@ namespace openshot { }; /// Exception when a required chunk is missing - class ChunkNotFound : public BaseException + class ChunkNotFound : public ExceptionBase { public: int64_t frame_number; @@ -70,13 +70,13 @@ namespace openshot { * @param chunk_frame The chunk frame */ ChunkNotFound(std::string message, int64_t frame_number, int64_t chunk_number, int64_t chunk_frame) - : BaseException(message), frame_number(frame_number), chunk_number(chunk_number), chunk_frame(chunk_frame) { } + : ExceptionBase(message), frame_number(frame_number), chunk_number(chunk_number), chunk_frame(chunk_frame) { } virtual ~ChunkNotFound() noexcept {} }; /// Exception when accessing a blackmagic decklink card - class DecklinkError : public BaseException + class DecklinkError : public ExceptionBase { public: /** @@ -85,12 +85,12 @@ namespace openshot { * @param message A message to accompany the exception */ DecklinkError(std::string message) - : BaseException(message) { } + : ExceptionBase(message) { } virtual ~DecklinkError() noexcept {} }; /// Exception when decoding audio packet - class ErrorDecodingAudio : public BaseException + class ErrorDecodingAudio : public ExceptionBase { public: int64_t frame_number; @@ -101,12 +101,12 @@ namespace openshot { * @param frame_number The frame number being processed */ ErrorDecodingAudio(std::string message, int64_t frame_number) - : BaseException(message), frame_number(frame_number) { } + : ExceptionBase(message), frame_number(frame_number) { } virtual ~ErrorDecodingAudio() noexcept {} }; /// Exception when encoding audio packet - class ErrorEncodingAudio : public BaseException + class ErrorEncodingAudio : public ExceptionBase { public: int64_t frame_number; @@ -117,12 +117,12 @@ namespace openshot { * @param frame_number The frame number being processed */ ErrorEncodingAudio(std::string message, int64_t frame_number) - : BaseException(message), frame_number(frame_number) { } + : ExceptionBase(message), frame_number(frame_number) { } virtual ~ErrorEncodingAudio() noexcept {} }; /// Exception when encoding audio packet - class ErrorEncodingVideo : public BaseException + class ErrorEncodingVideo : public ExceptionBase { public: int64_t frame_number; @@ -133,12 +133,12 @@ namespace openshot { * @param frame_number The frame number being processed */ ErrorEncodingVideo(std::string message, int64_t frame_number) - : BaseException(message), frame_number(frame_number) { } + : ExceptionBase(message), frame_number(frame_number) { } virtual ~ErrorEncodingVideo() noexcept {} }; /// Exception when an invalid # of audio channels are detected - class InvalidChannels : public BaseException + class InvalidChannels : public ExceptionBase { public: std::string file_path; @@ -149,12 +149,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ InvalidChannels(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~InvalidChannels() noexcept {} }; /// Exception when no valid codec is found for a file - class InvalidCodec : public BaseException + class InvalidCodec : public ExceptionBase { public: std::string file_path; @@ -165,12 +165,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ InvalidCodec(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~InvalidCodec() noexcept {} }; /// Exception for files that can not be found or opened - class InvalidFile : public BaseException + class InvalidFile : public ExceptionBase { public: std::string file_path; @@ -181,12 +181,12 @@ namespace openshot { * @param file_path The input file being processed */ InvalidFile(std::string message, std::string file_path) - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~InvalidFile() noexcept {} }; /// Exception when no valid format is found for a file - class InvalidFormat : public BaseException + class InvalidFormat : public ExceptionBase { public: std::string file_path; @@ -197,12 +197,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ InvalidFormat(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~InvalidFormat() noexcept {} }; /// Exception for invalid JSON - class InvalidJSON : public BaseException + class InvalidJSON : public ExceptionBase { public: std::string file_path; @@ -213,12 +213,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ InvalidJSON(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~InvalidJSON() noexcept {} }; /// Exception when invalid encoding options are used - class InvalidOptions : public BaseException + class InvalidOptions : public ExceptionBase { public: std::string file_path; @@ -229,12 +229,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ InvalidOptions(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~InvalidOptions() noexcept {} }; /// Exception when invalid sample rate is detected during encoding - class InvalidSampleRate : public BaseException + class InvalidSampleRate : public ExceptionBase { public: std::string file_path; @@ -245,12 +245,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ InvalidSampleRate(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~InvalidSampleRate() noexcept {} }; /// Exception for missing JSON Change key - class InvalidJSONKey : public BaseException + class InvalidJSONKey : public ExceptionBase { public: std::string json; @@ -261,12 +261,12 @@ namespace openshot { * @param json The json data being processed */ InvalidJSONKey(std::string message, std::string json) - : BaseException(message), json(json) { } + : ExceptionBase(message), json(json) { } virtual ~InvalidJSONKey() noexcept {} }; /// Exception when no streams are found in the file - class NoStreamsFound : public BaseException + class NoStreamsFound : public ExceptionBase { public: std::string file_path; @@ -277,12 +277,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ NoStreamsFound(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~NoStreamsFound() noexcept {} }; /// Exception for frames that are out of bounds. - class OutOfBoundsFrame : public BaseException + class OutOfBoundsFrame : public ExceptionBase { public: int64_t FrameRequested; @@ -295,12 +295,12 @@ namespace openshot { * @param max_frames The maximum available frame number */ OutOfBoundsFrame(std::string message, int64_t frame_requested, int64_t max_frames) - : BaseException(message), FrameRequested(frame_requested), MaxFrames(max_frames) { } + : ExceptionBase(message), FrameRequested(frame_requested), MaxFrames(max_frames) { } virtual ~OutOfBoundsFrame() noexcept {} }; /// Exception for an out of bounds key-frame point. - class OutOfBoundsPoint : public BaseException + class OutOfBoundsPoint : public ExceptionBase { public: int PointRequested; @@ -313,12 +313,12 @@ namespace openshot { * @param max_points The maximum available point value */ OutOfBoundsPoint(std::string message, int point_requested, int max_points) - : BaseException(message), PointRequested(point_requested), MaxPoints(max_points) { } + : ExceptionBase(message), PointRequested(point_requested), MaxPoints(max_points) { } virtual ~OutOfBoundsPoint() noexcept {} }; /// Exception when memory could not be allocated - class OutOfMemory : public BaseException + class OutOfMemory : public ExceptionBase { public: std::string file_path; @@ -329,12 +329,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ OutOfMemory(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~OutOfMemory() noexcept {} }; /// Exception when a reader is closed, and a frame is requested - class ReaderClosed : public BaseException + class ReaderClosed : public ExceptionBase { public: std::string file_path; @@ -345,12 +345,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ ReaderClosed(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~ReaderClosed() noexcept {} }; /// Exception when resample fails - class ResampleError : public BaseException + class ResampleError : public ExceptionBase { public: std::string file_path; @@ -361,12 +361,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ ResampleError(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~ResampleError() noexcept {} }; /// Exception when too many seek attempts happen - class TooManySeeks : public BaseException + class TooManySeeks : public ExceptionBase { public: std::string file_path; @@ -377,12 +377,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ TooManySeeks(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~TooManySeeks() noexcept {} }; /// Exception when a writer is closed, and a frame is requested - class WriterClosed : public BaseException + class WriterClosed : public ExceptionBase { public: std::string file_path; @@ -393,7 +393,7 @@ namespace openshot { * @param file_path (optional) The output file being written */ WriterClosed(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~WriterClosed() noexcept {} }; } diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index e9cee5793..ec0829652 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -246,31 +246,31 @@ namespace openshot { virtual ~FFmpegReader(); /// Close File - void Close(); + void Close() override; /// Get the cache object used by this reader - CacheMemory *GetCache() { return &final_cache; }; + CacheMemory *GetCache() override { return &final_cache; }; /// Get a shared pointer to a openshot::Frame object for a specific frame number of this reader. /// /// @returns The requested frame of video /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "FFmpegReader"; }; + std::string Name() override { return "FFmpegReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open File - which is called by the constructor automatically - void Open(); + void Open() override; }; } diff --git a/include/FFmpegUtilities.h b/include/FFmpegUtilities.h index 895b220d3..7daf0bc56 100644 --- a/include/FFmpegUtilities.h +++ b/include/FFmpegUtilities.h @@ -163,11 +163,10 @@ #define AV_FREE_CONTEXT(av_context) avcodec_free_context(&av_context) #define AV_GET_CODEC_TYPE(av_stream) av_stream->codecpar->codec_type #define AV_FIND_DECODER_CODEC_ID(av_stream) av_stream->codecpar->codec_id - auto AV_GET_CODEC_CONTEXT = [](AVStream* av_stream, AVCodec* av_codec) { \ - AVCodecContext *context = avcodec_alloc_context3(av_codec); \ - avcodec_parameters_to_context(context, av_stream->codecpar); \ - return context; \ - }; + #define AV_GET_CODEC_CONTEXT(av_stream, av_codec) \ + ({ AVCodecContext *context = avcodec_alloc_context3(av_codec); \ + avcodec_parameters_to_context(context, av_stream->codecpar); \ + context; }) #define AV_GET_CODEC_PAR_CONTEXT(av_stream, av_codec) av_codec; #define AV_GET_CODEC_FROM_STREAM(av_stream,codec_in) #define AV_GET_CODEC_ATTRIBUTES(av_stream, av_context) av_stream->codecpar @@ -199,11 +198,10 @@ #define AV_FREE_CONTEXT(av_context) avcodec_free_context(&av_context) #define AV_GET_CODEC_TYPE(av_stream) av_stream->codecpar->codec_type #define AV_FIND_DECODER_CODEC_ID(av_stream) av_stream->codecpar->codec_id - auto AV_GET_CODEC_CONTEXT = [](AVStream* av_stream, AVCodec* av_codec) { \ - AVCodecContext *context = avcodec_alloc_context3(av_codec); \ - avcodec_parameters_to_context(context, av_stream->codecpar); \ - return context; \ - }; + #define AV_GET_CODEC_CONTEXT(av_stream, av_codec) \ + ({ AVCodecContext *context = avcodec_alloc_context3(av_codec); \ + avcodec_parameters_to_context(context, av_stream->codecpar); \ + context; }) #define AV_GET_CODEC_PAR_CONTEXT(av_stream, av_codec) av_codec; #define AV_GET_CODEC_FROM_STREAM(av_stream,codec_in) #define AV_GET_CODEC_ATTRIBUTES(av_stream, av_context) av_stream->codecpar diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index 7480663f8..98fbbb590 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -167,7 +167,6 @@ namespace openshot { AVCodecContext *video_codec_ctx; AVCodecContext *audio_codec_ctx; SwsContext *img_convert_ctx; - double audio_pts, video_pts; int16_t *samples; uint8_t *audio_outbuf; uint8_t *audio_encoder_buffer; diff --git a/include/FrameMapper.h b/include/FrameMapper.h index ff4ccd719..35dc8fb71 100644 --- a/include/FrameMapper.h +++ b/include/FrameMapper.h @@ -175,13 +175,13 @@ namespace openshot void ChangeMapping(Fraction target_fps, PulldownType pulldown, int target_sample_rate, int target_channels, ChannelLayout target_channel_layout); /// Close the openshot::FrameMapper and internal reader - void Close(); + void Close() override; /// Get a frame based on the target frame rate and the new frame number of a frame MappedFrame GetMappedFrame(int64_t TargetFrameNumber); /// Get the cache object used by this reader - CacheMemory* GetCache() { return &final_cache; }; + CacheMemory* GetCache() override { return &final_cache; }; /// @brief This method is required for all derived classes of ReaderBase, and return the /// openshot::Frame object, which contains the image and audio information for that @@ -189,22 +189,22 @@ namespace openshot /// /// @returns The requested frame of video /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen(); + bool IsOpen() override; /// Return the type name of the class - std::string Name() { return "FrameMapper"; }; + std::string Name() override { return "FrameMapper"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open the internal reader - void Open(); + void Open() override; /// Print all of the original frames and which new frames they map to void PrintMapping(); diff --git a/include/ImageReader.h b/include/ImageReader.h index bb19dd3dc..5aafcc8f7 100644 --- a/include/ImageReader.h +++ b/include/ImageReader.h @@ -87,32 +87,32 @@ namespace openshot ImageReader(std::string path, bool inspect_reader); /// Close File - void Close(); + void Close() override; /// Get the cache object used by this reader (always returns NULL for this object) - CacheMemory* GetCache() { return NULL; }; + CacheMemory* GetCache() override { return NULL; }; /// Get an openshot::Frame object for a specific frame number of this reader. All numbers /// return the same Frame, since they all share the same image data. /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "ImageReader"; }; + std::string Name() override { return "ImageReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object - Json::Value JsonValue() const; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object + Json::Value JsonValue() const override; ///< Generate Json::Value for this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open File - which is called by the constructor automatically - void Open(); + void Open() override; }; } diff --git a/include/ImageWriter.h b/include/ImageWriter.h index 87e8a9a95..e483cb10f 100644 --- a/include/ImageWriter.h +++ b/include/ImageWriter.h @@ -88,7 +88,6 @@ namespace openshot private: std::string path; int cache_size; - bool is_writing; bool is_open; int64_t write_video_count; std::vector frames; diff --git a/include/MagickUtilities.h b/include/MagickUtilities.h index 74365904a..953b85ee0 100644 --- a/include/MagickUtilities.h +++ b/include/MagickUtilities.h @@ -32,7 +32,11 @@ #ifdef USE_IMAGEMAGICK +// Exclude a warning message with IM6 headers +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wignored-qualifiers" #include "Magick++.h" +#pragma GCC diagnostic pop // Determine ImageMagick version, as IM7 isn't fully // backwards compatible diff --git a/include/Qt/AudioPlaybackThread.h b/include/Qt/AudioPlaybackThread.h index 348a0f48a..9a1594483 100644 --- a/include/Qt/AudioPlaybackThread.h +++ b/include/Qt/AudioPlaybackThread.h @@ -75,7 +75,7 @@ namespace openshot static AudioDeviceManagerSingleton * Instance(); /// Public device manager property - AudioDeviceManager audioDeviceManager; + juce::AudioDeviceManager audioDeviceManager; /// Close audio device void CloseAudioDevice(); @@ -86,9 +86,9 @@ namespace openshot */ class AudioPlaybackThread : juce::Thread { - AudioSourcePlayer player; - AudioTransportSource transport; - MixerAudioSource mixer; + juce::AudioSourcePlayer player; + juce::AudioTransportSource transport; + juce::MixerAudioSource mixer; AudioReaderSource *source; double sampleRate; int numChannels; diff --git a/include/QtHtmlReader.h b/include/QtHtmlReader.h index d7052d494..3d426afb0 100644 --- a/include/QtHtmlReader.h +++ b/include/QtHtmlReader.h @@ -112,32 +112,32 @@ namespace openshot QtHtmlReader(int width, int height, int x_offset, int y_offset, GravityType gravity, std::string html, std::string css, std::string background_color); /// Close Reader - void Close(); + void Close() override; /// Get the cache object used by this reader (always returns NULL for this object) - openshot::CacheMemory* GetCache() { return NULL; }; + openshot::CacheMemory* GetCache() override { return NULL; }; /// Get an openshot::Frame object for a specific frame number of this reader. All numbers /// return the same Frame, since they all share the same image data. /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "QtHtmlReader"; }; + std::string Name() override { return "QtHtmlReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open Reader - which is called by the constructor automatically - void Open(); + void Open() override; }; } diff --git a/include/QtImageReader.h b/include/QtImageReader.h index 3e456e394..3848065a1 100644 --- a/include/QtImageReader.h +++ b/include/QtImageReader.h @@ -85,32 +85,32 @@ namespace openshot virtual ~QtImageReader(); /// Close File - void Close(); + void Close() override; /// Get the cache object used by this reader (always returns NULL for this object) - CacheMemory* GetCache() { return NULL; }; + CacheMemory* GetCache() override { return NULL; }; /// Get an openshot::Frame object for a specific frame number of this reader. All numbers /// return the same Frame, since they all share the same image data. /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "QtImageReader"; }; + std::string Name() override { return "QtImageReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open File - which is called by the constructor automatically - void Open(); + void Open() override; }; } diff --git a/include/QtTextReader.h b/include/QtTextReader.h index d226e920c..2fd203ad4 100644 --- a/include/QtTextReader.h +++ b/include/QtTextReader.h @@ -123,32 +123,32 @@ namespace openshot void SetTextBackgroundColor(std::string color); /// Close Reader - void Close(); + void Close() override; /// Get the cache object used by this reader (always returns NULL for this object) - openshot::CacheMemory* GetCache() { return NULL; }; + openshot::CacheMemory* GetCache() override { return NULL; }; /// Get an openshot::Frame object for a specific frame number of this reader. All numbers /// return the same Frame, since they all share the same image data. /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "QtTextReader"; }; + std::string Name() override { return "QtTextReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open Reader - which is called by the constructor automatically - void Open(); + void Open() override; }; } diff --git a/include/TextReader.h b/include/TextReader.h index b6dbf5cd0..b5488f5fe 100644 --- a/include/TextReader.h +++ b/include/TextReader.h @@ -123,32 +123,32 @@ namespace openshot void SetTextBackgroundColor(std::string color); /// Close Reader - void Close(); + void Close() override; /// Get the cache object used by this reader (always returns NULL for this object) - openshot::CacheMemory* GetCache() { return NULL; }; + openshot::CacheMemory* GetCache() override { return NULL; }; /// Get an openshot::Frame object for a specific frame number of this reader. All numbers /// return the same Frame, since they all share the same image data. /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "TextReader"; }; + std::string Name() override { return "TextReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open Reader - which is called by the constructor automatically - void Open(); + void Open() override; }; } diff --git a/include/Timeline.h b/include/Timeline.h index 56a895866..932b04acf 100644 --- a/include/Timeline.h +++ b/include/Timeline.h @@ -242,13 +242,13 @@ namespace openshot { std::list Clips() { return clips; }; /// Close the timeline reader (and any resources it was consuming) - void Close(); + void Close() override; /// Return the list of effects on the timeline std::list Effects() { return effects; }; /// Get the cache object used by this reader - CacheBase* GetCache() { return final_cache; }; + CacheBase* GetCache() override { return final_cache; }; /// Set the cache object used by this reader. You must now manage the lifecycle /// of this cache object though (Timeline will not delete it for you). @@ -258,7 +258,7 @@ namespace openshot { /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; // Curves for the viewport Keyframe viewport_scale; ///MAX_WIDTH and Settings::Instance()->MAX_HEIGHT. @@ -291,7 +291,7 @@ namespace openshot { void ApplyJsonDiff(std::string value); /// Open the reader (and start consuming resources) - void Open(); + void Open() override; /// @brief Remove an openshot::Clip from the timeline /// @param clip Remove an openshot::Clip from the timeline. diff --git a/include/effects/Bars.h b/include/effects/Bars.h index fa9df6f80..7c92255aa 100644 --- a/include/effects/Bars.h +++ b/include/effects/Bars.h @@ -86,13 +86,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Blur.h b/include/effects/Blur.h index c254b8cde..60a0cd085 100644 --- a/include/effects/Blur.h +++ b/include/effects/Blur.h @@ -98,13 +98,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Brightness.h b/include/effects/Brightness.h index 69f2cf343..5f25b94a0 100644 --- a/include/effects/Brightness.h +++ b/include/effects/Brightness.h @@ -86,13 +86,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/ChromaKey.h b/include/effects/ChromaKey.h index dbc81e9cf..fcc8c3b1f 100644 --- a/include/effects/ChromaKey.h +++ b/include/effects/ChromaKey.h @@ -83,13 +83,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object // Get all properties for a specific frame std::string PropertiesJSON(int64_t requested_frame) const override; diff --git a/include/effects/ColorShift.h b/include/effects/ColorShift.h index ada2acd68..4ef56dc68 100644 --- a/include/effects/ColorShift.h +++ b/include/effects/ColorShift.h @@ -90,13 +90,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Crop.h b/include/effects/Crop.h index 2d4a2b2ee..f5ba07f24 100644 --- a/include/effects/Crop.h +++ b/include/effects/Crop.h @@ -85,13 +85,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Deinterlace.h b/include/effects/Deinterlace.h index eff7b2fe7..97c778538 100644 --- a/include/effects/Deinterlace.h +++ b/include/effects/Deinterlace.h @@ -79,13 +79,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object // Get all properties for a specific frame std::string PropertiesJSON(int64_t requested_frame) const override; diff --git a/include/effects/Hue.h b/include/effects/Hue.h index 9d86d5c2b..833bf087b 100644 --- a/include/effects/Hue.h +++ b/include/effects/Hue.h @@ -76,13 +76,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Mask.h b/include/effects/Mask.h index 390ffa361..8156b8436 100644 --- a/include/effects/Mask.h +++ b/include/effects/Mask.h @@ -98,13 +98,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Negate.h b/include/effects/Negate.h index 6206a6607..c691a86c1 100644 --- a/include/effects/Negate.h +++ b/include/effects/Negate.h @@ -67,13 +67,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object // Get all properties for a specific frame std::string PropertiesJSON(int64_t requested_frame) const override; diff --git a/include/effects/Pixelate.h b/include/effects/Pixelate.h index 9348ce863..4cdd440f2 100644 --- a/include/effects/Pixelate.h +++ b/include/effects/Pixelate.h @@ -85,13 +85,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Saturation.h b/include/effects/Saturation.h index e8d0d9409..f272305f9 100644 --- a/include/effects/Saturation.h +++ b/include/effects/Saturation.h @@ -83,13 +83,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Shift.h b/include/effects/Shift.h index 765da7555..7a7efbea4 100644 --- a/include/effects/Shift.h +++ b/include/effects/Shift.h @@ -79,13 +79,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Wave.h b/include/effects/Wave.h index ad516bde3..d4759c24e 100644 --- a/include/effects/Wave.h +++ b/include/effects/Wave.h @@ -85,13 +85,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/src/AudioBufferSource.cpp b/src/AudioBufferSource.cpp index 2f3d14ca3..69e5713ad 100644 --- a/src/AudioBufferSource.cpp +++ b/src/AudioBufferSource.cpp @@ -35,7 +35,7 @@ using namespace openshot; // Default constructor AudioBufferSource::AudioBufferSource(juce::AudioSampleBuffer *audio_buffer) - : position(0), start(0), repeat(false), buffer(audio_buffer) + : position(0), repeat(false), buffer(audio_buffer) { } // Destructor diff --git a/src/AudioReaderSource.cpp b/src/AudioReaderSource.cpp index c96d0bcc3..999d109d2 100644 --- a/src/AudioReaderSource.cpp +++ b/src/AudioReaderSource.cpp @@ -35,7 +35,7 @@ using namespace openshot; // Constructor that reads samples from a reader AudioReaderSource::AudioReaderSource(ReaderBase *audio_reader, int64_t starting_frame_number, int buffer_size) - : reader(audio_reader), frame_number(starting_frame_number), original_frame_number(starting_frame_number), + : reader(audio_reader), frame_number(starting_frame_number), size(buffer_size), position(0), frame_position(0), estimated_frame(0), speed(1) { // Initialize an audio buffer (based on reader) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a57780b0d..6b9dd8eed 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,9 +42,11 @@ if (APPLE) set_property(GLOBAL PROPERTY JUCE_MAC "JUCE_MAC") add_definitions(-DNDEBUG) set(EXTENSION "mm") - set(JUCE_PLATFORM_SPECIFIC_DIR build/macosx/platform_specific_code) set(JUCE_PLATFORM_SPECIFIC_LIBRARIES "-framework Carbon -framework Cocoa -framework CoreFoundation -framework CoreAudio -framework CoreMidi -framework IOKit -framework AGL -framework AudioToolbox -framework QuartzCore -lobjc -framework Accelerate") + + # Prevent compiling with __cxx11 + add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) endif() ################ IMAGE MAGICK ################## @@ -248,34 +250,29 @@ target_include_directories(openshot ################### JSONCPP ##################### # Include jsoncpp headers (needed for JSON parsing) if (USE_SYSTEM_JSONCPP) - message(STATUS "Looking for system JsonCpp") - find_package(JsonCpp) - if (JSONCPP_FOUND AND NOT TARGET jsoncpp_lib) - # Create the expected target, for older installs that don't - add_library(jsoncpp_lib INTERFACE) - target_include_directories(jsoncpp_lib INTERFACE - ${JSONCPP_INCLUDE_DIRS}) - target_link_libraries(jsoncpp_lib INTERFACE ${JSONCPP_LIBRARY}) - endif () + message(STATUS "Looking for system jsoncpp") + # Either an installed config or our find module will + # create the IMPORTED target jsoncpp_lib if successful + find_package(jsoncpp) endif () -if (NOT JSONCPP_FOUND AND NOT DISABLE_BUNDLED_JSONCPP) - message(STATUS "Using embedded JsonCpp (not found or USE_SYSTEM_JSONCPP disabled)") +if (NOT jsoncpp_FOUND AND NOT DISABLE_BUNDLED_JSONCPP) + message(STATUS "Using embedded jsoncpp (not found or USE_SYSTEM_JSONCPP disabled)") if (NOT TARGET jsoncpp_lib) add_library(jsoncpp_lib INTERFACE) target_include_directories(jsoncpp_lib INTERFACE "${PROJECT_SOURCE_DIR}/thirdparty/jsoncpp") target_sources(jsoncpp_lib INTERFACE "${PROJECT_SOURCE_DIR}/thirdparty/jsoncpp/jsoncpp.cpp") # Because this satisfies the requirement, an installed JsonCpp is optional - set_package_properties(JsonCpp PROPERTIES TYPE OPTIONAL) + set_package_properties(jsoncpp PROPERTIES TYPE OPTIONAL) endif () - add_feature_info("JsonCpp (embedded)" TRUE "JsonCpp will be compiled from the bundled sources") + add_feature_info("jsoncpp (embedded)" TRUE "jsoncpp will be compiled from the bundled sources") endif () -if (JSONCPP_FOUND) +if (jsoncpp_FOUND) # JsonCpp is actually required, even though we probe for it optionally # (This tells feature_summary() to bail if it's not found, later) - set_package_properties(JsonCpp PROPERTIES TYPE REQUIRED) + set_package_properties(jsoncpp PROPERTIES TYPE REQUIRED) endif () # If we found any usable JsonCpp, use it. Otherwise, bail. @@ -308,8 +305,6 @@ endforeach() # Threading library -- uses IMPORTED target Threads::Threads (since CMake 3.1) set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE) -find_package(Threads REQUIRED) -target_link_libraries(openshot PUBLIC Threads::Threads) ################### OPENMP ##################### # Check for OpenMP (used for multi-core processing) @@ -322,7 +317,6 @@ if(NOT TARGET OpenMP::OpenMP_CXX) add_library(OpenMP_TARGET INTERFACE) add_library(OpenMP::OpenMP_CXX ALIAS OpenMP_TARGET) target_compile_options(OpenMP_TARGET INTERFACE ${OpenMP_CXX_FLAGS}) - target_link_libraries(OpenMP_TARGET INTERFACE Threads::Threads) target_link_libraries(OpenMP_TARGET INTERFACE ${OpenMP_CXX_FLAGS}) endif() diff --git a/src/CacheDisk.cpp b/src/CacheDisk.cpp index 9f67ce994..bb2e12c42 100644 --- a/src/CacheDisk.cpp +++ b/src/CacheDisk.cpp @@ -228,7 +228,7 @@ std::shared_ptr CacheDisk::GetFrame(int64_t frame_number) // Load image file std::shared_ptr image = std::shared_ptr(new QImage()); - bool success = image->load(QString::fromStdString(frame_path.toStdString())); + image->load(frame_path); // Set pixel formatimage-> image = std::shared_ptr(new QImage(image->convertToFormat(QImage::Format_RGBA8888))); diff --git a/src/Clip.cpp b/src/Clip.cpp index 1968bb3b1..d9f694408 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -89,6 +89,8 @@ void Clip::init_settings() // Init shear and perspective curves shear_x = Keyframe(0.0); shear_y = Keyframe(0.0); + origin_x = Keyframe(0.5); + origin_y = Keyframe(0.5); perspective_c1_x = Keyframe(-1.0); perspective_c1_y = Keyframe(-1.0); perspective_c2_x = Keyframe(-1.0); @@ -132,14 +134,14 @@ void Clip::init_reader_rotation() { } // Default Constructor for a clip -Clip::Clip() : resampler(NULL), audio_cache(NULL), reader(NULL), allocated_reader(NULL) +Clip::Clip() : resampler(NULL), reader(NULL), allocated_reader(NULL) { // Init all default settings init_settings(); } // Constructor with reader -Clip::Clip(ReaderBase* new_reader) : resampler(NULL), audio_cache(NULL), reader(new_reader), allocated_reader(NULL) +Clip::Clip(ReaderBase* new_reader) : resampler(NULL), reader(new_reader), allocated_reader(NULL) { // Init all default settings init_settings(); @@ -148,12 +150,15 @@ Clip::Clip(ReaderBase* new_reader) : resampler(NULL), audio_cache(NULL), reader( Open(); Close(); - // Update duration - End(reader->info.duration); + // Update duration and set parent + if (reader) { + End(reader->info.duration); + reader->SetClip(this); + } } // Constructor with filepath -Clip::Clip(std::string path) : resampler(NULL), audio_cache(NULL), reader(NULL), allocated_reader(NULL) +Clip::Clip(std::string path) : resampler(NULL), reader(NULL), allocated_reader(NULL) { // Init all default settings init_settings(); @@ -202,9 +207,10 @@ Clip::Clip(std::string path) : resampler(NULL), audio_cache(NULL), reader(NULL), } } - // Update duration + // Update duration and set parent if (reader) { End(reader->info.duration); + reader->SetClip(this); allocated_reader = reader; init_reader_rotation(); } @@ -422,7 +428,6 @@ void Clip::get_time_mapped_frame(std::shared_ptr frame, int64_t frame_num int delta = int(round(time.GetDelta(frame_number))); // Init audio vars - int sample_rate = reader->info.sample_rate; int channels = reader->info.channels; int number_of_samples = GetOrCreateFrame(new_frame_number)->GetAudioSamplesCount(); @@ -433,7 +438,6 @@ void Clip::get_time_mapped_frame(std::shared_ptr frame, int64_t frame_num // SLOWING DOWN AUDIO // Resample data, and return new buffer pointer juce::AudioSampleBuffer *resampled_buffer = NULL; - int resampled_buffer_size = 0; // SLOW DOWN audio (split audio) samples = new juce::AudioSampleBuffer(channels, number_of_samples); @@ -455,9 +459,6 @@ void Clip::get_time_mapped_frame(std::shared_ptr frame, int64_t frame_num // Resample the data (since it's the 1st slice) resampled_buffer = resampler->GetResampledBuffer(); - // Get the length of the resampled buffer (if one exists) - resampled_buffer_size = resampled_buffer->getNumSamples(); - // Just take the samples we need for the requested frame int start = (number_of_samples * (time.GetRepeatFraction(frame_number).num - 1)); if (start > 0) @@ -567,7 +568,6 @@ void Clip::get_time_mapped_frame(std::shared_ptr frame, int64_t frame_num // Resample data, and return new buffer pointer juce::AudioSampleBuffer *buffer = resampler->GetResampledBuffer(); - int resampled_buffer_size = buffer->getNumSamples(); // Add the newly resized audio samples to the current frame for (int channel = 0; channel < channels; channel++) @@ -718,6 +718,8 @@ std::string Clip::PropertiesJSON(int64_t requested_frame) const { root["shear_x"] = add_property_json("Shear X", shear_x.GetValue(requested_frame), "float", "", &shear_x, -1.0, 1.0, false, requested_frame); root["shear_y"] = add_property_json("Shear Y", shear_y.GetValue(requested_frame), "float", "", &shear_y, -1.0, 1.0, false, requested_frame); root["rotation"] = add_property_json("Rotation", rotation.GetValue(requested_frame), "float", "", &rotation, -360, 360, false, requested_frame); + root["origin_x"] = add_property_json("Origin X", origin_x.GetValue(requested_frame), "float", "", &origin_x, 0.0, 1.0, false, requested_frame); + root["origin_y"] = add_property_json("Origin Y", origin_y.GetValue(requested_frame), "float", "", &origin_y, 0.0, 1.0, false, requested_frame); root["volume"] = add_property_json("Volume", volume.GetValue(requested_frame), "float", "", &volume, 0.0, 1.0, false, requested_frame); root["time"] = add_property_json("Time", time.GetValue(requested_frame), "float", "", &time, 0.0, 30 * 60 * 60 * 48, false, requested_frame); root["channel_filter"] = add_property_json("Channel Filter", channel_filter.GetValue(requested_frame), "int", "", &channel_filter, -1, 10, false, requested_frame); @@ -774,6 +776,8 @@ Json::Value Clip::JsonValue() const { root["crop_y"] = crop_y.JsonValue(); root["shear_x"] = shear_x.JsonValue(); root["shear_y"] = shear_y.JsonValue(); + root["origin_x"] = origin_x.JsonValue(); + root["origin_y"] = origin_y.JsonValue(); root["channel_filter"] = channel_filter.JsonValue(); root["channel_mapping"] = channel_mapping.JsonValue(); root["has_audio"] = has_audio.JsonValue(); @@ -871,6 +875,10 @@ void Clip::SetJsonValue(const Json::Value root) { shear_x.SetJsonValue(root["shear_x"]); if (!root["shear_y"].isNull()) shear_y.SetJsonValue(root["shear_y"]); + if (!root["origin_x"].isNull()) + origin_x.SetJsonValue(root["origin_x"]); + if (!root["origin_y"].isNull()) + origin_y.SetJsonValue(root["origin_y"]); if (!root["channel_filter"].isNull()) channel_filter.SetJsonValue(root["channel_filter"]); if (!root["channel_mapping"].isNull()) diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp index 5613a696f..8b6f752f7 100644 --- a/src/DummyReader.cpp +++ b/src/DummyReader.cpp @@ -32,18 +32,8 @@ using namespace openshot; -// Blank constructor for DummyReader, with default settings. -DummyReader::DummyReader() : is_open(false) { - - // Call actual constructor with default values - DummyReader(Fraction(24,1), 1280, 768, 44100, 2, 30.0); -} - -// Constructor for DummyReader. Pass a framerate and samplerate. -DummyReader::DummyReader(Fraction fps, int width, int height, - int sample_rate, int channels, float duration) - : is_open(false) { - +// Initialize variables used by constructor +void DummyReader::init(Fraction fps, int width, int height, int sample_rate, int channels, float duration) { // Set key info settings info.has_audio = false; info.has_video = true; @@ -70,10 +60,30 @@ DummyReader::DummyReader(Fraction fps, int width, int height, // Set the ratio based on the reduced fraction info.display_ratio.num = size.num; info.display_ratio.den = size.den; +} + +// Blank constructor for DummyReader, with default settings. +DummyReader::DummyReader() : dummy_cache(NULL), is_open(false) { + + // Initialize important variables + init(Fraction(24,1), 1280, 768, 44100, 2, 30.0); +} + +// Constructor for DummyReader. Pass a framerate and samplerate. +DummyReader::DummyReader(Fraction fps, int width, int height, int sample_rate, int channels, float duration) : dummy_cache(NULL), is_open(false) { + + // Initialize important variables + init(fps, width, height, sample_rate, channels, duration); +} - // Open and Close the reader, to populate its attributes (such as height, width, etc...) - Open(); - Close(); +// Constructor which also takes a cache object +DummyReader::DummyReader(Fraction fps, int width, int height, int sample_rate, int channels, float duration, CacheBase* cache) : is_open(false) { + + // Initialize important variables + init(fps, width, height, sample_rate, channels, duration); + + // Set cache object + dummy_cache = (CacheBase*) cache; } DummyReader::~DummyReader() { @@ -104,21 +114,40 @@ void DummyReader::Close() } } -// Get an openshot::Frame object for a specific frame number of this reader. +// Get an openshot::Frame object for a specific frame number of this reader. It is either a blank frame +// or a custom frame added with passing a Cache object to the constructor. std::shared_ptr DummyReader::GetFrame(int64_t requested_frame) { // Check for open reader (or throw exception) if (!is_open) throw ReaderClosed("The ImageReader is closed. Call Open() before calling this method.", "dummy"); - if (image_frame) - { + int dummy_cache_count = 0; + if (dummy_cache) { + dummy_cache_count = dummy_cache->Count(); + } + + if (dummy_cache_count == 0 && image_frame) { // Create a scoped lock, allowing only a single thread to run the following code at one time const GenericScopedLock lock(getFrameCriticalSection); // Always return same frame (regardless of which frame number was requested) image_frame->number = requested_frame; return image_frame; + + } else if (dummy_cache_count > 0) { + // Create a scoped lock, allowing only a single thread to run the following code at one time + const GenericScopedLock lock(getFrameCriticalSection); + + // Get a frame from the dummy cache + std::shared_ptr f = dummy_cache->GetFrame(requested_frame); + if (f) { + // return frame from cache (if found) + return f; + } else { + // No cached frame found + throw InvalidFile("Requested frame not found. You can only access Frame numbers that exist in the Cache object.", "dummy"); + } } else // no frame loaded diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 2b03994be..c8ce141fe 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -706,9 +706,16 @@ void FFmpegReader::UpdateVideoInfo() { info.vcodec = pCodecCtx->codec->name; info.video_bit_rate = (pFormatCtx->bit_rate / 8); - // set frames per second (fps) - info.fps.num = pStream->avg_frame_rate.num; - info.fps.den = pStream->avg_frame_rate.den; + // Frame rate from the container and codec + AVRational framerate = av_guess_frame_rate(pFormatCtx, pStream, NULL); + info.fps.num = framerate.num; + info.fps.den = framerate.den; + + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::UpdateVideoInfo", "info.fps.num", info.fps.num, "info.fps.den", info.fps.den); + + // TODO: remove excessive debug info in the next releases + // The debug info below is just for comparison and troubleshooting on users side during the transition period + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::UpdateVideoInfo (pStream->avg_frame_rate)", "num", pStream->avg_frame_rate.num, "den", pStream->avg_frame_rate.den); if (pStream->sample_aspect_ratio.num != 0) { info.pixel_ratio.num = pStream->sample_aspect_ratio.num; @@ -1419,8 +1426,6 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr int packet_samples = 0; int data_size = 0; - // re-initialize buffer size (it gets changed in the avcodec_decode_audio2 method call) - int buf_size = AVCODEC_MAX_AUDIO_FRAME_SIZE + MY_INPUT_BUFFER_PADDING_SIZE; #pragma omp critical (ProcessAudioPacket) { #if IS_FFMPEG_3_2 @@ -1458,7 +1463,6 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr if (frame_finished) { // determine how many samples were decoded - int planar = av_sample_fmt_is_planar((AVSampleFormat) AV_GET_CODEC_PIXEL_FORMAT(aStream, aCodecCtx)); int plane_size = -1; data_size = av_samples_get_buffer_size(&plane_size, AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels, @@ -1547,7 +1551,7 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0); av_opt_set_int(avr, "in_channels", info.channels, 0); av_opt_set_int(avr, "out_channels", info.channels, 0); - int r = SWR_INIT(avr); + SWR_INIT(avr); // Convert audio samples nb_samples = SWR_CONVERT(avr, // audio resample context @@ -1627,9 +1631,8 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr else partial_frame = true; - // Add samples for current channel to the frame. Reduce the volume to 98%, to prevent - // some louder samples from maxing out at 1.0 (not sure why this happens) - f->AddAudio(true, channel_filter, start, iterate_channel_buffer, samples, 0.98f); + // Add samples for current channel to the frame. + f->AddAudio(true, channel_filter, start, iterate_channel_buffer, samples, 1.0f); // Debug output ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessAudioPacket (f->AddAudio)", "frame", starting_frame_number, "start", start, "samples", samples, "channel", channel_filter, "partial_frame", partial_frame, "samples_per_frame", samples_per_frame); diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index eb100095c..cbf8a88b2 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -84,7 +84,7 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6 #endif // HAVE_HW_ACCEL FFmpegWriter::FFmpegWriter(std::string path) : - path(path), fmt(NULL), oc(NULL), audio_st(NULL), video_st(NULL), audio_pts(0), video_pts(0), samples(NULL), + path(path), fmt(NULL), oc(NULL), audio_st(NULL), video_st(NULL), samples(NULL), audio_outbuf(NULL), audio_outbuf_size(0), audio_input_frame_size(0), audio_input_position(0), initial_audio_input_frame_size(0), img_convert_ctx(NULL), cache_size(8), num_of_rescalers(32), rescaler_position(0), video_codec_ctx(NULL), audio_codec_ctx(NULL), is_writing(false), write_video_count(0), write_audio_count(0), @@ -255,7 +255,7 @@ void FFmpegWriter::SetVideoOptions(bool has_video, std::string codec, Fraction f } if (bit_rate >= 1000) // bit_rate is the bitrate in b/s info.video_bit_rate = bit_rate; - if ((bit_rate >= 0) && (bit_rate < 64)) // bit_rate is the bitrate in crf + if ((bit_rate >= 0) && (bit_rate < 256)) // bit_rate is the bitrate in crf info.video_bit_rate = bit_rate; info.interlaced_frame = interlaced; @@ -358,7 +358,7 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va // Was option found? if (option || (name == "g" || name == "qmin" || name == "qmax" || name == "max_b_frames" || name == "mb_decision" || name == "level" || name == "profile" || name == "slices" || name == "rc_min_rate" || name == "rc_max_rate" || - name == "rc_buffer_size" || name == "crf" || name == "cqp")) { + name == "rc_buffer_size" || name == "crf" || name == "cqp" || name == "qp")) { // Check for specific named options if (name == "g") // Set gop_size @@ -478,6 +478,7 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va #if (LIBAVCODEC_VERSION_MAJOR >= 58) case AV_CODEC_ID_AV1 : c->bit_rate = 0; + // AV1 only supports "crf" quality values av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0); break; #endif @@ -500,7 +501,14 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va } break; case AV_CODEC_ID_HEVC : - av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value), 51), 0); // 0-51 + if (strstr(info.vcodec.c_str(), "svt_hevc") != NULL) { + av_opt_set_int(c->priv_data, "preset", 7, 0); + av_opt_set_int(c->priv_data, "forced-idr",1,0); + av_opt_set_int(c->priv_data, "qp",std::min(std::stoi(value), 51),0); + } + else { + av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value), 51), 0); // 0-51 + } if (std::stoi(value) == 0) { av_opt_set(c->priv_data, "preset", "veryslow", 0); av_opt_set_int(c->priv_data, "lossless", 1, 0); @@ -520,6 +528,41 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va c->bit_rate = (int) (mbs); } } +#endif + } else if (name == "qp") { + // encode quality and special settings like lossless + // This might be better in an extra methods as more options + // and way to set quality are possible +#if (LIBAVCODEC_VERSION_MAJOR >= 58) + switch (c->codec_id) { + case AV_CODEC_ID_AV1 : + c->bit_rate = 0; + if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) { + av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); + } + else if (strstr(info.vcodec.c_str(), "rav1e") != NULL) { + // Set number of tiles to a fixed value + // TODO Let user choose number of tiles + av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),255), 0); + } + else if (strstr(info.vcodec.c_str(), "aom") != NULL) { + // Set number of tiles to a fixed value + // TODO Let user choose number of tiles + // libaom doesn't have qp only crf + av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0); + } + else { + av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0); + } + case AV_CODEC_ID_HEVC : + c->bit_rate = 0; + if (strstr(info.vcodec.c_str(), "svt_hevc") != NULL) { + av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),51), 0); + av_opt_set_int(c->priv_data, "preset", 7, 0); + av_opt_set_int(c->priv_data, "forced-idr",1,0); + } + break; + } #endif } else { // Set AVOption @@ -801,11 +844,11 @@ void FFmpegWriter::flush_encoders() { #if (LIBAVFORMAT_VERSION_MAJOR < 58) if (info.has_video && video_codec_ctx && AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && (oc->oformat->flags & AVFMT_RAWPICTURE) && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO) return; +#else + if (info.has_video && video_codec && AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO) + return; #endif - int error_code = 0; - int stop_encoding = 1; - // FLUSH VIDEO ENCODER if (info.has_video) for (;;) { @@ -879,13 +922,9 @@ void FFmpegWriter::flush_encoders() { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::flush_encoders ERROR [" + (std::string) av_err2str(error_code) + "]", "error_code", error_code); } if (!got_packet) { - stop_encoding = 1; break; } - // Override PTS (in frames and scaled to the codec's timebase) - //pkt.pts = write_video_count; - // set the timestamp if (pkt.pts != AV_NOPTS_VALUE) pkt.pts = av_rescale_q(pkt.pts, video_codec_ctx->time_base, video_st->time_base); @@ -900,10 +939,6 @@ void FFmpegWriter::flush_encoders() { if (error_code < 0) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::flush_encoders ERROR [" + (std::string)av_err2str(error_code) + "]", "error_code", error_code); } - - // Deallocate memory (if needed) - if (video_outbuf) - av_freep(&video_outbuf); } // FLUSH AUDIO ENCODER @@ -925,10 +960,10 @@ void FFmpegWriter::flush_encoders() { pkt.pts = pkt.dts = write_audio_count; /* encode the image */ + int error_code = 0; int got_packet = 0; #if IS_FFMPEG_3_2 - avcodec_send_frame(audio_codec_ctx, NULL); - got_packet = 0; + error_code = avcodec_send_frame(audio_codec_ctx, NULL); #else error_code = avcodec_encode_audio2(audio_codec_ctx, &pkt, NULL, &got_packet); #endif @@ -936,7 +971,6 @@ void FFmpegWriter::flush_encoders() { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::flush_encoders ERROR [" + (std::string)av_err2str(error_code) + "]", "error_code", error_code); } if (!got_packet) { - stop_encoding = 1; break; } @@ -1166,20 +1200,61 @@ AVStream *FFmpegWriter::add_video_stream() { #endif /* Init video encoder options */ - if (info.video_bit_rate >= 1000) { + if (info.video_bit_rate >= 1000 +#if (LIBAVCODEC_VERSION_MAJOR >= 58) + && c->codec_id != AV_CODEC_ID_AV1 +#endif + ) { c->bit_rate = info.video_bit_rate; if (info.video_bit_rate >= 1500000) { - c->qmin = 2; - c->qmax = 30; + if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + c->qmin = 2; + c->qmax = 30; + } } // Here should be the setting for low fixed bitrate // Defaults are used because mpeg2 otherwise had problems } else { - // Check if codec supports crf + // Check if codec supports crf or qp switch (c->codec_id) { #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) #if (LIBAVCODEC_VERSION_MAJOR >= 58) case AV_CODEC_ID_AV1 : + // TODO: Set `crf` or `qp` according to bitrate, as bitrate is not supported by these encoders yet. + if (info.video_bit_rate >= 1000) { + c->bit_rate = 0; + if (strstr(info.vcodec.c_str(), "aom") != NULL) { + int calculated_quality = 35; + if (info.video_bit_rate < 500000) calculated_quality = 50; + if (info.video_bit_rate > 5000000) calculated_quality = 10; + av_opt_set_int(c->priv_data, "crf", calculated_quality, 0); + info.video_bit_rate = calculated_quality; + } else { + int calculated_quality = 50; + if (info.video_bit_rate < 500000) calculated_quality = 60; + if (info.video_bit_rate > 5000000) calculated_quality = 15; + av_opt_set_int(c->priv_data, "qp", calculated_quality, 0); + info.video_bit_rate = calculated_quality; + } // medium + } + if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) { + av_opt_set_int(c->priv_data, "preset", 6, 0); + av_opt_set_int(c->priv_data, "forced-idr",1,0); + } + else if (strstr(info.vcodec.c_str(), "rav1e") != NULL) { + av_opt_set_int(c->priv_data, "speed", 7, 0); + av_opt_set_int(c->priv_data, "tile-rows", 2, 0); + av_opt_set_int(c->priv_data, "tile-columns", 4, 0); + } + else if (strstr(info.vcodec.c_str(), "aom") != NULL) { + // Set number of tiles to a fixed value + // TODO: Allow user to chose their own number of tiles + av_opt_set_int(c->priv_data, "tile-rows", 1, 0); // log2 of number of rows + av_opt_set_int(c->priv_data, "tile-columns", 2, 0); // log2 of number of columns + av_opt_set_int(c->priv_data, "row-mt", 1, 0); // use multiple cores + av_opt_set_int(c->priv_data, "cpu-used", 3, 0); // default is 1, usable is 4 + } + //break; #endif case AV_CODEC_ID_VP9 : case AV_CODEC_ID_HEVC : @@ -1227,6 +1302,13 @@ AVStream *FFmpegWriter::add_video_stream() { st->avg_frame_rate = av_inv_q(c->time_base); st->time_base.num = info.video_timebase.num; st->time_base.den = info.video_timebase.den; +#if (LIBAVFORMAT_VERSION_MAJOR >= 58) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" + st->codec->time_base.num = info.video_timebase.num; + st->codec->time_base.den = info.video_timebase.den; + #pragma GCC diagnostic pop +#endif c->gop_size = 12; /* TODO: add this to "info"... emit one intra frame every twelve frames at most */ c->max_b_frames = 10; @@ -1520,21 +1602,31 @@ void FFmpegWriter::write_audio_packets(bool is_final) { channels_in_frame = frame->GetAudioChannelsCount(); channel_layout_in_frame = frame->ChannelsLayout(); - // Get audio sample array float *frame_samples_float = NULL; // Get samples interleaved together (c1 c2 c1 c2 c1 c2) frame_samples_float = frame->GetInterleavedAudioSamples(sample_rate_in_frame, NULL, &samples_in_frame); - // Calculate total samples total_frame_samples = samples_in_frame * channels_in_frame; - // Translate audio sample values back to 16 bit integers - for (int s = 0; s < total_frame_samples; s++, frame_position++) - // Translate sample value and copy into buffer - all_queued_samples[frame_position] = int(frame_samples_float[s] * (1 << 15)); + // Translate audio sample values back to 16 bit integers with saturation + const int16_t max16 = 32767; + const int16_t min16 = -32768; + for (int s = 0; s < total_frame_samples; s++, frame_position++) { + float valF = frame_samples_float[s] * (1 << 15); + int16_t conv; + if (valF > max16) { + conv = max16; + } else if (valF < min16) { + conv = min16; + } else { + conv = int(valF + 32768.5) - 32768; // +0.5 is for rounding + } + // Copy into buffer + all_queued_samples[frame_position] = conv; + } // Deallocate float array delete[] frame_samples_float; @@ -1656,10 +1748,11 @@ void FFmpegWriter::write_audio_packets(bool is_final) { // Determine how many samples we need int diff = 0; - if (remaining_frame_samples >= remaining_packet_samples) + if (remaining_frame_samples >= remaining_packet_samples) { diff = remaining_packet_samples; - else if (remaining_frame_samples < remaining_packet_samples) + } else { diff = remaining_frame_samples; + } // Copy frame samples into the packet samples array if (!is_final) @@ -1671,7 +1764,6 @@ void FFmpegWriter::write_audio_packets(bool is_final) { audio_input_position += diff; samples_position += diff * (av_get_bytes_per_sample(output_sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)); remaining_frame_samples -= diff; - remaining_packet_samples -= diff; // Do we have enough samples to proceed? if (audio_input_position < (audio_input_frame_size * info.channels) && !is_final) @@ -1955,10 +2047,13 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) { bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *frame_final) { #if (LIBAVFORMAT_VERSION_MAJOR >= 58) ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags", oc->oformat->flags); + + if (AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO) { #else ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags & AVFMT_RAWPICTURE", oc->oformat->flags & AVFMT_RAWPICTURE); if (oc->oformat->flags & AVFMT_RAWPICTURE) { +#endif // Raw video case. AVPacket pkt; av_init_packet(&pkt); @@ -1983,7 +2078,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra AV_FREE_PACKET(&pkt); } else -#endif { AVPacket pkt; @@ -2023,7 +2117,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra int error_code = 0; #if IS_FFMPEG_3_2 // Write video packet (latest version of FFmpeg) - int frameFinished = 0; int ret; #if HAVE_HW_ACCEL diff --git a/src/Frame.cpp b/src/Frame.cpp index 9577a7f9e..764b9651a 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -480,6 +480,11 @@ const unsigned char* Frame::GetPixels() // Get pixel data (for only a single scan-line) const unsigned char* Frame::GetPixels(int row) { + // Check for blank image + if (!image) + // Fill with black + AddColor(width, height, color); + // Return array of pixel packets return image->constScanLine(row); } @@ -829,7 +834,7 @@ void Frame::AddImage(std::shared_ptr new_image, bool only_odd_lines) if (ret) { return; } - + // Get the frame's image const GenericScopedLock lock(addingImageSection); #pragma omp critical (AddImage) @@ -979,7 +984,8 @@ void Frame::Play() return; juce::AudioDeviceManager deviceManager; - String error = deviceManager.initialise (0, /* number of input channels */ + juce::String error = deviceManager.initialise ( + 0, /* number of input channels */ 2, /* number of output channels */ 0, /* no XML settings.. */ true /* select default device on failure */); @@ -992,8 +998,8 @@ void Frame::Play() juce::AudioSourcePlayer audioSourcePlayer; deviceManager.addAudioCallback (&audioSourcePlayer); - ScopedPointer my_source; - my_source = new AudioBufferSource(audio.get()); + std::unique_ptr my_source; + my_source.reset (new AudioBufferSource (audio.get())); // Create TimeSliceThread for audio buffering juce::TimeSliceThread my_thread("Audio buffer thread"); @@ -1001,8 +1007,8 @@ void Frame::Play() // Start thread my_thread.startThread(); - AudioTransportSource transport1; - transport1.setSource (my_source, + juce::AudioTransportSource transport1; + transport1.setSource (my_source.get(), 5000, // tells it to buffer this many samples ahead &my_thread, (double) sample_rate, diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index e80f355c3..e1e5700c2 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -785,10 +785,23 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig // Create a new array (to hold all S16 audio samples for the current queued frames) int16_t* frame_samples = (int16_t*) av_malloc(sizeof(int16_t)*total_frame_samples); - // Translate audio sample values back to 16 bit integers - for (int s = 0; s < total_frame_samples; s++) - // Translate sample value and copy into buffer - frame_samples[s] = int(frame_samples_float[s] * (1 << 15)); + // Translate audio sample values back to 16 bit integers with saturation + float valF; + int16_t conv; + const int16_t max16 = 32767; + const int16_t min16 = -32768; + for (int s = 0; s < total_frame_samples; s++) { + valF = frame_samples_float[s] * (1 << 15); + if (valF > max16) + conv = max16; + else if (valF < min16) + conv = min16; + else + conv = int(valF + 32768.5) - 32768; // +0.5 is for rounding + + // Copy into buffer + frame_samples[s] = conv; + } // Deallocate float array diff --git a/src/ImageWriter.cpp b/src/ImageWriter.cpp index 376feb62a..1b7a01e9b 100644 --- a/src/ImageWriter.cpp +++ b/src/ImageWriter.cpp @@ -39,7 +39,7 @@ using namespace openshot; ImageWriter::ImageWriter(std::string path) : - path(path), cache_size(8), is_writing(false), write_video_count(0), image_quality(75), number_of_loops(1), + path(path), cache_size(8), write_video_count(0), image_quality(75), number_of_loops(1), combine_frames(true), is_open(false) { // Disable audio & video (so they can be independently enabled) diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp index 864af23db..cf64ef930 100644 --- a/src/QtImageReader.cpp +++ b/src/QtImageReader.cpp @@ -111,7 +111,12 @@ void QtImageReader::Open() info.has_audio = false; info.has_video = true; info.has_single_image = true; - info.file_size = image->byteCount(); + #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + // byteCount() is deprecated from Qt 5.10 + info.file_size = image->sizeInBytes(); + #else + info.file_size = image->byteCount(); + #endif info.vcodec = "QImage"; info.width = image->width(); info.height = image->height(); diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 61ce31e33..124058ac2 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -524,9 +524,6 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in // Loop through pixels for (int pixel = 0, byte_index=0; pixel < source_image->width() * source_image->height(); pixel++, byte_index+=4) { - // Get the alpha values from the pixel - int A = pixels[byte_index + 3]; - // Apply alpha to pixel pixels[byte_index + 3] *= alpha; } @@ -677,6 +674,8 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in y += (Settings::Instance()->MAX_HEIGHT * source_clip->location_y.GetValue(clip_frame_number)); // move in percentage of final height float shear_x = source_clip->shear_x.GetValue(clip_frame_number); float shear_y = source_clip->shear_y.GetValue(clip_frame_number); + float origin_x = source_clip->origin_x.GetValue(clip_frame_number); + float origin_y = source_clip->origin_y.GetValue(clip_frame_number); bool transformed = false; QTransform transform; @@ -684,21 +683,22 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in // Transform source image (if needed) ZmqLogger::Instance()->AppendDebugMethod("Timeline::add_layer (Build QTransform - if needed)", "source_frame->number", source_frame->number, "x", x, "y", y, "r", r, "sx", sx, "sy", sy); - if (!isEqual(r, 0)) { - // ROTATE CLIP - float origin_x = x + (scaled_source_width / 2.0); - float origin_y = y + (scaled_source_height / 2.0); - transform.translate(origin_x, origin_y); - transform.rotate(r); - transform.translate(-origin_x,-origin_y); + if (!isEqual(x, 0) || !isEqual(y, 0)) { + // TRANSLATE/MOVE CLIP + transform.translate(x, y); transformed = true; } - if (!isEqual(x, 0) || !isEqual(y, 0)) { - // TRANSLATE/MOVE CLIP - transform.translate(x, y); - transformed = true; - } + if (!isEqual(r, 0) || !isEqual(shear_x, 0) || !isEqual(shear_y, 0)) { + // ROTATE CLIP (around origin_x, origin_y) + float origin_x_value = (scaled_source_width * origin_x); + float origin_y_value = (scaled_source_height * origin_y); + transform.translate(origin_x_value, origin_y_value); + transform.rotate(r); + transform.shear(shear_x, shear_y); + transform.translate(-origin_x_value,-origin_y_value); + transformed = true; + } // SCALE CLIP (if needed) float source_width_scale = (float(source_size.width()) / float(source_image->width())) * sx; @@ -709,12 +709,6 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in transformed = true; } - if (!isEqual(shear_x, 0) || !isEqual(shear_y, 0)) { - // SHEAR HEIGHT/WIDTH - transform.shear(shear_x, shear_y); - transformed = true; - } - // Debug output ZmqLogger::Instance()->AppendDebugMethod("Timeline::add_layer (Transform: Composite Image Layer: Prepare)", "source_frame->number", source_frame->number, "new_frame->GetImage()->width()", new_frame->GetImage()->width(), "transformed", transformed); diff --git a/src/ZmqLogger.cpp b/src/ZmqLogger.cpp index 89d2798a6..103de73d7 100644 --- a/src/ZmqLogger.cpp +++ b/src/ZmqLogger.cpp @@ -71,7 +71,7 @@ ZmqLogger *ZmqLogger::Instance() } // Set the connection for this logger -void ZmqLogger::Connection(string new_connection) +void ZmqLogger::Connection(std::string new_connection) { // Create a scoped lock, allowing only a single thread to run the following code at one time const GenericScopedLock lock(loggerCriticalSection); @@ -102,7 +102,7 @@ void ZmqLogger::Connection(string new_connection) publisher->bind(connection.c_str()); } catch (zmq::error_t &e) { - cout << "ZmqLogger::Connection - Error binding to " << connection << ". Switching to an available port." << endl; + std::cout << "ZmqLogger::Connection - Error binding to " << connection << ". Switching to an available port." << std::endl; connection = "tcp://*:*"; publisher->bind(connection.c_str()); } @@ -111,7 +111,7 @@ void ZmqLogger::Connection(string new_connection) usleep(250000); } -void ZmqLogger::Log(string message) +void ZmqLogger::Log(std::string message) { if (!enabled) // Don't do anything @@ -122,23 +122,28 @@ void ZmqLogger::Log(string message) // Send message over socket (ZeroMQ) zmq::message_t reply (message.length()); - memcpy (reply.data(), message.c_str(), message.length()); + std::memcpy (reply.data(), message.c_str(), message.length()); + +#if ZMQ_VERSION > ZMQ_MAKE_VERSION(4, 3, 1) + // Set flags for immediate delivery (new API) + publisher->send(reply, zmq::send_flags::dontwait); +#else publisher->send(reply); +#endif - // Write to log file (if opened, and force it to write to disk in case of a crash) - if (log_file.is_open()) - log_file << message << std::flush; + // Also log to file, if open + LogToFile(message); } // Log message to a file (if path set) -void ZmqLogger::LogToFile(string message) +void ZmqLogger::LogToFile(std::string message) { // Write to log file (if opened, and force it to write to disk in case of a crash) if (log_file.is_open()) log_file << message << std::flush; } -void ZmqLogger::Path(string new_path) +void ZmqLogger::Path(std::string new_path) { // Update path file_path = new_path; @@ -148,14 +153,14 @@ void ZmqLogger::Path(string new_path) log_file.close(); // Open file (write + append) - log_file.open (file_path.c_str(), ios::out | ios::app); + log_file.open (file_path.c_str(), std::ios::out | std::ios::app); // Get current time and log first message - time_t now = time(0); - tm* localtm = localtime(&now); - log_file << "------------------------------------------" << endl; - log_file << "libopenshot logging: " << asctime(localtm); - log_file << "------------------------------------------" << endl; + std::time_t now = std::time(0); + std::tm* localtm = std::localtime(&now); + log_file << "------------------------------------------" << std::endl; + log_file << "libopenshot logging: " << std::asctime(localtm); + log_file << "------------------------------------------" << std::endl; } void ZmqLogger::Close() @@ -176,13 +181,13 @@ void ZmqLogger::Close() } // Append debug information -void ZmqLogger::AppendDebugMethod(string method_name, - string arg1_name, float arg1_value, - string arg2_name, float arg2_value, - string arg3_name, float arg3_value, - string arg4_name, float arg4_value, - string arg5_name, float arg5_value, - string arg6_name, float arg6_value) +void ZmqLogger::AppendDebugMethod(std::string method_name, + std::string arg1_name, float arg1_value, + std::string arg2_name, float arg2_value, + std::string arg3_name, float arg3_value, + std::string arg4_name, float arg4_value, + std::string arg5_name, float arg5_value, + std::string arg6_name, float arg6_value) { if (!enabled) // Don't do anything @@ -192,8 +197,8 @@ void ZmqLogger::AppendDebugMethod(string method_name, // Create a scoped lock, allowing only a single thread to run the following code at one time const GenericScopedLock lock(loggerCriticalSection); - stringstream message; - message << fixed << setprecision(4); + std::stringstream message; + message << std::fixed << std::setprecision(4); message << method_name << " ("; // Add attributes to method JSON diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 21405f637..6d7ce79ea 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -26,81 +26,99 @@ ############### SWIG PYTHON BINDINGS ################ -FIND_PACKAGE(SWIG 3.0 REQUIRED) -INCLUDE(${SWIG_USE_FILE}) +find_package(SWIG 3.0 REQUIRED) +include(${SWIG_USE_FILE}) ### Enable some legacy SWIG behaviors, in newer CMAKEs if (POLICY CMP0078) - cmake_policy(SET CMP0078 OLD) + cmake_policy(SET CMP0078 OLD) endif() if (POLICY CMP0086) - cmake_policy(SET CMP0086 OLD) + cmake_policy(SET CMP0086 OLD) endif() -FIND_PACKAGE(PythonInterp 3) -FIND_PACKAGE(PythonLibs 3) -if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) - - ### Include Python header files - INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}) - INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - - ### Enable C++ support in SWIG - set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) - set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) - - ### Suppress a ton of warnings in the generated SWIG C++ code - set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ --Wno-unused-parameter -Wno-catch-value -Wno-sign-compare -Wno-ignored-qualifiers") - separate_arguments(sw_flags UNIX_COMMAND ${SWIG_CXX_FLAGS}) - set_property(SOURCE openshot.i PROPERTY GENERATED_COMPILE_OPTIONS ${sw_flags}) - - ### Take include dirs from target, automatically if possible - if (CMAKE_VERSION VERSION_GREATER 3.13) - set_property(SOURCE openshot.i PROPERTY USE_TARGET_INCLUDE_DIRECTORIES True) - else () - set_property(SOURCE openshot.i PROPERTY INCLUDE_DIRECTORIES $) - endif () - - ### Add the SWIG interface file (which defines all the SWIG methods) - if (CMAKE_VERSION VERSION_LESS 3.8.0) - swig_add_module(pyopenshot python openshot.i) - else() - swig_add_library(pyopenshot LANGUAGE python SOURCES openshot.i) - endif() - - ### Set output name of target - set_target_properties(${SWIG_MODULE_pyopenshot_REAL_NAME} PROPERTIES - PREFIX "_" OUTPUT_NAME "openshot") - - ### Link the new python wrapper library with libopenshot - target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} - PUBLIC ${PYTHON_LIBRARIES} openshot) - - ### Check if the following Debian-friendly python module path exists - SET(PYTHON_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/dist-packages") - if (NOT EXISTS ${PYTHON_MODULE_PATH}) - - ### Calculate the python module path (using distutils) - execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ -from distutils.sysconfig import get_python_lib; \ -print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )" - OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE ) - - GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH - "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) - FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH - ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) - SET(PYTHON_MODULE_PATH ${_ABS_PYTHON_MODULE_PATH}) - endif() - message("PYTHON_MODULE_PATH: ${PYTHON_MODULE_PATH}") - - ############### INSTALL HEADERS & LIBRARY ################ - ### Install Python bindings - INSTALL(TARGETS ${SWIG_MODULE_pyopenshot_REAL_NAME} - LIBRARY DESTINATION ${PYTHON_MODULE_PATH} ) - INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/openshot.py - DESTINATION ${PYTHON_MODULE_PATH} ) +find_package(PythonInterp 3) +find_package(PythonLibs 3) + +if (NOT PYTHONLIBS_FOUND OR NOT PYTHONINTERP_FOUND) + return() +endif() + +### Include Python header files +include_directories(${PYTHON_INCLUDE_PATH}) + +if (CMAKE_VERSION VERSION_LESS 3.12) + ### Include project headers + include_directories( + "${PROJECT_SOURCE_DIR}/include" + "${PROJECT_BINARY_DIR}/include") +endif() +### Enable C++ support in SWIG +set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) +set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) + +### Suppress a ton of warnings in the generated SWIG C++ code +set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function \ + -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ + -Wno-unused-parameter -Wno-catch-value -Wno-sign-compare -Wno-ignored-qualifiers") +separate_arguments(sw_flags UNIX_COMMAND ${SWIG_CXX_FLAGS}) +set_property(SOURCE openshot.i PROPERTY GENERATED_COMPILE_OPTIONS ${sw_flags}) + +### Take include dirs from target, automatically if possible +if (CMAKE_VERSION VERSION_GREATER 3.13) + set_property(SOURCE openshot.i PROPERTY USE_TARGET_INCLUDE_DIRECTORIES True) +elseif (CMAKE_VERSION VERSION_GREATER 3.12) + set_property(SOURCE openshot.i PROPERTY + INCLUDE_DIRECTORIES $) endif () + +### Add the SWIG interface file (which defines all the SWIG methods) +if (CMAKE_VERSION VERSION_LESS 3.8.0) + swig_add_module(pyopenshot python openshot.i) +else() + swig_add_library(pyopenshot LANGUAGE python SOURCES openshot.i) +endif() + +### Set output name of target +set_target_properties(${SWIG_MODULE_pyopenshot_REAL_NAME} PROPERTIES + PREFIX "_" OUTPUT_NAME "openshot") + +### Link the new python wrapper library with libopenshot +target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} PUBLIC + ${PYTHON_LIBRARIES} openshot) + +######### INSTALL PATH ######## +if (NOT DEFINED PYTHON_MODULE_PATH AND DEFINED $ENV{PYTHON_MODULE_PATH}) + set(PYTHON_MODULE_PATH $ENV{PYTHON_MODULE_PATH}) +endif() + +if (NOT DEFINED PYTHON_MODULE_PATH) + if (WIN32 OR APPLE) + set (PYTHON_MODULE_PATH "python") + endif() + + if (UNIX AND NOT APPLE) + ### Check if the following Debian-friendly python module path exists + set(PYTHON_MODULE_PATH + "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/dist-packages") + + if (NOT EXISTS "${CMAKE_INSTALL_PREFIX}/${PYTHON_MODULE_PATH}") + ### Calculate the python module path (using distutils) + execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ +from distutils.sysconfig import get_python_lib; \ +print( get_python_lib( plat_specific=True, prefix='' ) )" + OUTPUT_VARIABLE PYTHON_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) + endif() + endif() +endif() + +message(STATUS "PYTHON_MODULE_PATH: ${CMAKE_INSTALL_PREFIX}/${PYTHON_MODULE_PATH}") + +############### INSTALL HEADERS & LIBRARY ################ +### Install Python bindings +install(TARGETS ${SWIG_MODULE_pyopenshot_REAL_NAME} + DESTINATION ${PYTHON_MODULE_PATH} ) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/openshot.py + DESTINATION ${PYTHON_MODULE_PATH} ) diff --git a/src/bindings/python/openshot.i b/src/bindings/python/openshot.i index 44b1953e1..53e514c15 100644 --- a/src/bindings/python/openshot.i +++ b/src/bindings/python/openshot.i @@ -59,57 +59,57 @@ %{ #include "OpenShotVersion.h" -#include "../../../include/ReaderBase.h" -#include "../../../include/WriterBase.h" -#include "../../../include/CacheBase.h" -#include "../../../include/CacheDisk.h" -#include "../../../include/CacheMemory.h" -#include "../../../include/ChannelLayouts.h" -#include "../../../include/ChunkReader.h" -#include "../../../include/ChunkWriter.h" -#include "../../../include/ClipBase.h" -#include "../../../include/Clip.h" -#include "../../../include/Coordinate.h" -#include "../../../include/Color.h" -#include "../../../include/DummyReader.h" -#include "../../../include/EffectBase.h" -#include "../../../include/Effects.h" -#include "../../../include/EffectInfo.h" -#include "../../../include/Enums.h" -#include "../../../include/Exceptions.h" -#include "../../../include/FFmpegReader.h" -#include "../../../include/FFmpegWriter.h" -#include "../../../include/Fraction.h" -#include "../../../include/Frame.h" -#include "../../../include/FrameMapper.h" -#include "../../../include/PlayerBase.h" -#include "../../../include/Point.h" -#include "../../../include/Profiles.h" -#include "../../../include/QtHtmlReader.h" -#include "../../../include/QtImageReader.h" -#include "../../../include/QtPlayer.h" -#include "../../../include/QtTextReader.h" -#include "../../../include/KeyFrame.h" -#include "../../../include/RendererBase.h" -#include "../../../include/Settings.h" -#include "../../../include/Timeline.h" -#include "../../../include/ZmqLogger.h" -#include "../../../include/AudioDeviceInfo.h" +#include "ReaderBase.h" +#include "WriterBase.h" +#include "CacheBase.h" +#include "CacheDisk.h" +#include "CacheMemory.h" +#include "ChannelLayouts.h" +#include "ChunkReader.h" +#include "ChunkWriter.h" +#include "ClipBase.h" +#include "Clip.h" +#include "Coordinate.h" +#include "Color.h" +#include "DummyReader.h" +#include "EffectBase.h" +#include "Effects.h" +#include "EffectInfo.h" +#include "Enums.h" +#include "Exceptions.h" +#include "FFmpegReader.h" +#include "FFmpegWriter.h" +#include "Fraction.h" +#include "Frame.h" +#include "FrameMapper.h" +#include "PlayerBase.h" +#include "Point.h" +#include "Profiles.h" +#include "QtHtmlReader.h" +#include "QtImageReader.h" +#include "QtPlayer.h" +#include "QtTextReader.h" +#include "KeyFrame.h" +#include "RendererBase.h" +#include "Settings.h" +#include "Timeline.h" +#include "ZmqLogger.h" +#include "AudioDeviceInfo.h" %} #ifdef USE_BLACKMAGIC %{ - #include "../../../include/DecklinkReader.h" - #include "../../../include/DecklinkWriter.h" + #include "DecklinkReader.h" + #include "DecklinkWriter.h" %} #endif #ifdef USE_IMAGEMAGICK %{ - #include "../../../include/ImageReader.h" - #include "../../../include/ImageWriter.h" - #include "../../../include/TextReader.h" + #include "ImageReader.h" + #include "ImageWriter.h" + #include "TextReader.h" %} #endif @@ -166,68 +166,68 @@ } %include "OpenShotVersion.h" -%include "../../../include/ReaderBase.h" -%include "../../../include/WriterBase.h" -%include "../../../include/CacheBase.h" -%include "../../../include/CacheDisk.h" -%include "../../../include/CacheMemory.h" -%include "../../../include/ChannelLayouts.h" -%include "../../../include/ChunkReader.h" -%include "../../../include/ChunkWriter.h" -%include "../../../include/ClipBase.h" -%include "../../../include/Clip.h" -%include "../../../include/Coordinate.h" -%include "../../../include/Color.h" +%include "ReaderBase.h" +%include "WriterBase.h" +%include "CacheBase.h" +%include "CacheDisk.h" +%include "CacheMemory.h" +%include "ChannelLayouts.h" +%include "ChunkReader.h" +%include "ChunkWriter.h" +%include "ClipBase.h" +%include "Clip.h" +%include "Coordinate.h" +%include "Color.h" #ifdef USE_BLACKMAGIC - %include "../../../include/DecklinkReader.h" - %include "../../../include/DecklinkWriter.h" + %include "DecklinkReader.h" + %include "DecklinkWriter.h" #endif -%include "../../../include/DummyReader.h" -%include "../../../include/EffectBase.h" -%include "../../../include/Effects.h" -%include "../../../include/EffectInfo.h" -%include "../../../include/Enums.h" -%include "../../../include/Exceptions.h" -%include "../../../include/FFmpegReader.h" -%include "../../../include/FFmpegWriter.h" -%include "../../../include/Fraction.h" -%include "../../../include/Frame.h" -%include "../../../include/FrameMapper.h" -%include "../../../include/PlayerBase.h" -%include "../../../include/Point.h" -%include "../../../include/Profiles.h" -%include "../../../include/QtHtmlReader.h" -%include "../../../include/QtImageReader.h" -%include "../../../include/QtPlayer.h" -%include "../../../include/QtTextReader.h" -%include "../../../include/KeyFrame.h" -%include "../../../include/RendererBase.h" -%include "../../../include/Settings.h" -%include "../../../include/Timeline.h" -%include "../../../include/ZmqLogger.h" -%include "../../../include/AudioDeviceInfo.h" +%include "DummyReader.h" +%include "EffectBase.h" +%include "Effects.h" +%include "EffectInfo.h" +%include "Enums.h" +%include "Exceptions.h" +%include "FFmpegReader.h" +%include "FFmpegWriter.h" +%include "Fraction.h" +%include "Frame.h" +%include "FrameMapper.h" +%include "PlayerBase.h" +%include "Point.h" +%include "Profiles.h" +%include "QtHtmlReader.h" +%include "QtImageReader.h" +%include "QtPlayer.h" +%include "QtTextReader.h" +%include "KeyFrame.h" +%include "RendererBase.h" +%include "Settings.h" +%include "Timeline.h" +%include "ZmqLogger.h" +%include "AudioDeviceInfo.h" #ifdef USE_IMAGEMAGICK - %include "../../../include/ImageReader.h" - %include "../../../include/ImageWriter.h" - %include "../../../include/TextReader.h" + %include "ImageReader.h" + %include "ImageWriter.h" + %include "TextReader.h" #endif /* Effects */ -%include "../../../include/effects/Bars.h" -%include "../../../include/effects/Blur.h" -%include "../../../include/effects/Brightness.h" -%include "../../../include/effects/ChromaKey.h" -%include "../../../include/effects/ColorShift.h" -%include "../../../include/effects/Crop.h" -%include "../../../include/effects/Deinterlace.h" -%include "../../../include/effects/Hue.h" -%include "../../../include/effects/Mask.h" -%include "../../../include/effects/Negate.h" -%include "../../../include/effects/Pixelate.h" -%include "../../../include/effects/Saturation.h" -%include "../../../include/effects/Shift.h" -%include "../../../include/effects/Wave.h" +%include "effects/Bars.h" +%include "effects/Blur.h" +%include "effects/Brightness.h" +%include "effects/ChromaKey.h" +%include "effects/ColorShift.h" +%include "effects/Crop.h" +%include "effects/Deinterlace.h" +%include "effects/Hue.h" +%include "effects/Mask.h" +%include "effects/Negate.h" +%include "effects/Pixelate.h" +%include "effects/Saturation.h" +%include "effects/Shift.h" +%include "effects/Wave.h" /* Wrap std templates (list, vector, etc...) */ diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt index bf7e6421f..2ec16dcf3 100644 --- a/src/bindings/ruby/CMakeLists.txt +++ b/src/bindings/ruby/CMakeLists.txt @@ -25,8 +25,8 @@ ################################################################################ ############### RUBY BINDINGS ################ -FIND_PACKAGE(SWIG 3.0 REQUIRED) -INCLUDE(${SWIG_USE_FILE}) +find_package(SWIG 3.0 REQUIRED) +include(${SWIG_USE_FILE}) ### Enable some legacy SWIG behaviors, in newer CMAKEs if (POLICY CMP0078) @@ -36,56 +36,99 @@ if (POLICY CMP0086) cmake_policy(SET CMP0086 OLD) endif() -FIND_PACKAGE(Ruby) -IF (RUBY_FOUND) - - ### Include the Ruby header files - INCLUDE_DIRECTORIES(${RUBY_INCLUDE_DIRS}) - INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - - ### Enable C++ in SWIG - set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) - set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) - - ### Suppress a ton of warnings in the generated SWIG C++ code - set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ --Wno-unused-parameter -Wno-catch-value -Wno-sign-compare -Wno-ignored-qualifiers") - separate_arguments(sw_flags UNIX_COMMAND ${SWIG_CXX_FLAGS}) - set_property(SOURCE openshot.i PROPERTY GENERATED_COMPILE_OPTIONS ${sw_flags}) - - ### Take include dirs from target, automatically if possible - if (CMAKE_VERSION VERSION_GREATER 3.13) - set_property(SOURCE openshot.i PROPERTY USE_TARGET_INCLUDE_DIRECTORIES True) - else () - set_property(SOURCE openshot.i PROPERTY INCLUDE_DIRECTORIES $) - endif () - - ### Add the SWIG interface file (which defines all the SWIG methods) - if (CMAKE_VERSION VERSION_LESS 3.8.0) - swig_add_module(rbopenshot ruby openshot.i) - else() - swig_add_library(rbopenshot LANGUAGE ruby SOURCES openshot.i) - endif() - - ### Set name of target (with no prefix, since Ruby does not like that) - SET_TARGET_PROPERTIES(${SWIG_MODULE_rbopenshot_REAL_NAME} PROPERTIES - PREFIX "" OUTPUT_NAME "openshot") - - ### Link the new Ruby wrapper library with libopenshot - target_link_libraries(${SWIG_MODULE_rbopenshot_REAL_NAME} - ${RUBY_LIBRARY} openshot) - - ### FIND THE RUBY INTERPRETER (AND THE LOAD_PATH FOLDER) - EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} - -r rbconfig -e "print RbConfig::CONFIG['vendorarchdir']" - OUTPUT_VARIABLE RUBY_VENDOR_ARCH_DIR) - MESSAGE(STATUS "Ruby executable: ${RUBY_EXECUTABLE}") - MESSAGE(STATUS "Ruby vendor arch dir: ${RUBY_VENDOR_ARCH_DIR}") - MESSAGE(STATUS "Ruby include path: ${RUBY_INCLUDE_PATH}") - - ############### INSTALL HEADERS & LIBRARY ################ - # Install Ruby bindings - install(TARGETS ${SWIG_MODULE_rbopenshot_REAL_NAME} - LIBRARY DESTINATION ${RUBY_VENDOR_ARCH_DIR} ) - -ENDIF (RUBY_FOUND) +find_package(Ruby) +if (NOT RUBY_FOUND) + return() +endif() + +### Ruby 2.7.0 made API changes that are incompatible with versions of +### SWIG prior to 4.0.3 +option(SILENCE_RUBY_VERSION_WARNING + "Don't warn about possible SWIG incompatibilities with Ruby 2.7.0+" OFF) + +if (${RUBY_VERSION} VERSION_GREATER 2.6.9 AND ${SWIG_VERSION} VERSION_LESS 4.0.3) + if (NOT ${SILENCE_RUBY_VERSION_WARNING}) + message(WARNING "\ +Ruby 2.7.0+ detected, building the libopenshot Ruby API bindings \ +requires either SWIG 4.0.3 or an older version patched with this commit: \ +https://github.com/swig/swig/commit/5542cc228ad10bdc5c91107afb77c808c43bf2a4 \ +(Recent Fedora and Ubuntu distro packages of SWIG 4.0.1 have already been \ +patched.)") + message(STATUS "To disable the previous warning, add \ +-DSILENCE_RUBY_VERSION_WARNING:BOOL=1 to the cmake command line, \ +or enable the option in the CMake GUI.") + endif() +endif() + +### Include the Ruby header files +include_directories(${RUBY_INCLUDE_DIRS}) + +if (CMAKE_VERSION VERSION_LESS 3.12) + ### Include Ruby header files and project headers + include_directories( + "${PROJECT_SOURCE_DIR}/include" + "${PROJECT_BINARY_DIR}/include") +endif() + +### Enable C++ in SWIG +set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) +set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) + +### Unbreak std::isfinite() +add_definitions(-DHAVE_ISFINITE=1) + +### Suppress a ton of warnings in the generated SWIG C++ code +set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function \ + -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ + -Wno-unused-parameter -Wno-catch-value -Wno-sign-compare -Wno-ignored-qualifiers") +separate_arguments(sw_flags UNIX_COMMAND ${SWIG_CXX_FLAGS}) +set_property(SOURCE openshot.i PROPERTY GENERATED_COMPILE_OPTIONS ${sw_flags}) + +### Take include dirs from target, automatically if possible +if (CMAKE_VERSION VERSION_GREATER 3.13) + set_property(SOURCE openshot.i PROPERTY USE_TARGET_INCLUDE_DIRECTORIES True) +else () + set_property(SOURCE openshot.i PROPERTY + INCLUDE_DIRECTORIES $) +endif () + +### Add the SWIG interface file (which defines all the SWIG methods) +if (CMAKE_VERSION VERSION_LESS 3.8.0) + swig_add_module(rbopenshot ruby openshot.i) +else() + swig_add_library(rbopenshot LANGUAGE ruby SOURCES openshot.i) +endif() + +### Link the new Ruby wrapper library with libopenshot +target_link_libraries(${SWIG_MODULE_rbopenshot_REAL_NAME} PUBLIC + ${RUBY_LIBRARY} openshot) + +######### INSTALL PATH ######## +if (NOT DEFINED RUBY_MODULE_PATH AND DEFINED $ENV{RUBY_MODULE_PATH}) + set(RUBY_MODULE_PATH $ENV{RUBY_MODULE_PATH}) +endif() + +if (NOT DEFINED RUBY_MODULE_PATH) + if (WIN32 OR APPLE) + set (RUBY_MODULE_PATH "ruby") + endif() + + if (UNIX AND NOT APPLE) + ### FIND THE RUBY INTERPRETER (AND THE LOAD_PATH FOLDER) + execute_process(COMMAND ${RUBY_EXECUTABLE} -r rbconfig + -e "dir = RbConfig::CONFIG['vendorarchdir']" + -e "dir.start_with?(RbConfig::CONFIG['prefix']) && dir.sub!(RbConfig::CONFIG['prefix']+'/', '')" + -e "p dir" + OUTPUT_VARIABLE RUBY_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) + # Ruby quotes its output strings + string(REPLACE "\"" "" RUBY_MODULE_PATH "${RUBY_MODULE_PATH}") + endif() +endif() + +message(STATUS "RUBY_MODULE_PATH: ${CMAKE_INSTALL_PREFIX}/${RUBY_MODULE_PATH}") + +############### INSTALL HEADERS & LIBRARY ################ +# Install Ruby bindings +install(TARGETS ${SWIG_MODULE_rbopenshot_REAL_NAME} + DESTINATION ${RUBY_MODULE_PATH} ) diff --git a/src/bindings/ruby/openshot.i b/src/bindings/ruby/openshot.i index a08ac9ae9..2f24d2200 100644 --- a/src/bindings/ruby/openshot.i +++ b/src/bindings/ruby/openshot.i @@ -70,42 +70,42 @@ namespace std { #undef RSHIFT #endif #include "OpenShotVersion.h" -#include "../../../include/ReaderBase.h" -#include "../../../include/WriterBase.h" -#include "../../../include/CacheBase.h" -#include "../../../include/CacheDisk.h" -#include "../../../include/CacheMemory.h" -#include "../../../include/ChannelLayouts.h" -#include "../../../include/ChunkReader.h" -#include "../../../include/ChunkWriter.h" -#include "../../../include/ClipBase.h" -#include "../../../include/Clip.h" -#include "../../../include/Coordinate.h" -#include "../../../include/Color.h" -#include "../../../include/DummyReader.h" -#include "../../../include/EffectBase.h" -#include "../../../include/Effects.h" -#include "../../../include/EffectInfo.h" -#include "../../../include/Enums.h" -#include "../../../include/Exceptions.h" -#include "../../../include/FFmpegReader.h" -#include "../../../include/FFmpegWriter.h" -#include "../../../include/Fraction.h" -#include "../../../include/Frame.h" -#include "../../../include/FrameMapper.h" -#include "../../../include/PlayerBase.h" -#include "../../../include/Point.h" -#include "../../../include/Profiles.h" -#include "../../../include/QtHtmlReader.h" -#include "../../../include/QtImageReader.h" -#include "../../../include/QtPlayer.h" -#include "../../../include/QtTextReader.h" -#include "../../../include/KeyFrame.h" -#include "../../../include/RendererBase.h" -#include "../../../include/Settings.h" -#include "../../../include/Timeline.h" -#include "../../../include/ZmqLogger.h" -#include "../../../include/AudioDeviceInfo.h" +#include "ReaderBase.h" +#include "WriterBase.h" +#include "CacheBase.h" +#include "CacheDisk.h" +#include "CacheMemory.h" +#include "ChannelLayouts.h" +#include "ChunkReader.h" +#include "ChunkWriter.h" +#include "ClipBase.h" +#include "Clip.h" +#include "Coordinate.h" +#include "Color.h" +#include "DummyReader.h" +#include "EffectBase.h" +#include "Effects.h" +#include "EffectInfo.h" +#include "Enums.h" +#include "Exceptions.h" +#include "FFmpegReader.h" +#include "FFmpegWriter.h" +#include "Fraction.h" +#include "Frame.h" +#include "FrameMapper.h" +#include "PlayerBase.h" +#include "Point.h" +#include "Profiles.h" +#include "QtHtmlReader.h" +#include "QtImageReader.h" +#include "QtPlayer.h" +#include "QtTextReader.h" +#include "KeyFrame.h" +#include "RendererBase.h" +#include "Settings.h" +#include "Timeline.h" +#include "ZmqLogger.h" +#include "AudioDeviceInfo.h" /* Move FFmpeg's RSHIFT to FF_RSHIFT, if present */ #ifdef RSHIFT @@ -120,42 +120,42 @@ namespace std { #ifdef USE_BLACKMAGIC %{ - #include "../../../include/DecklinkReader.h" - #include "../../../include/DecklinkWriter.h" + #include "DecklinkReader.h" + #include "DecklinkWriter.h" %} #endif #ifdef USE_IMAGEMAGICK %{ - #include "../../../include/ImageReader.h" - #include "../../../include/ImageWriter.h" - #include "../../../include/TextReader.h" + #include "ImageReader.h" + #include "ImageWriter.h" + #include "TextReader.h" %} #endif %include "OpenShotVersion.h" -%include "../../../include/ReaderBase.h" -%include "../../../include/WriterBase.h" -%include "../../../include/CacheBase.h" -%include "../../../include/CacheDisk.h" -%include "../../../include/CacheMemory.h" -%include "../../../include/ChannelLayouts.h" -%include "../../../include/ChunkReader.h" -%include "../../../include/ChunkWriter.h" -%include "../../../include/ClipBase.h" -%include "../../../include/Clip.h" -%include "../../../include/Coordinate.h" -%include "../../../include/Color.h" +%include "ReaderBase.h" +%include "WriterBase.h" +%include "CacheBase.h" +%include "CacheDisk.h" +%include "CacheMemory.h" +%include "ChannelLayouts.h" +%include "ChunkReader.h" +%include "ChunkWriter.h" +%include "ClipBase.h" +%include "Clip.h" +%include "Coordinate.h" +%include "Color.h" #ifdef USE_BLACKMAGIC - %include "../../../include/DecklinkReader.h" - %include "../../../include/DecklinkWriter.h" + %include "DecklinkReader.h" + %include "DecklinkWriter.h" #endif -%include "../../../include/DummyReader.h" -%include "../../../include/EffectBase.h" -%include "../../../include/Effects.h" -%include "../../../include/EffectInfo.h" -%include "../../../include/Enums.h" -%include "../../../include/Exceptions.h" +%include "DummyReader.h" +%include "EffectBase.h" +%include "Effects.h" +%include "EffectInfo.h" +%include "Enums.h" +%include "Exceptions.h" /* Ruby and FFmpeg define competing RSHIFT macros, * so we move Ruby's out of the way for now. We'll @@ -166,8 +166,8 @@ namespace std { #undef RSHIFT #endif -%include "../../../include/FFmpegReader.h" -%include "../../../include/FFmpegWriter.h" +%include "FFmpegReader.h" +%include "FFmpegWriter.h" /* Move FFmpeg's RSHIFT to FF_RSHIFT, if present */ #ifdef RSHIFT @@ -179,45 +179,45 @@ namespace std { #define RSHIFT(a, b) RB_RSHIFT(a, b) #endif -%include "../../../include/Fraction.h" -%include "../../../include/Frame.h" -%include "../../../include/FrameMapper.h" -%include "../../../include/PlayerBase.h" -%include "../../../include/Point.h" -%include "../../../include/Profiles.h" -%include "../../../include/QtHtmlReader.h" -%include "../../../include/QtImageReader.h" -%include "../../../include/QtPlayer.h" -%include "../../../include/QtTextReader.h" -%include "../../../include/KeyFrame.h" -%include "../../../include/RendererBase.h" -%include "../../../include/Settings.h" -%include "../../../include/Timeline.h" -%include "../../../include/ZmqLogger.h" -%include "../../../include/AudioDeviceInfo.h" +%include "Fraction.h" +%include "Frame.h" +%include "FrameMapper.h" +%include "PlayerBase.h" +%include "Point.h" +%include "Profiles.h" +%include "QtHtmlReader.h" +%include "QtImageReader.h" +%include "QtPlayer.h" +%include "QtTextReader.h" +%include "KeyFrame.h" +%include "RendererBase.h" +%include "Settings.h" +%include "Timeline.h" +%include "ZmqLogger.h" +%include "AudioDeviceInfo.h" #ifdef USE_IMAGEMAGICK - %include "../../../include/ImageReader.h" - %include "../../../include/ImageWriter.h" - %include "../../../include/TextReader.h" + %include "ImageReader.h" + %include "ImageWriter.h" + %include "TextReader.h" #endif /* Effects */ -%include "../../../include/effects/Bars.h" -%include "../../../include/effects/Blur.h" -%include "../../../include/effects/Brightness.h" -%include "../../../include/effects/ChromaKey.h" -%include "../../../include/effects/ColorShift.h" -%include "../../../include/effects/Crop.h" -%include "../../../include/effects/Deinterlace.h" -%include "../../../include/effects/Hue.h" -%include "../../../include/effects/Mask.h" -%include "../../../include/effects/Negate.h" -%include "../../../include/effects/Pixelate.h" -%include "../../../include/effects/Saturation.h" -%include "../../../include/effects/Shift.h" -%include "../../../include/effects/Wave.h" +%include "effects/Bars.h" +%include "effects/Blur.h" +%include "effects/Brightness.h" +%include "effects/ChromaKey.h" +%include "effects/ColorShift.h" +%include "effects/Crop.h" +%include "effects/Deinterlace.h" +%include "effects/Hue.h" +%include "effects/Mask.h" +%include "effects/Negate.h" +%include "effects/Pixelate.h" +%include "effects/Saturation.h" +%include "effects/Shift.h" +%include "effects/Wave.h" /* Wrap std templates (list, vector, etc...) */ diff --git a/src/bindings/ruby/test.rb b/src/examples/Example.rb similarity index 100% rename from src/bindings/ruby/test.rb rename to src/examples/Example.rb diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 480dfb3d3..f75d8ab17 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -36,6 +36,11 @@ if(WIN32) set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -include cmath") endif() +if (APPLE) + # Prevent compiling with __cxx11 + add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) +endif() + ################### UNITTEST++ ##################### # Find UnitTest++ libraries (used for unit testing) find_package(UnitTest++) @@ -109,6 +114,7 @@ set(OPENSHOT_TEST_FILES Clip_Tests.cpp Color_Tests.cpp Coordinate_Tests.cpp + DummyReader_Tests.cpp ReaderBase_Tests.cpp ImageWriter_Tests.cpp FFmpegReader_Tests.cpp diff --git a/tests/DummyReader_Tests.cpp b/tests/DummyReader_Tests.cpp new file mode 100644 index 000000000..c72be2d9f --- /dev/null +++ b/tests/DummyReader_Tests.cpp @@ -0,0 +1,149 @@ +/** + * @file + * @brief Unit tests for openshot::DummyReader + * @author Jonathan Thomas + * + * @ref License + */ + +/* LICENSE + * + * Copyright (c) 2008-2019 OpenShot Studios, LLC + * . This file is part of + * OpenShot Library (libopenshot), an open-source project dedicated to + * delivering high quality video editing and animation solutions to the + * world. For more information visit . + * + * OpenShot Library (libopenshot) is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * OpenShot Library (libopenshot) 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with OpenShot Library. If not, see . + */ + +#include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 + +#include "../include/OpenShot.h" + +using namespace std; +using namespace openshot; + +TEST (DummyReader_Basic_Constructor) { + // Create a default fraction (should be 1/1) + openshot::DummyReader r; + r.Open(); // Open the reader + + // Check values + CHECK_EQUAL(1280, r.info.width); + CHECK_EQUAL(768, r.info.height); + CHECK_EQUAL(24, r.info.fps.num); + CHECK_EQUAL(1, r.info.fps.den); + CHECK_EQUAL(44100, r.info.sample_rate); + CHECK_EQUAL(2, r.info.channels); + CHECK_EQUAL(30.0, r.info.duration); +} + +TEST (DummyReader_Constructor) { + // Create a default fraction (should be 1/1) + openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 60.0); + r.Open(); // Open the reader + + // Check values + CHECK_EQUAL(1920, r.info.width); + CHECK_EQUAL(1080, r.info.height); + CHECK_EQUAL(30, r.info.fps.num); + CHECK_EQUAL(1, r.info.fps.den); + CHECK_EQUAL(44100, r.info.sample_rate); + CHECK_EQUAL(2, r.info.channels); + CHECK_EQUAL(60.0, r.info.duration); +} + +TEST (DummyReader_Blank_Frame) { + // Create a default fraction (should be 1/1) + openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0); + r.Open(); // Open the reader + + // Get a blank frame (because we have not passed a Cache object (full of Frame objects) to the constructor + // Check values + CHECK_EQUAL(1, r.GetFrame(1)->number); + CHECK_EQUAL(1, r.GetFrame(1)->GetPixels(700)[700] == 0); // black pixel + CHECK_EQUAL(1, r.GetFrame(1)->GetPixels(701)[701] == 0); // black pixel +} + +TEST (DummyReader_Fake_Frame) { + + // Create cache object to hold test frames + CacheMemory cache; + + // Let's create some test frames + for (int64_t frame_number = 1; frame_number <= 30; frame_number++) { + // Create blank frame (with specific frame #, samples, and channels) + // Sample count should be 44100 / 30 fps = 1470 samples per frame + int sample_count = 1470; + std::shared_ptr f(new openshot::Frame(frame_number, sample_count, 2)); + + // Create test samples with incrementing value + float *audio_buffer = new float[sample_count]; + for (int64_t sample_number = 0; sample_number < sample_count; sample_number++) { + // Generate an incrementing audio sample value (just as an example) + audio_buffer[sample_number] = float(frame_number) + (float(sample_number) / float(sample_count)); + } + + // Add custom audio samples to Frame (bool replaceSamples, int destChannel, int destStartSample, const float* source, + f->AddAudio(true, 0, 0, audio_buffer, sample_count, 1.0); // add channel 1 + f->AddAudio(true, 1, 0, audio_buffer, sample_count, 1.0); // add channel 2 + + // Add test frame to dummy reader + cache.Add(f); + } + + // Create a default fraction (should be 1/1) + openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0, &cache); + r.Open(); // Open the reader + + // Verify our artificial audio sample data is correct + CHECK_EQUAL(1, r.GetFrame(1)->number); + CHECK_EQUAL(1, r.GetFrame(1)->GetAudioSamples(0)[0]); + CHECK_CLOSE(1.00068033, r.GetFrame(1)->GetAudioSamples(0)[1], 0.00001); + CHECK_CLOSE(1.00136054, r.GetFrame(1)->GetAudioSamples(0)[2], 0.00001); + CHECK_EQUAL(2, r.GetFrame(2)->GetAudioSamples(0)[0]); + CHECK_CLOSE(2.00068033, r.GetFrame(2)->GetAudioSamples(0)[1], 0.00001); + CHECK_CLOSE(2.00136054, r.GetFrame(2)->GetAudioSamples(0)[2], 0.00001); + + // Clean up + cache.Clear(); + r.Close(); +} + +TEST (DummyReader_Invalid_Fake_Frame) { + // Create fake frames (with specific frame #, samples, and channels) + std::shared_ptr f1(new openshot::Frame(1, 1470, 2)); + std::shared_ptr f2(new openshot::Frame(2, 1470, 2)); + + // Add test frames to cache object + CacheMemory cache; + cache.Add(f1); + cache.Add(f2); + + // Create a default fraction (should be 1/1) + openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0, &cache); + r.Open(); + + // Verify exception + CHECK_EQUAL(1, r.GetFrame(1)->number); + CHECK_EQUAL(2, r.GetFrame(2)->number); + CHECK_THROW(r.GetFrame(3)->number, InvalidFile); + + // Clean up + cache.Clear(); + r.Close(); +} \ No newline at end of file diff --git a/tests/FFmpegReader_Tests.cpp b/tests/FFmpegReader_Tests.cpp index 0a8620c9b..b79820ade 100644 --- a/tests/FFmpegReader_Tests.cpp +++ b/tests/FFmpegReader_Tests.cpp @@ -36,13 +36,16 @@ using namespace std; using namespace openshot; -TEST(FFmpegReader_Invalid_Path) +SUITE(FFmpegReader) +{ + +TEST(Invalid_Path) { // Check invalid path CHECK_THROW(FFmpegReader(""), InvalidFile); } -TEST(FFmpegReader_GetFrame_Before_Opening) +TEST(GetFrame_Before_Opening) { // Create a reader stringstream path; @@ -53,7 +56,7 @@ TEST(FFmpegReader_GetFrame_Before_Opening) CHECK_THROW(r.GetFrame(1), ReaderClosed); } -TEST(FFmpegReader_Check_Audio_File) +TEST(Check_Audio_File) { // Create a reader stringstream path; @@ -76,14 +79,14 @@ TEST(FFmpegReader_Check_Audio_File) CHECK_CLOSE(0.0f, samples[50], 0.00001); CHECK_CLOSE(0.0f, samples[100], 0.00001); CHECK_CLOSE(0.0f, samples[200], 0.00001); - CHECK_CLOSE(0.160781f, samples[230], 0.00001); - CHECK_CLOSE(-0.06125f, samples[300], 0.00001); + CHECK_CLOSE(0.16406f, samples[230], 0.00001); + CHECK_CLOSE(-0.06250f, samples[300], 0.00001); // Close reader r.Close(); } -TEST(FFmpegReader_Check_Video_File) +TEST(Check_Video_File) { // Create a reader stringstream path; @@ -129,7 +132,7 @@ TEST(FFmpegReader_Check_Video_File) r.Close(); } -TEST(FFmpegReader_Seek) +TEST(Seek) { // Create a reader stringstream path; @@ -186,7 +189,23 @@ TEST(FFmpegReader_Seek) } -TEST(FFmpegReader_Multiple_Open_and_Close) +TEST(Frame_Rate) +{ + // Create a reader + stringstream path; + path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4"; + FFmpegReader r(path.str()); + r.Open(); + + // Verify detected frame rate + openshot::Fraction rate = r.info.fps; + CHECK_EQUAL(24, rate.num); + CHECK_EQUAL(1, rate.den); + + r.Close(); +} + +TEST(Multiple_Open_and_Close) { // Create a reader stringstream path; @@ -221,3 +240,6 @@ TEST(FFmpegReader_Multiple_Open_and_Close) // Close reader r.Close(); } + +} // SUITE(FFmpegReader) + diff --git a/version.sh b/version.sh new file mode 100755 index 000000000..86a664dc6 --- /dev/null +++ b/version.sh @@ -0,0 +1,4 @@ +#!/bin/sh +grep 'set.*(.*PROJECT_VERSION_FULL' CMakeLists.txt\ + |sed -e 's#set(PROJECT_VERSION_FULL.*"\(.*\)\")#\1#;q' +