diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 000000000..c5ec1048c
--- /dev/null
+++ b/.github/stale.yml
@@ -0,0 +1,22 @@
+# Number of days of inactivity before an issue becomes stale
+daysUntilStale: 90
+# Number of days of inactivity before a stale issue is closed
+daysUntilClose: 10
+# Issues with these labels will never be considered stale
+exemptLabels:
+ - pinned
+ - security
+ - enhancement
+# Label to use when marking an issue as stale
+staleLabel: stale
+# Comment to post when marking an issue as stale. Set to `false` to disable
+markComment: >
+ This issue has been automatically marked as **stale** because it has not had
+ recent activity. It will be closed if no further activity occurs. Thank you
+ for your contributions.
+# Comment to post when closing a stale issue. Set to `false` to disable
+closeComment: false
+# Only close issues
+only: issues
+# Don't close issues which are assigned to somebody
+exemptAssignees: true
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 612f234cf..f998c3d45 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -24,7 +24,7 @@ linux-builder:
- ~/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)..HEAD --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"
+ - 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
except:
- tags
@@ -46,12 +46,12 @@ mac-builder:
- 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=Debug" -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_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" ../
- 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)..HEAD --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"
+ - 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
except:
- tags
@@ -79,8 +79,8 @@ windows-builder-x64:
- 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..HEAD" --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"
+ - $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"
when: always
except:
- tags
@@ -108,8 +108,8 @@ windows-builder-x86:
- 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..HEAD" --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"
+ - $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"
when: always
except:
- tags
diff --git a/.travis.yml b/.travis.yml
index 1034042d9..e2c3d5f15 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,6 +18,7 @@ addons:
- qtmultimedia5-dev
- doxygen
- graphviz
+ - curl
packages: &ff_common # Common set of FFmpeg packages
- *p_common
- libfdk-aac-dev
@@ -33,20 +34,12 @@ addons:
matrix:
include:
- - name: "FFmpeg 2 GCC (Ubuntu 16.04 Xenial)"
- env: BUILD_VERSION=ffmpeg2
- os: linux
- dist: xenial
- addons:
- apt:
- sources:
- - sourceline: 'ppa:openshot.developers/libopenshot-daily'
- - sourceline: 'ppa:beineri/opt-qt-5.10.0-xenial'
- packages:
- - *ff_common
- - name: "FFmpeg 3 GCC (Ubuntu 18.04 Bionic)"
- env: BUILD_VERSION=ffmpeg3
+ - name: "Coverage + FFmpeg 3.4 GCC (Ubuntu 18.04 Bionic)"
+ env:
+ - BUILD_VERSION=coverage_ffmpeg34
+ - CMAKE_EXTRA_ARGS="-DENABLE_COVERAGE=1"
+ - TEST_TARGET=coverage
os: linux
dist: bionic
addons:
@@ -57,9 +50,15 @@ matrix:
packages:
- *ff_common
- qt5-default
+ - libjsoncpp-dev
+ - lcov
+ - binutils-common # For c++filt
- name: "FFmpeg 4 GCC (Ubuntu 18.04 Bionic)"
- env: BUILD_VERSION=ffmpeg4
+ env:
+ - BUILD_VERSION=ffmpeg4
+ - CMAKE_EXTRA_ARGS=""
+ - TEST_TARGET=test
os: linux
dist: bionic
addons:
@@ -71,6 +70,7 @@ matrix:
packages:
- *ff_common
- qt5-default
+ - libjsoncpp-dev
- libavcodec58
- libavformat58
- libavdevice58
@@ -81,8 +81,11 @@ matrix:
- libavresample4
- libswresample3
- - name: "FFmpeg 3 Clang (Ubuntu 18.04 Bionic)"
- env: BUILD_VERSION=ffmpeg3
+ - name: "FFmpeg 3.4 Clang (Ubuntu 18.04 Bionic)"
+ env:
+ - BUILD_VERSION=clang_ffmpeg34
+ - CMAKE_EXTRA_ARGS=""
+ - TEST_TARGET=test
os: linux
dist: bionic
compiler: clang
@@ -96,9 +99,53 @@ matrix:
- qt5-default
- libomp-dev
+ - name: "FFmpeg 3.2 GCC (Ubuntu 16.04 Xenial)"
+ env:
+ - BUILD_VERSION=ffmpeg32
+ - CMAKE_EXTRA_ARGS=""
+ - TEST_TARGET="os_test"
+ os: linux
+ dist: xenial
+ addons:
+ 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
+ - libavcodec57
+ - libavdevice57
+ - libavfilter6
+ - libavformat57
+ - libavresample3
+ - libavutil55
+ - libpostproc54
+ - libswresample2
+ - libswscale4
+
+ - name: "FFmpeg 2 GCC (Ubuntu 16.04 Xenial)"
+ env:
+ - BUILD_VERSION=ffmpeg2
+ - CMAKE_EXTRA_ARGS=""
+ - TEST_TARGET="os_test"
+ os: linux
+ dist: xenial
+ addons:
+ apt:
+ sources:
+ - sourceline: 'ppa:openshot.developers/libopenshot-daily'
+ - sourceline: 'ppa:beineri/opt-qt-5.10.0-xenial'
+ packages:
+ - *ff_common
+
script:
- mkdir -p build; cd build;
- - cmake -DCMAKE_BUILD_TYPE:STRING="Debug" ../
+ - cmake -DCMAKE_BUILD_TYPE:STRING="Debug" ${CMAKE_EXTRA_ARGS} ../
- make VERBOSE=1
- - make os_test
+ - make ${TEST_TARGET}
- make install DESTDIR="$BUILD_VERSION"
+ - cd ..
+
+after_success:
+ - if [ "x$TEST_TARGET" = "xcoverage" ]; then bash <(curl -s https://codecov.io/bash) -f build/coverage.info || echo "Codecov did not collect coverage reports"; fi
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5cfb678c9..a0e8a5feb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -40,8 +40,8 @@ For more information, please visit .
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules")
################ PROJECT VERSION ####################
-set(PROJECT_VERSION_FULL "0.2.3-dev1")
-set(PROJECT_SO_VERSION 17)
+set(PROJECT_VERSION_FULL "0.2.5-dev2")
+set(PROJECT_SO_VERSION 19)
# Remove the dash and anything following, to get the #.#.# version for project()
STRING(REGEX REPLACE "\-.*$" "" VERSION_NUM "${PROJECT_VERSION_FULL}")
@@ -66,12 +66,44 @@ Generating build files for OpenShot with CMake ${CMAKE_VERSION}
# in order to properly configure CMAKE_INSTALL_LIBDIR path
include(GNUInstallDirs)
+# Collect and display summary of options/dependencies
+include(FeatureSummary)
+
+################ OPTIONS ##################
+# Optional build settings for libopenshot
+option(USE_SYSTEM_JSONCPP "Use system installed JsonCpp, if found" ON)
+option(DISABLE_BUNDLED_JSONCPP "Don't fall back to bundled JsonCpp" OFF)
+option(ENABLE_IWYU "Enable 'Include What You Use' scanner (CMake 3.3+)" OFF)
+option(ENABLE_TESTS "Build unit tests (requires UnitTest++)" ON)
+option(ENABLE_DOCS "Build API documentation (requires Doxygen)" ON)
+
+# Legacy commandline override
+if (DISABLE_TESTS)
+ if(ENABLE_COVERAGE)
+ message(WARNING "ENABLE_COVERAGE requires tests, overriding DISABLE_TESTS")
+ set(ENABLE_TESTS ON)
+ else()
+ set(ENABLE_TESTS OFF)
+ endif()
+endif()
+
+if(DEFINED ENABLE_TESTS)
+ set(ENABLE_TESTS ${ENABLE_TESTS} CACHE BOOL "Build unit tests (requires UnitTest++)" FORCE)
+endif()
+
########## Configure Version.h header ##############
configure_file(include/OpenShotVersion.h.in include/OpenShotVersion.h @ONLY)
# We'll want that installed later
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/OpenShotVersion.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libopenshot)
+#### Work around a GCC < 9 bug with handling of _Pragma() in macros
+#### See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578
+if ((${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") AND
+ (${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS "9.0.0"))
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no-integrated-cpp")
+endif()
+
#### Enable C++11 (for std::shared_ptr support)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -85,29 +117,67 @@ 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")
+ set(DISABLE_TESTS OFF CACHE BOOL "Don't build unit tests" FORCE)
+endif()
+
+if (ENABLE_COVERAGE)
+ if (NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "Debug")
+ message(STATUS "Coverage enabled, setting build type to Debug")
+ endif()
+ include(CodeCoverage)
+ append_coverage_compiler_flags()
+endif()
+add_feature_info("Coverage" ENABLE_COVERAGE "analyze test coverage and generate report")
+
############## PROCESS src/ DIRECTORIES ##############
add_subdirectory(src)
################### DOCUMENTATION ###################
# Find Doxygen (used for documentation)
-include(cmake/Modules/UseDoxygen.cmake)
-
-# Doxygen was found
-if (TARGET doc)
- message(STATUS "Doxygen found, documentation target enabled")
- message("\nTo compile documentation in doc/html, run: 'make doc'")
-
- # Install docs, if the user builds them with `make doc`
- install(CODE "MESSAGE(\"Checking for documentation files to install...\")")
- install(CODE "MESSAGE(\"(Compile with 'make doc' command, requires Doxygen)\")")
-
- install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/html/
- DESTINATION ${CMAKE_INSTALL_DOCDIR}/API
- MESSAGE_NEVER # Don't spew about file copies
- OPTIONAL ) # No error if the docs aren't found
+set(DOCS_ENABLED FALSE) # Only set true if Doxygen is found and configured
+if (ENABLE_DOCS)
+ include(cmake/Modules/UseDoxygen.cmake)
+
+ # Doxygen was found
+ if (TARGET doc)
+ message(STATUS "Doxygen found, documentation target enabled")
+ set(DOCS_ENABLED TRUE)
+
+ # Install docs, if the user builds them with `make doc`
+ install(CODE "MESSAGE(\"Checking for documentation files to install...\")")
+ install(CODE "MESSAGE(\"(Compile with 'make doc' command, requires Doxygen)\")")
+
+ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/html/
+ DESTINATION ${CMAKE_INSTALL_DOCDIR}/API
+ MESSAGE_NEVER # Don't spew about file copies
+ OPTIONAL ) # No error if the docs aren't found
+ endif()
endif()
+add_feature_info("Documentation" DOCS_ENABLED "Build API documentation with 'make doc'")
############# PROCESS tests/ DIRECTORY ##############
-if(NOT DISABLE_TESTS)
+if(ENABLE_TESTS)
+ set(TESTS_ENABLED TRUE) # May be overridden by tests/CMakeLists.txt
add_subdirectory(tests)
endif()
+add_feature_info("Unit tests" TESTS_ENABLED "Compile unit tests for library functions")
+
+############## COVERAGE REPORTING #################
+if (ENABLE_COVERAGE)
+ setup_target_for_coverage_lcov(
+ NAME coverage
+ LCOV_ARGS "--no-external"
+ EXECUTABLE openshot-test
+ DEPENDENCIES openshot-test)
+ message("Generate coverage report with 'make coverage'")
+endif()
+
+########### PRINT FEATURE SUMMARY ##############
+feature_summary(WHAT ALL
+ INCLUDE_QUIET_PACKAGES
+ FATAL_ON_MISSING_REQUIRED_PACKAGES
+ DESCRIPTION "Displaying feature summary\n\nBuild configuration:")
diff --git a/cmake/Modules/CodeCoverage.cmake b/cmake/Modules/CodeCoverage.cmake
new file mode 100644
index 000000000..fde7f535c
--- /dev/null
+++ b/cmake/Modules/CodeCoverage.cmake
@@ -0,0 +1,435 @@
+# Copyright (c) 2012 - 2017, Lars Bilke
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# CHANGES:
+#
+# 2012-01-31, Lars Bilke
+# - Enable Code Coverage
+#
+# 2013-09-17, Joakim Söderberg
+# - Added support for Clang.
+# - Some additional usage instructions.
+#
+# 2016-02-03, Lars Bilke
+# - Refactored functions to use named parameters
+#
+# 2017-06-02, Lars Bilke
+# - Merged with modified version from github.com/ufz/ogs
+#
+# 2019-05-06, Anatolii Kurotych
+# - Remove unnecessary --coverage flag
+#
+# 2019-12-13, FeRD (Frank Dana)
+# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor
+# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments.
+# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY
+# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list
+# - Set lcov basedir with -b argument
+# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be
+# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().)
+# - Delete output dir, .info file on 'make clean'
+# - Remove Python detection, since version mismatches will break gcovr
+# - Minor cleanup (lowercase function names, update examples...)
+#
+# 2019-12-19, FeRD (Frank Dana)
+# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets
+#
+# 2020-01-19, Bob Apthorpe
+# - Added gfortran support
+#
+# 2020-02-17, FeRD (Frank Dana)
+# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters
+# in EXCLUDEs, and remove manual escaping from gcovr targets
+#
+# USAGE:
+#
+# 1. Copy this file into your cmake modules path.
+#
+# 2. Add the following line to your CMakeLists.txt:
+# include(CodeCoverage)
+#
+# 3. Append necessary compiler flags:
+# append_coverage_compiler_flags()
+#
+# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og
+#
+# 4. If you need to exclude additional directories from the report, specify them
+# using full paths in the COVERAGE_EXCLUDES variable before calling
+# setup_target_for_coverage_*().
+# Example:
+# set(COVERAGE_EXCLUDES
+# '${PROJECT_SOURCE_DIR}/src/dir1/*'
+# '/path/to/my/src/dir2/*')
+# Or, use the EXCLUDE argument to setup_target_for_coverage_*().
+# Example:
+# setup_target_for_coverage_lcov(
+# NAME coverage
+# EXECUTABLE testrunner
+# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*")
+#
+# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set
+# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR)
+# Example:
+# set(COVERAGE_EXCLUDES "dir1/*")
+# setup_target_for_coverage_gcovr_html(
+# NAME coverage
+# EXECUTABLE testrunner
+# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src"
+# EXCLUDE "dir2/*")
+#
+# 5. Use the functions described below to create a custom make target which
+# runs your test executable and produces a code coverage report.
+#
+# 6. Build a Debug build:
+# cmake -DCMAKE_BUILD_TYPE=Debug ..
+# make
+# make my_coverage_target
+#
+
+include(CMakeParseArguments)
+
+# Check prereqs
+find_program( GCOV_PATH gcov )
+find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
+find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
+find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
+find_program( CPPFILT_PATH NAMES c++filt )
+
+if(NOT GCOV_PATH)
+ message(FATAL_ERROR "gcov not found! Aborting...")
+endif() # NOT GCOV_PATH
+
+if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
+ if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
+ message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
+ endif()
+elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
+ if("${CMAKE_Fortran_COMPILER_ID}" MATCHES "[Ff]lang")
+ # Do nothing; exit conditional without error if true
+ elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU")
+ # Do nothing; exit conditional without error if true
+ else()
+ message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
+ endif()
+endif()
+
+set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage"
+ CACHE INTERNAL "")
+
+set(CMAKE_Fortran_FLAGS_COVERAGE
+ ${COVERAGE_COMPILER_FLAGS}
+ CACHE STRING "Flags used by the Fortran compiler during coverage builds."
+ FORCE )
+set(CMAKE_CXX_FLAGS_COVERAGE
+ ${COVERAGE_COMPILER_FLAGS}
+ CACHE STRING "Flags used by the C++ compiler during coverage builds."
+ FORCE )
+set(CMAKE_C_FLAGS_COVERAGE
+ ${COVERAGE_COMPILER_FLAGS}
+ CACHE STRING "Flags used by the C compiler during coverage builds."
+ FORCE )
+set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
+ ""
+ CACHE STRING "Flags used for linking binaries during coverage builds."
+ FORCE )
+set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
+ ""
+ CACHE STRING "Flags used by the shared libraries linker during coverage builds."
+ FORCE )
+mark_as_advanced(
+ CMAKE_Fortran_FLAGS_COVERAGE
+ CMAKE_CXX_FLAGS_COVERAGE
+ CMAKE_C_FLAGS_COVERAGE
+ CMAKE_EXE_LINKER_FLAGS_COVERAGE
+ CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
+
+if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
+ message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
+endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
+ link_libraries(gcov)
+endif()
+
+# Defines a target for running and collection code coverage information
+# Builds dependencies, runs the given executable and outputs reports.
+# NOTE! The executable should always have a ZERO as exit code otherwise
+# the coverage generation will not complete.
+#
+# setup_target_for_coverage_lcov(
+# NAME testrunner_coverage # New target name
+# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
+# DEPENDENCIES testrunner # Dependencies to build first
+# BASE_DIRECTORY "../" # Base directory for report
+# # (defaults to PROJECT_SOURCE_DIR)
+# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
+# # to BASE_DIRECTORY, with CMake 3.4+)
+# NO_DEMANGLE # Don't demangle C++ symbols
+# # even if c++filt is found
+# )
+function(setup_target_for_coverage_lcov)
+
+ set(options NO_DEMANGLE)
+ set(oneValueArgs BASE_DIRECTORY NAME)
+ set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
+ cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(NOT LCOV_PATH)
+ message(FATAL_ERROR "lcov not found! Aborting...")
+ endif() # NOT LCOV_PATH
+
+ if(NOT GENHTML_PATH)
+ message(FATAL_ERROR "genhtml not found! Aborting...")
+ endif() # NOT GENHTML_PATH
+
+ # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
+ if(${Coverage_BASE_DIRECTORY})
+ get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
+ else()
+ set(BASEDIR ${PROJECT_SOURCE_DIR})
+ endif()
+
+ # Collect excludes (CMake 3.4+: Also compute absolute paths)
+ set(LCOV_EXCLUDES "")
+ foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES})
+ if(CMAKE_VERSION VERSION_GREATER 3.4)
+ get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
+ endif()
+ list(APPEND LCOV_EXCLUDES "${EXCLUDE}")
+ endforeach()
+ list(REMOVE_DUPLICATES LCOV_EXCLUDES)
+
+ # Conditional arguments
+ if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
+ set(GENHTML_EXTRA_ARGS "--demangle-cpp")
+ endif()
+
+ # Setup target
+ add_custom_target(${Coverage_NAME}
+
+ # Cleanup lcov
+ COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . -b ${BASEDIR} --zerocounters
+ # Create baseline to make sure untouched files show up in the report
+ COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b ${BASEDIR} -o ${Coverage_NAME}.base
+
+ # Run tests
+ COMMAND ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
+
+ # Capturing lcov counters and generating report
+ COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b ${BASEDIR} --capture --output-file ${Coverage_NAME}.capture
+ # add baseline counters
+ COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total
+ # filter collected data to final coverage report
+ COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info
+
+ # Generate HTML output
+ COMMAND ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o ${Coverage_NAME} ${Coverage_NAME}.info
+
+ # Set output files as GENERATED (will be removed on 'make clean')
+ BYPRODUCTS
+ ${Coverage_NAME}.base
+ ${Coverage_NAME}.capture
+ ${Coverage_NAME}.total
+ ${Coverage_NAME}.info
+ ${Coverage_NAME} # report directory
+
+ WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
+ DEPENDS ${Coverage_DEPENDENCIES}
+ VERBATIM # Protect arguments to commands
+ COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
+ )
+
+ # Show where to find the lcov info report
+ add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
+ COMMAND ;
+ COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
+ )
+
+ # Show info where to find the report
+ add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
+ COMMAND ;
+ COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
+ )
+
+endfunction() # setup_target_for_coverage_lcov
+
+# Defines a target for running and collection code coverage information
+# Builds dependencies, runs the given executable and outputs reports.
+# NOTE! The executable should always have a ZERO as exit code otherwise
+# the coverage generation will not complete.
+#
+# setup_target_for_coverage_gcovr_xml(
+# NAME ctest_coverage # New target name
+# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
+# DEPENDENCIES executable_target # Dependencies to build first
+# BASE_DIRECTORY "../" # Base directory for report
+# # (defaults to PROJECT_SOURCE_DIR)
+# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
+# # to BASE_DIRECTORY, with CMake 3.4+)
+# )
+function(setup_target_for_coverage_gcovr_xml)
+
+ set(options NONE)
+ set(oneValueArgs BASE_DIRECTORY NAME)
+ set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
+ cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(NOT GCOVR_PATH)
+ message(FATAL_ERROR "gcovr not found! Aborting...")
+ endif() # NOT GCOVR_PATH
+
+ # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
+ if(${Coverage_BASE_DIRECTORY})
+ get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
+ else()
+ set(BASEDIR ${PROJECT_SOURCE_DIR})
+ endif()
+
+ # Collect excludes (CMake 3.4+: Also compute absolute paths)
+ set(GCOVR_EXCLUDES "")
+ foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
+ if(CMAKE_VERSION VERSION_GREATER 3.4)
+ get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
+ endif()
+ list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
+ endforeach()
+ list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
+
+ # Combine excludes to several -e arguments
+ set(GCOVR_EXCLUDE_ARGS "")
+ foreach(EXCLUDE ${GCOVR_EXCLUDES})
+ list(APPEND GCOVR_EXCLUDE_ARGS "-e")
+ list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
+ endforeach()
+
+ add_custom_target(${Coverage_NAME}
+ # Run tests
+ ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
+
+ # Running gcovr
+ COMMAND ${GCOVR_PATH} --xml
+ -r ${BASEDIR} ${GCOVR_EXCLUDE_ARGS}
+ --object-directory=${PROJECT_BINARY_DIR}
+ -o ${Coverage_NAME}.xml
+ BYPRODUCTS ${Coverage_NAME}.xml
+ WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
+ DEPENDS ${Coverage_DEPENDENCIES}
+ VERBATIM # Protect arguments to commands
+ COMMENT "Running gcovr to produce Cobertura code coverage report."
+ )
+
+ # Show info where to find the report
+ add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
+ COMMAND ;
+ COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
+ )
+endfunction() # setup_target_for_coverage_gcovr_xml
+
+# Defines a target for running and collection code coverage information
+# Builds dependencies, runs the given executable and outputs reports.
+# NOTE! The executable should always have a ZERO as exit code otherwise
+# the coverage generation will not complete.
+#
+# setup_target_for_coverage_gcovr_html(
+# NAME ctest_coverage # New target name
+# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
+# DEPENDENCIES executable_target # Dependencies to build first
+# BASE_DIRECTORY "../" # Base directory for report
+# # (defaults to PROJECT_SOURCE_DIR)
+# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
+# # to BASE_DIRECTORY, with CMake 3.4+)
+# )
+function(setup_target_for_coverage_gcovr_html)
+
+ set(options NONE)
+ set(oneValueArgs BASE_DIRECTORY NAME)
+ set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
+ cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(NOT GCOVR_PATH)
+ message(FATAL_ERROR "gcovr not found! Aborting...")
+ endif() # NOT GCOVR_PATH
+
+ # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
+ if(${Coverage_BASE_DIRECTORY})
+ get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
+ else()
+ set(BASEDIR ${PROJECT_SOURCE_DIR})
+ endif()
+
+ # Collect excludes (CMake 3.4+: Also compute absolute paths)
+ set(GCOVR_EXCLUDES "")
+ foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
+ if(CMAKE_VERSION VERSION_GREATER 3.4)
+ get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
+ endif()
+ list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
+ endforeach()
+ list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
+
+ # Combine excludes to several -e arguments
+ set(GCOVR_EXCLUDE_ARGS "")
+ foreach(EXCLUDE ${GCOVR_EXCLUDES})
+ list(APPEND GCOVR_EXCLUDE_ARGS "-e")
+ list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
+ endforeach()
+
+ add_custom_target(${Coverage_NAME}
+ # Run tests
+ ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
+
+ # Create folder
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
+
+ # Running gcovr
+ COMMAND ${GCOVR_PATH} --html --html-details
+ -r ${BASEDIR} ${GCOVR_EXCLUDE_ARGS}
+ --object-directory=${PROJECT_BINARY_DIR}
+ -o ${Coverage_NAME}/index.html
+
+ BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME} # report directory
+ WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
+ DEPENDS ${Coverage_DEPENDENCIES}
+ VERBATIM # Protect arguments to commands
+ COMMENT "Running gcovr to produce HTML code coverage report."
+ )
+
+ # Show info where to find the report
+ add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
+ COMMAND ;
+ COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
+ )
+
+endfunction() # setup_target_for_coverage_gcovr_html
+
+function(append_coverage_compiler_flags)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
+ set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
+ message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
+endfunction() # append_coverage_compiler_flags
diff --git a/cmake/Modules/FindRESVG.cmake b/cmake/Modules/FindRESVG.cmake
index b03a0667e..0538eacd5 100644
--- a/cmake/Modules/FindRESVG.cmake
+++ b/cmake/Modules/FindRESVG.cmake
@@ -1,28 +1,115 @@
-# - Try to find RESVG
-# Once done this will define
-# RESVG_FOUND - System has RESVG
-# RESVG_INCLUDE_DIRS - The RESVG include directories
-# RESVG_LIBRARIES - The libraries needed to use RESVG
-find_path ( RESVG_INCLUDE_DIR ResvgQt.h
- PATHS ${RESVGDIR}/include/resvg
- $ENV{RESVGDIR}/include/resvg
- $ENV{RESVGDIR}/include
- /usr/include/resvg
- /usr/include
- /usr/local/include/resvg
- /usr/local/include )
-
-find_library ( RESVG_LIBRARY NAMES resvg
- PATHS /usr/lib
- /usr/local/lib
- $ENV{RESVGDIR}
- $ENV{RESVGDIR}/lib )
-
-set ( RESVG_LIBRARIES ${RESVG_LIBRARY} )
-set ( RESVG_INCLUDE_DIRS ${RESVG_INCLUDE_DIR} )
-
-include ( FindPackageHandleStandardArgs )
-# handle the QUIETLY and REQUIRED arguments and set RESVG_FOUND to TRUE
-# if all listed variables are TRUE
-find_package_handle_standard_args ( RESVG "Could NOT find RESVG, using Qt SVG parsing instead" RESVG_LIBRARY RESVG_INCLUDE_DIR )
-mark_as_advanced( RESVG_LIBRARY RESVG_INCLUDE_DIR )
+# vim: ts=2 sw=2
+#[=======================================================================[.rst:
+FindRESVG
+---------
+Try to find the shared-library build of resvg, the Rust SVG library
+
+IMPORTED targets
+^^^^^^^^^^^^^^^^
+
+This module defines :prop_tgt:`IMPORTED` target ``RESVG::resvg`` when
+the library and headers are found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+::
+
+ RESVG_FOUND - Library and header files found
+ RESVG_INCLUDE_DIRS - Include directory path
+ RESVG_LIBRARIES - Link path to the library
+ RESVG_DEFINITIONS - Compiler switches (currently unused)
+
+Backwards compatibility
+^^^^^^^^^^^^^^^^^^^^^^^
+
+For compatibility with previous versions of this module, uppercase names
+for FFmpeg and for all components are also recognized, and all-uppercase
+versions of the cache variables are also created.
+
+Control variables
+^^^^^^^^^^^^^^^^^
+
+The following variables can be used to provide path hints to the module:
+
+RESVGDIR - Set in the calling CMakeLists.txt or on the command line
+ENV{RESVGDIR} - An environment variable in the cmake process context
+
+Copyright (c) 2020, FeRD (Frank Dana)
+#]=======================================================================]
+include(FindPackageHandleStandardArgs)
+
+# CMake 3.4+ only: Convert relative paths to absolute
+if(DEFINED RESVGDIR AND CMAKE_VERSION VERSION_GREATER 3.4)
+ get_filename_component(RESVGDIR "${RESVGDIR}" ABSOLUTE
+ BASE_DIR ${CMAKE_CURRENT_BINARY_DIR})
+endif()
+
+find_path(RESVG_INCLUDE_DIRS
+ ResvgQt.h
+ PATHS
+ ${RESVGDIR}
+ ${RESVGDIR}/include
+ $ENV{RESVGDIR}
+ $ENV{RESVGDIR}/include
+ /usr/include
+ /usr/local/include
+ PATH_SUFFIXES
+ resvg
+ capi/include
+ resvg/capi/include
+)
+
+find_library(RESVG_LIBRARIES
+ NAMES resvg
+ PATHS
+ ${RESVGDIR}
+ ${RESVGDIR}/lib
+ $ENV{RESVGDIR}
+ $ENV{RESVGDIR}/lib
+ /usr/lib
+ /usr/local/lib
+ PATH_SUFFIXES
+ resvg
+ target/release
+ resvg/target/release
+)
+
+if (RESVG_INCLUDE_DIRS AND RESVG_LIBRARIES)
+ set(RESVG_FOUND TRUE)
+endif()
+set(RESVG_LIBRARIES ${RESVG_LIBRARIES} CACHE STRING "The Resvg library link path")
+set(RESVG_INCLUDE_DIRS ${RESVG_INCLUDE_DIRS} CACHE STRING "The Resvg include directories")
+set(RESVG_DEFINITIONS "" CACHE STRING "The Resvg CFLAGS")
+
+mark_as_advanced(RESVG_LIBRARIES RESVG_INCLUDE_DIRS RESVG_DEFINITIONS)
+
+# Give a nice error message if some of the required vars are missing.
+find_package_handle_standard_args(RESVG
+ "Could NOT find RESVG, using Qt SVG parsing instead"
+ RESVG_LIBRARIES RESVG_INCLUDE_DIRS )
+
+# Export target
+if(RESVG_FOUND AND NOT TARGET RESVG::resvg)
+ message(STATUS "Creating IMPORTED target RESVG::resvg")
+ if (WIN32)
+ # Windows mis-links SHARED library targets
+ add_library(RESVG::resvg UNKNOWN IMPORTED)
+ else()
+ # Linux needs SHARED to link because libresvg has no SONAME
+ add_library(RESVG::resvg SHARED IMPORTED)
+ set_property(TARGET RESVG::resvg APPEND PROPERTY
+ IMPORTED_NO_SONAME TRUE)
+ endif()
+
+ set_property(TARGET RESVG::resvg APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES "${RESVG_INCLUDE_DIRS}")
+
+ set_property(TARGET RESVG::resvg APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS "${RESVG_DEFINITIONS}")
+
+ set_property(TARGET RESVG::resvg APPEND PROPERTY
+ IMPORTED_LOCATION "${RESVG_LIBRARIES}")
+endif()
diff --git a/cmake/Modules/FindUnitTest++.cmake b/cmake/Modules/FindUnitTest++.cmake
index 545f62a88..ce1bdc458 100644
--- a/cmake/Modules/FindUnitTest++.cmake
+++ b/cmake/Modules/FindUnitTest++.cmake
@@ -1,43 +1,59 @@
-# Locate UNITTEST
+# Locate UnitTest++
# This module defines
-# UNITTEST++_LIBRARY
-# UNITTEST++_FOUND, if false, do not try to link to gdal
-# UNITTEST++_INCLUDE_DIR, where to find the headers
-
-FIND_PATH(UNITTEST++_INCLUDE_DIR UnitTest++.h
- ${UNITTEST_DIR}/include/unittest++
- $ENV{UNITTEST_DIR}/include/unittest++
- $ENV{UNITTEST_DIR}/src
+# UnitTest++_FOUND, if successful
+# UnitTest++_LIBRARIES, the library path
+# UnitTest++_INCLUDE_DIRS, where to find the headers
+
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_UnitTest QUIET UnitTest++)
+ set(UnitTest++_VERSION ${PC_UnitTest_VERSION})
+endif()
+
+
+FIND_PATH(UnitTest++_INCLUDE_DIRS UnitTest++.h
+ DOC
+ "Location of UnitTest++ header files"
+ PATH_SUFFIXES
+ unittest++
+ UnitTest++ # Fedora, Arch
+ unittest-cpp # openSUSE
+ HINTS
+ ${PC_UnitTest++_INCLUDEDIR}
+ ${PC_UnitTest++_INCLUDE_DIRS}
+ PATHS
+ ${UnitTest++_ROOT}
+ ${UNITTEST_DIR}
+ $ENV{UNITTEST_DIR}/src
$ENV{UNITTEST_DIR}
~/Library/Frameworks
/Library/Frameworks
- /usr/local/include
- /usr/include
- /usr/include/unittest++
- /usr/include/UnitTest++ # Fedora
- /usr/include/unittest-cpp # openSUSE
- /usr/local/include/UnitTest++/ # Arch
- /sw/include # Fink
- /opt/local/include # DarwinPorts
- /opt/local/include/UnitTest++
- /opt/csw/include # Blastwave
- /opt/include
+ /usr/local
+ /sw # Fink
+ /opt
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment]/include
- /usr/freeware/include
+ /usr/freeware
)
-FIND_LIBRARY(UNITTEST++_LIBRARY
- NAMES unittest++ UnitTest++
- PATHS
- ${UNITTEST_DIR}/lib
- $ENV{UNITTEST_DIR}/lib
- $ENV{UNITTEST_DIR}/build
+FIND_LIBRARY(UnitTest++_LIBRARIES
+ NAMES unittest++ UnitTest++
+ DOC
+ "Location of UnitTest++ shared library"
+ HINTS
+ ${PC_UnitTest++_LIBDIR}
+ ${PC_UnitTest++_LIBRARY_DIRS}
+ PATHS
+ ${UnitTest++_ROOT}
+ ${UnitTest++_ROOT}/lib
+ ${UNITTEST_DIR}
$ENV{UNITTEST_DIR}
+ $ENV{UNITTEST_DIR}/lib
+ $ENV{UNITTEST_DIR}/build
~/Library/Frameworks
/Library/Frameworks
/usr/local/lib
- /usr/lib
- /usr/lib64/ # Fedora
/sw/lib
/opt/local/lib
/opt/csw/lib
@@ -46,13 +62,24 @@ FIND_LIBRARY(UNITTEST++_LIBRARY
/usr/freeware/lib64
)
-SET(UNITTEST++_FOUND "NO")
-IF(UNITTEST++_LIBRARY AND UNITTEST++_INCLUDE_DIR)
- SET(UNITTEST++_FOUND "YES")
-ENDIF(UNITTEST++_LIBRARY AND UNITTEST++_INCLUDE_DIR)
+if(UnitTest++_LIBRARIES AND UnitTest++_INCLUDE_DIRS)
+ set(UnitTest++_FOUND TRUE)
+endif()
include(FindPackageHandleStandardArgs)
-# handle the QUIETLY and REQUIRED arguments and set UNITTEST++_FOUND to TRUE
-# if all listed variables are TRUE
-find_package_handle_standard_args(UNITTEST++ DEFAULT_MSG
- UNITTEST++_LIBRARY UNITTEST++_INCLUDE_DIR)
+find_package_handle_standard_args(UnitTest++
+ REQUIRED_VARS
+ UnitTest++_LIBRARIES
+ UnitTest++_INCLUDE_DIRS
+ VERSION_VAR
+ UnitTest++_VERSION
+)
+
+# Excessive backwards-compatibility paranoia
+set(UnitTest++_LIBRARY "${UnitTest++_LIBRARIES}" PARENT_SCOPE)
+set(UnitTest++_INCLUDE_DIR "${UnitTest++_INCLUDE_DIRS}" PARENT_SCOPE)
+# Even more excessive backwards-compatibility paranoia
+set(UNITTEST++_FOUND "${UnitTest++_FOUND}" PARENT_SCOPE)
+set(UNITTEST++_LIBRARY "${UnitTest++_LIBRARIES}" PARENT_SCOPE)
+set(UNITTEST++_INCLUDE_DIR "${UnitTest++_INCLUDE_DIRS}" PARENT_SCOPE)
+
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 000000000..dfdc93755
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,15 @@
+codecov:
+ branch: default
+coverage:
+ status:
+ project:
+ default:
+ base: pr # Only post a status to pull requests
+ informational: true # Don't block PRs based on coverage stats (yet?)
+ignore:
+ - "/src/examples"
+ - "/src/Qt/demo"
+ - "/thirdparty"
+ - "/doc"
+ - "/cmake"
+ - "/*.md"
diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md
index cbcf5e63f..497ae2b9b 100644
--- a/doc/HW-ACCEL.md
+++ b/doc/HW-ACCEL.md
@@ -26,7 +26,7 @@ The following table summarizes our current level of support:
## Supported FFmpeg Versions
-* HW accel is supported from FFmpeg version 3.2 (3.3 for nVidia drivers)
+* HW accel is supported from FFmpeg version 3.4
* HW accel was removed for nVidia drivers in Ubuntu for FFmpeg 4+
**Notice:** The FFmpeg versions of Ubuntu and PPAs for Ubuntu show the
diff --git a/include/AudioBufferSource.h b/include/AudioBufferSource.h
index 42e55c943..3a17feb3c 100644
--- a/include/AudioBufferSource.h
+++ b/include/AudioBufferSource.h
@@ -31,14 +31,6 @@
#ifndef OPENSHOT_AUDIOBUFFERSOURCE_H
#define OPENSHOT_AUDIOBUFFERSOURCE_H
-/// Do not include the juce unittest headers, because it collides with unittest++
-#define __JUCE_UNITTEST_JUCEHEADER__
-
-#ifndef _NDEBUG
- /// Define NO debug for JUCE on mac os
- #define _NDEBUG
-#endif
-
#include
#include "JuceHeader.h"
diff --git a/include/AudioReaderSource.h b/include/AudioReaderSource.h
index 33030adf1..c4e2d2480 100644
--- a/include/AudioReaderSource.h
+++ b/include/AudioReaderSource.h
@@ -31,14 +31,6 @@
#ifndef OPENSHOT_AUDIOREADERSOURCE_H
#define OPENSHOT_AUDIOREADERSOURCE_H
-/// Do not include the juce unittest headers, because it collides with unittest++
-#define __JUCE_UNITTEST_JUCEHEADER__
-
-#ifndef _NDEBUG
- /// Define NO debug for JUCE on mac os
- #define _NDEBUG
-#endif
-
#include
#include "ReaderBase.h"
#include "JuceHeader.h"
diff --git a/include/AudioResampler.h b/include/AudioResampler.h
index 96615cb3f..d88eb7cbe 100644
--- a/include/AudioResampler.h
+++ b/include/AudioResampler.h
@@ -31,16 +31,6 @@
#ifndef OPENSHOT_RESAMPLER_H
#define OPENSHOT_RESAMPLER_H
-/// Do not include the juce unittest headers, because it collides with unittest++
-#ifndef __JUCE_UNITTEST_JUCEHEADER__
- #define __JUCE_UNITTEST_JUCEHEADER__
-#endif
-
-#ifndef _NDEBUG
- // Define NO debug for JUCE on mac os
- #define _NDEBUG
-#endif
-
#include "AudioBufferSource.h"
#include "Exceptions.h"
#include "JuceHeader.h"
diff --git a/include/CacheBase.h b/include/CacheBase.h
index aad65a846..da72e5dbd 100644
--- a/include/CacheBase.h
+++ b/include/CacheBase.h
@@ -110,9 +110,9 @@ namespace openshot {
/// Get and Set JSON methods
virtual std::string Json() = 0; ///< Generate JSON string of this object
- virtual void SetJson(std::string value) = 0; ///< Load JSON string into this object
- virtual Json::Value JsonValue() = 0; ///< Generate Json::JsonValue for this object
- virtual void SetJsonValue(Json::Value root) = 0; ///< Load Json::JsonValue into this object
+ virtual void SetJson(const std::string value) = 0; ///< Load JSON string into this object
+ virtual Json::Value JsonValue() = 0; ///< Generate Json::Value for this object
+ virtual void SetJsonValue(const Json::Value root) = 0; ///< Load Json::Value into this object
virtual ~CacheBase() = default;
};
diff --git a/include/CacheDisk.h b/include/CacheDisk.h
index e69cc3578..09ebd4abc 100644
--- a/include/CacheDisk.h
+++ b/include/CacheDisk.h
@@ -129,9 +129,9 @@ namespace openshot {
/// Get and Set JSON methods
std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ void SetJson(const std::string value); ///< Load JSON string into this object
+ Json::Value JsonValue(); ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
};
}
diff --git a/include/CacheMemory.h b/include/CacheMemory.h
index fb3c75f66..ba771cedf 100644
--- a/include/CacheMemory.h
+++ b/include/CacheMemory.h
@@ -111,9 +111,9 @@ namespace openshot {
/// Get and Set JSON methods
std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ void SetJson(const std::string value); ///< Load JSON string into this object
+ Json::Value JsonValue(); ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
};
}
diff --git a/include/ChunkReader.h b/include/ChunkReader.h
index 9d99fcd47..4d72c31da 100644
--- a/include/ChunkReader.h
+++ b/include/ChunkReader.h
@@ -157,10 +157,10 @@ namespace openshot
std::string Name() { return "ChunkReader"; };
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
/// Open the reader. This is required before you can access frames or data from the reader.
void Open();
diff --git a/include/Clip.h b/include/Clip.h
index 4fdccea98..68d4622a1 100644
--- a/include/Clip.h
+++ b/include/Clip.h
@@ -31,11 +31,6 @@
#ifndef OPENSHOT_CLIP_H
#define OPENSHOT_CLIP_H
-/// Do not include the juce unittest headers, because it collides with unittest++
-#ifndef __JUCE_UNITTEST_JUCEHEADER__
- #define __JUCE_UNITTEST_JUCEHEADER__
-#endif
-
#include
#include
#include
@@ -192,18 +187,18 @@ namespace openshot {
openshot::ReaderBase* Reader();
/// Override End() method
- float End(); ///< Get end position (in seconds) of clip (trim end of video), which can be affected by the time curve.
+ float End() const; ///< Get end position (in seconds) of clip (trim end of video), which can be affected by the time curve.
void End(float value) { end = value; } ///< Set end position (in seconds) of clip (trim end of video)
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< 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)
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
/// @brief Remove an effect from the clip
/// @param effect Remove an effect from the clip.
diff --git a/include/ClipBase.h b/include/ClipBase.h
index 2890f5d8f..1f7f55c47 100644
--- a/include/ClipBase.h
+++ b/include/ClipBase.h
@@ -31,11 +31,6 @@
#ifndef OPENSHOT_CLIPBASE_H
#define OPENSHOT_CLIPBASE_H
-/// Do not include the juce unittest headers, because it collides with unittest++
-#ifndef __JUCE_UNITTEST_JUCEHEADER__
- #define __JUCE_UNITTEST_JUCEHEADER__
-#endif
-
#include
#include
#include "Exceptions.h"
@@ -61,10 +56,10 @@ namespace openshot {
std::string previous_properties; ///< This string contains the previous JSON properties
/// Generate JSON for a property
- Json::Value add_property_json(std::string name, float value, std::string type, std::string memo, Keyframe* keyframe, float min_value, float max_value, bool readonly, int64_t requested_frame);
+ Json::Value add_property_json(std::string name, float value, std::string type, std::string memo, const Keyframe* keyframe, float min_value, float max_value, bool readonly, int64_t requested_frame) const;
/// Generate JSON choice for a property (dropdown properties)
- Json::Value add_property_choice_json(std::string name, int value, int selected_value);
+ Json::Value add_property_choice_json(std::string name, int value, int selected_value) const;
public:
@@ -78,12 +73,12 @@ namespace openshot {
bool operator>= ( ClipBase& a) { return (Position() >= a.Position()); }
/// Get basic properties
- std::string Id() { return id; } ///< Get the Id of this clip object
- float Position() { return position; } ///< Get position on timeline (in seconds)
- int Layer() { return layer; } ///< Get layer of clip on timeline (lower number is covered by higher numbers)
- float Start() { return start; } ///< Get start position (in seconds) of clip (trim start of video)
- float End() { return end; } ///< Get end position (in seconds) of clip (trim end of video)
- float Duration() { return end - start; } ///< Get the length of this clip (in seconds)
+ std::string Id() const { return id; } ///< Get the Id of this clip object
+ float Position() const { return position; } ///< Get position on timeline (in seconds)
+ int Layer() const { return layer; } ///< Get layer of clip on timeline (lower number is covered by higher numbers)
+ float Start() const { return start; } ///< Get start position (in seconds) of clip (trim start of video)
+ float End() const { return end; } ///< Get end position (in seconds) of clip (trim end of video)
+ float Duration() const { return end - start; } ///< Get the length of this clip (in seconds)
/// Set basic properties
void Id(std::string value) { id = value; } ///> Set the Id of this clip object
@@ -93,14 +88,14 @@ namespace openshot {
void End(float value) { end = value; } ///< Set end position (in seconds) of clip (trim end of video)
/// Get and Set JSON methods
- virtual std::string Json() = 0; ///< Generate JSON string of this object
- virtual void SetJson(std::string value) = 0; ///< Load JSON string into this object
- virtual Json::Value JsonValue() = 0; ///< Generate Json::JsonValue for this object
- virtual void SetJsonValue(Json::Value root) = 0; ///< Load Json::JsonValue into this object
+ virtual std::string Json() const = 0; ///< Generate JSON string of this object
+ virtual void SetJson(const std::string value) = 0; ///< Load JSON string into this object
+ virtual Json::Value JsonValue() const = 0; ///< Generate Json::Value for this object
+ virtual void SetJsonValue(const Json::Value root) = 0; ///< 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)
- virtual std::string PropertiesJSON(int64_t requested_frame) = 0;
+ virtual std::string PropertiesJSON(int64_t requested_frame) const = 0;
virtual ~ClipBase() = default;
};
diff --git a/include/Color.h b/include/Color.h
index 47db29a7f..2b4a6d771 100644
--- a/include/Color.h
+++ b/include/Color.h
@@ -69,10 +69,10 @@ namespace openshot {
static long GetDistance(long R1, long G1, long B1, long R2, long G2, long B2);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJson(std::string value); ///< Load JSON string into this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ std::string Json() const; ///< Generate JSON string of this object
+ Json::Value JsonValue() const; ///< Generate Json::Value for this object
+ void SetJson(const std::string value); ///< Load JSON string into this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
};
diff --git a/include/Coordinate.h b/include/Coordinate.h
index 5bfd893a8..a4b9599d2 100644
--- a/include/Coordinate.h
+++ b/include/Coordinate.h
@@ -66,10 +66,10 @@ namespace openshot {
Coordinate(double x, double y);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJson(std::string value); ///< Load JSON string into this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ std::string Json() const; ///< Generate JSON string of this object
+ Json::Value JsonValue() const; ///< Generate Json::Value for this object
+ void SetJson(const std::string value); ///< Load JSON string into this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
};
}
diff --git a/include/DecklinkReader.h b/include/DecklinkReader.h
index de077bdf8..d846cca90 100644
--- a/include/DecklinkReader.h
+++ b/include/DecklinkReader.h
@@ -118,10 +118,10 @@ namespace openshot
std::string Name() { return "DecklinkReader"; };
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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
/// Open device and video stream - which is called by the constructor automatically
void Open();
diff --git a/include/DummyReader.h b/include/DummyReader.h
index 0b40f0790..fd17bed1c 100644
--- a/include/DummyReader.h
+++ b/include/DummyReader.h
@@ -87,10 +87,10 @@ namespace openshot
std::string Name() { return "DummyReader"; };
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
/// Open File - which is called by the constructor automatically
void Open();
diff --git a/include/EffectBase.h b/include/EffectBase.h
index 29e98b589..1f967a021 100644
--- a/include/EffectBase.h
+++ b/include/EffectBase.h
@@ -50,7 +50,6 @@ namespace openshot
struct EffectInfoStruct
{
std::string class_name; ///< The class name of the effect
- std::string short_name; ///< A short name of the effect, commonly used for icon names, etc...
std::string name; ///< The name of the effect
std::string description; ///< The description of this effect and what it does
bool has_video; ///< Determines if this effect manipulates the image of a frame
@@ -95,14 +94,14 @@ namespace openshot
void InitEffectInfo();
/// Get and Set JSON methods
- virtual std::string Json() = 0; ///< Generate JSON string of this object
- virtual void SetJson(std::string value) = 0; ///< Load JSON string into this object
- virtual Json::Value JsonValue() = 0; ///< Generate Json::JsonValue for this object
- virtual void SetJsonValue(Json::Value root) = 0; ///< Load Json::JsonValue into this object
- Json::Value JsonInfo(); ///< Generate JSON object of meta data / info
+ virtual std::string Json() const = 0; ///< Generate JSON string of this object
+ virtual void SetJson(const std::string value) = 0; ///< Load JSON string into this object
+ virtual Json::Value JsonValue() const = 0; ///< Generate Json::Value for this object
+ virtual void SetJsonValue(const Json::Value root) = 0; ///< Load Json::Value into this object
+ Json::Value JsonInfo() const; ///< Generate JSON object of meta data / info
/// Get the order that this effect should be executed.
- int Order() { return order; }
+ int Order() const { return order; }
/// Set the order that this effect should be executed.
void Order(int new_order) { order = new_order; }
diff --git a/include/EffectInfo.h b/include/EffectInfo.h
index 1015b0da7..0e64327bb 100644
--- a/include/EffectInfo.h
+++ b/include/EffectInfo.h
@@ -51,7 +51,7 @@ namespace openshot
/// JSON methods
static std::string Json(); ///< Generate JSON string of this object
- static Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
+ static Json::Value JsonValue(); ///< Generate Json::Value for this object
};
diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h
index 9faa86a35..e9cee5793 100644
--- a/include/FFmpegReader.h
+++ b/include/FFmpegReader.h
@@ -76,11 +76,11 @@ namespace openshot {
*
* @code
* // Create a reader for a video
- * FFmpegReader r("MyAwesomeVideo.webm");
+ * openshot::FFmpegReader r("MyAwesomeVideo.webm");
* r.Open(); // Open the reader
*
* // Get frame number 1 from the video
- * std::shared_ptr f = r.GetFrame(1);
+ * std::shared_ptr f = r.GetFrame(1);
*
* // Now that we have an openshot::Frame object, lets have some fun!
* f->Display(); // Display the frame on the screen
@@ -98,7 +98,7 @@ namespace openshot {
AVFormatContext *pFormatCtx;
int i, videoStream, audioStream;
AVCodecContext *pCodecCtx, *aCodecCtx;
-#if (LIBAVFORMAT_VERSION_MAJOR >= 57)
+#if HAVE_HW_ACCEL
AVBufferRef *hw_device_ctx = NULL; //PM
#endif
AVStream *pStream, *aStream;
@@ -147,12 +147,11 @@ namespace openshot {
int64_t current_video_frame; // can't reliably use PTS of video to determine this
int hw_de_supported = 0; // Is set by FFmpegReader
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
AVPixelFormat hw_de_av_pix_fmt = AV_PIX_FMT_NONE;
AVHWDeviceType hw_de_av_device_type = AV_HWDEVICE_TYPE_NONE;
-#endif
-
int IsHardwareDecodeSupported(int codecid);
+#endif
/// Check for the correct frames per second value by scanning the 1st few seconds of video packets.
void CheckFPS();
@@ -265,10 +264,10 @@ namespace openshot {
std::string Name() { return "FFmpegReader"; };
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
/// Open File - which is called by the constructor automatically
void Open();
diff --git a/include/FFmpegUtilities.h b/include/FFmpegUtilities.h
index c673305eb..62d64df17 100644
--- a/include/FFmpegUtilities.h
+++ b/include/FFmpegUtilities.h
@@ -40,6 +40,10 @@
#ifndef IS_FFMPEG_3_2
#define IS_FFMPEG_3_2 (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 64, 101))
#endif
+
+ #ifndef HAVE_HW_ACCEL
+ #define HAVE_HW_ACCEL (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 107, 100))
+ #endif
// Include the FFmpeg headers
extern "C" {
diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h
index dc3a2cf7b..1dfb21a93 100644
--- a/include/FFmpegWriter.h
+++ b/include/FFmpegWriter.h
@@ -75,15 +75,19 @@ namespace openshot {
* @code SIMPLE EXAMPLE
*
* // Create a reader for a video
- * FFmpegReader r("MyAwesomeVideo.webm");
- * r.Open(); // Open thetarget_ reader
+ * openshot::FFmpegReader r("MyAwesomeVideo.webm");
+ * r.Open(); // Open the target reader
*
* // Create a writer (which will create a WebM video)
- * FFmpegWriter w("/home/jonathan/NewVideo.webm");
+ * openshot::FFmpegWriter w("/home/jonathan/NewVideo.webm");
*
* // Set options
- * w.SetAudioOptions(true, "libvorbis", 44100, 2, ChannelLayout::LAYOUT_STEREO, 128000); // Sample Rate: 44100, Channels: 2, Bitrate: 128000
- * w.SetVideoOptions(true, "libvpx", openshot::Fraction(24,1), 720, 480, openshot::Fraction(1,1), false, false, 300000); // FPS: 24, Size: 720x480, Pixel Ratio: 1/1, Bitrate: 300000
+ *
+ * // Sample Rate: 44100, Channels: 2, Bitrate: 128000
+ * w.SetAudioOptions(true, "libvorbis", 44100, 2, openshot::ChannelLayout::LAYOUT_STEREO, 128000);
+ *
+ * // FPS: 24, Size: 720x480, Pixel Ratio: 1/1, Bitrate: 300000
+ * w.SetVideoOptions(true, "libvpx", openshot::Fraction(24,1), 720, 480, openshot::Fraction(1,1), false, false, 300000);
*
* // Open the writer
* w.Open();
@@ -102,15 +106,19 @@ namespace openshot {
* @code ADVANCED WRITER EXAMPLE
*
* // Create a reader for a video
- * FFmpegReader r("MyAwesomeVideo.webm");
+ * openshot::FFmpegReader r("MyAwesomeVideo.webm");
* r.Open(); // Open the reader
*
* // Create a writer (which will create a WebM video)
- * FFmpegWriter w("/home/jonathan/NewVideo.webm");
+ * openshot::FFmpegWriter w("/home/jonathan/NewVideo.webm");
*
* // Set options
- * w.SetAudioOptions(true, "libvorbis", 44100, 2, ChannelLayout::LAYOUT_STEREO, 128000); // Sample Rate: 44100, Channels: 2, Bitrate: 128000
- * w.SetVideoOptions(true, "libvpx", openshot::Fraction(24,1), 720, 480, openshot::Fraction(1,1), false, false, 300000); // FPS: 24, Size: 720x480, Pixel Ratio: 1/1, Bitrate: 300000
+ *
+ * // Sample Rate: 44100, Channels: 2, Bitrate: 128000
+ * w.SetAudioOptions(true, "libvorbis", 44100, 2, openshot::ChannelLayout::LAYOUT_STEREO, 128000);
+ *
+ * // FPS: 24, Size: 720x480, Pixel Ratio: 1/1, Bitrate: 300000
+ * w.SetVideoOptions(true, "libvpx", openshot::Fraction(24,1), 720, 480, openshot::Fraction(1,1), false, false, 300000);
*
* // Prepare Streams (Optional method that must be called before any SetOption calls)
* w.PrepareStreams();
@@ -285,8 +293,21 @@ namespace openshot {
/// @param channels The number of audio channels needed in this file
/// @param channel_layout The 'layout' of audio channels (i.e. mono, stereo, surround, etc...)
/// @param bit_rate The audio bit rate used during encoding
+ ///
+ /// \note This is an overloaded function.
void SetAudioOptions(bool has_audio, std::string codec, int sample_rate, int channels, openshot::ChannelLayout channel_layout, int bit_rate);
+ /// @brief Set audio export options.
+ ///
+ /// Enables the stream and configures a default 2-channel stereo layout.
+ ///
+ /// @param codec The codec used to encode the audio for this file
+ /// @param sample_rate The number of audio samples needed in this file
+ /// @param bit_rate The audio bit rate used during encoding
+ ///
+ /// \note This is an overloaded function.
+ void SetAudioOptions(std::string codec, int sample_rate, int bit_rate);
+
/// @brief Set the cache size
/// @param new_size The number of frames to queue before writing to the file
void SetCacheSize(int new_size) { cache_size = new_size; };
@@ -301,10 +322,27 @@ namespace openshot {
/// @param interlaced Does this video need to be interlaced?
/// @param top_field_first Which frame should be used as the top field?
/// @param bit_rate The video bit rate used during encoding
+ ///
+ /// \note This is an overloaded function.
void SetVideoOptions(bool has_video, std::string codec, openshot::Fraction fps, int width, int height, openshot::Fraction pixel_ratio, bool interlaced, bool top_field_first, int bit_rate);
+ /// @brief Set video export options.
+ ///
+ /// Enables the stream and configures non-interlaced video with a 1:1 pixel aspect ratio.
+ ///
+ /// @param codec The codec used to encode the images in this video
+ /// @param width The width in pixels of this video
+ /// @param height The height in pixels of this video
+ /// @param fps The number of frames per second
+ /// @param bit_rate The video bit rate used during encoding
+ ///
+ /// \note This is an overloaded function.
+ /// \warning Observe the argument order, which is consistent with the openshot::Timeline constructor, but differs from the other signature.
+ void SetVideoOptions(std::string codec, int width, int height, openshot::Fraction fps, int bit_rate);
+
/// @brief Set custom options (some codecs accept additional params). This must be called after the
/// PrepareStreams() method, otherwise the streams have not been initialized yet.
+ ///
/// @param stream The stream (openshot::StreamType) this option should apply to
/// @param name The name of the option you want to set (i.e. qmin, qmax, etc...)
/// @param value The new value of this option
@@ -316,12 +354,16 @@ namespace openshot {
/// @brief Add a frame to the stack waiting to be encoded.
/// @param frame The openshot::Frame object to write to this image
+ ///
+ /// \note This is an overloaded function.
void WriteFrame(std::shared_ptr frame);
/// @brief Write a block of frames from a reader
/// @param reader A openshot::ReaderBase object which will provide frames to be written
/// @param start The starting frame number of the reader
/// @param length The number of frames to write
+ ///
+ /// \note This is an overloaded function.
void WriteFrame(openshot::ReaderBase *reader, int64_t start, int64_t length);
/// @brief Write the file trailer (after all frames are written). This is called automatically
diff --git a/include/Frame.h b/include/Frame.h
index b9b989a50..f4ff54d44 100644
--- a/include/Frame.h
+++ b/include/Frame.h
@@ -31,15 +31,6 @@
#ifndef OPENSHOT_FRAME_H
#define OPENSHOT_FRAME_H
-/// Do not include the juce unittest headers, because it collides with unittest++
-#ifndef __JUCE_UNITTEST_JUCEHEADER__
- #define __JUCE_UNITTEST_JUCEHEADER__
-#endif
-#ifndef _NDEBUG
- // Define NO debug for JUCE on mac os
- #define _NDEBUG
-#endif
-
#include
#include
#include
diff --git a/include/FrameMapper.h b/include/FrameMapper.h
index f2b030a36..8be4ec1bd 100644
--- a/include/FrameMapper.h
+++ b/include/FrameMapper.h
@@ -199,10 +199,10 @@ namespace openshot
std::string Name() { return "FrameMapper"; };
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
/// Open the internal reader
void Open();
diff --git a/include/ImageReader.h b/include/ImageReader.h
index 8da450eb7..bb19dd3dc 100644
--- a/include/ImageReader.h
+++ b/include/ImageReader.h
@@ -106,10 +106,10 @@ namespace openshot
std::string Name() { return "ImageReader"; };
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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
/// Open File - which is called by the constructor automatically
void Open();
diff --git a/include/Json.h b/include/Json.h
index 3a10ab744..0bdf6e2c3 100644
--- a/include/Json.h
+++ b/include/Json.h
@@ -31,6 +31,12 @@
#ifndef OPENSHOT_JSON_H
#define OPENSHOT_JSON_H
+#include
#include "json/json.h"
+#include "Exceptions.h"
+
+namespace openshot {
+ const Json::Value stringToJson(const std::string value);
+}
#endif
diff --git a/include/KeyFrame.h b/include/KeyFrame.h
index 6ed395530..ee58da8f0 100644
--- a/include/KeyFrame.h
+++ b/include/KeyFrame.h
@@ -133,9 +133,9 @@ namespace openshot {
/// Get and Set JSON methods
std::string Json() const; ///< Generate JSON string of this object
- Json::Value JsonValue() const; ///< Generate Json::JsonValue for this object
- void SetJson(std::string value); ///< Load JSON string into this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ Json::Value JsonValue() const; ///< Generate Json::Value for this object
+ void SetJson(const std::string value); ///< Load JSON string into this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
/// Remove a point by matching a coordinate
void RemovePoint(Point p);
diff --git a/include/Point.h b/include/Point.h
index 3fdcd9176..4941c5589 100644
--- a/include/Point.h
+++ b/include/Point.h
@@ -119,10 +119,10 @@ namespace openshot
void Initialize_RightHandle(float x, float y);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJson(std::string value); ///< Load JSON string into this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ std::string Json() const; ///< Generate JSON string of this object
+ Json::Value JsonValue() const; ///< Generate Json::Value for this object
+ void SetJson(const std::string value); ///< Load JSON string into this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
};
diff --git a/include/Profiles.h b/include/Profiles.h
index bc5fe3e01..3b5ebd0d1 100644
--- a/include/Profiles.h
+++ b/include/Profiles.h
@@ -90,10 +90,10 @@ namespace openshot
Profile(std::string path);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJson(std::string value); ///< Load JSON string into this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ std::string Json() const; ///< Generate JSON string of this object
+ Json::Value JsonValue() const; ///< Generate Json::Value for this object
+ void SetJson(const std::string value); ///< Load JSON string into this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
};
}
diff --git a/include/QtHtmlReader.h b/include/QtHtmlReader.h
index c102038c4..d7052d494 100644
--- a/include/QtHtmlReader.h
+++ b/include/QtHtmlReader.h
@@ -131,10 +131,10 @@ namespace openshot
std::string Name() { return "QtHtmlReader"; };
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
/// Open Reader - which is called by the constructor automatically
void Open();
diff --git a/include/QtImageReader.h b/include/QtImageReader.h
index 3153e7a39..3e456e394 100644
--- a/include/QtImageReader.h
+++ b/include/QtImageReader.h
@@ -104,10 +104,10 @@ namespace openshot
std::string Name() { return "QtImageReader"; };
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
/// Open File - which is called by the constructor automatically
void Open();
diff --git a/include/QtTextReader.h b/include/QtTextReader.h
index e6a8c84b8..d226e920c 100644
--- a/include/QtTextReader.h
+++ b/include/QtTextReader.h
@@ -142,10 +142,10 @@ namespace openshot
std::string Name() { return "QtTextReader"; };
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
/// Open Reader - which is called by the constructor automatically
void Open();
diff --git a/include/ReaderBase.h b/include/ReaderBase.h
index 267693388..dfb9873d4 100644
--- a/include/ReaderBase.h
+++ b/include/ReaderBase.h
@@ -140,10 +140,10 @@ namespace openshot
virtual std::string Name() = 0;
/// Get and Set JSON methods
- virtual std::string Json() = 0; ///< Generate JSON string of this object
- virtual void SetJson(std::string value) = 0; ///< Load JSON string into this object
- virtual Json::Value JsonValue() = 0; ///< Generate Json::JsonValue for this object
- virtual void SetJsonValue(Json::Value root) = 0; ///< Load Json::JsonValue into this object
+ virtual std::string Json() const = 0; ///< Generate JSON string of this object
+ virtual void SetJson(const std::string value) = 0; ///< Load JSON string into this object
+ virtual Json::Value JsonValue() const = 0; ///< Generate Json::Value for this object
+ virtual void SetJsonValue(const Json::Value root) = 0; ///< Load Json::Value into this object
/// Open the reader (and start consuming resources, such as images or video files)
virtual void Open() = 0;
diff --git a/include/Settings.h b/include/Settings.h
index 56a84fd7a..e82bf56bb 100644
--- a/include/Settings.h
+++ b/include/Settings.h
@@ -124,6 +124,10 @@ namespace openshot {
/// The audio device name to use during playback
std::string PLAYBACK_AUDIO_DEVICE_NAME = "";
+ /// The current install path of OpenShot (needs to be set when using Timeline(path), since certain
+ /// paths depend on the location of OpenShot transitions and files)
+ std::string PATH_OPENSHOT_INSTALL = "";
+
/// Create or get an instance of this logger singleton (invoke the class with this method)
static Settings * Instance();
};
diff --git a/include/TextReader.h b/include/TextReader.h
index 2d54fdc25..b6dbf5cd0 100644
--- a/include/TextReader.h
+++ b/include/TextReader.h
@@ -119,7 +119,7 @@ namespace openshot
TextReader(int width, int height, int x_offset, int y_offset, GravityType gravity, std::string text, std::string font, double size, std::string text_color, std::string background_color);
/// Draw a box under rendered text using the specified color.
- /// @param text_background_color The background color behind the text
+ /// @param color The background color behind the text
void SetTextBackgroundColor(std::string color);
/// Close Reader
@@ -142,10 +142,10 @@ namespace openshot
std::string Name() { return "TextReader"; };
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
/// Open Reader - which is called by the constructor automatically
void Open();
diff --git a/include/Timeline.h b/include/Timeline.h
index 2ff03d919..56a895866 100644
--- a/include/Timeline.h
+++ b/include/Timeline.h
@@ -36,6 +36,7 @@
#include
#include
#include
+#include
#include "CacheBase.h"
#include "CacheDisk.h"
#include "CacheMemory.h"
@@ -156,6 +157,7 @@ namespace openshot {
CacheBase *final_cache; /// allocated_frame_mappers; ///< all the frame mappers we allocated and must free
bool managed_cache; ///< Does this timeline instance manage the cache object
+ std::string path; ///< Optional path of loaded UTF-8 OpenShot JSON project file
/// Process a new layer of video or audio
void add_layer(std::shared_ptr new_frame, Clip* source_clip, int64_t clip_frame_number, int64_t timeline_frame_number, bool is_top_clip, float max_volume);
@@ -209,6 +211,11 @@ namespace openshot {
/// @param channel_layout The channel layout (i.e. mono, stereo, 3 point surround, etc...)
Timeline(int width, int height, Fraction fps, int sample_rate, int channels, ChannelLayout channel_layout);
+ /// @brief Constructor for the timeline (which loads a JSON structure from a file path, and initializes a timeline)
+ /// @param projectPath The path of the UTF-8 *.osp project file (JSON contents). Contents will be loaded automatically.
+ /// @param convert_absolute_paths Should all paths be converted to absolute paths (based on the folder of the path provided)
+ Timeline(std::string projectPath, bool convert_absolute_paths);
+
virtual ~Timeline();
/// @brief Add an openshot::Clip to the timeline
@@ -268,10 +275,10 @@ namespace openshot {
std::string Name() { return "Timeline"; };
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
/// Set Max Image Size (used for performance optimization). Convenience function for setting
/// Settings::Instance()->MAX_WIDTH and Settings::Instance()->MAX_HEIGHT.
diff --git a/include/WriterBase.h b/include/WriterBase.h
index 503be6bfb..1b55c72b6 100644
--- a/include/WriterBase.h
+++ b/include/WriterBase.h
@@ -107,10 +107,10 @@ namespace openshot
virtual void WriteFrame(openshot::ReaderBase* reader, int64_t start, int64_t length) = 0;
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJson(std::string value); ///< Load JSON string into this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ std::string Json() const; ///< Generate JSON string of this object
+ Json::Value JsonValue() const; ///< Generate Json::Value for this object
+ void SetJson(const std::string value); ///< Load JSON string into this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
/// Display file information in the standard output stream (stdout)
void DisplayInfo();
diff --git a/include/effects/Bars.h b/include/effects/Bars.h
index 43a77a2ff..fa9df6f80 100644
--- a/include/effects/Bars.h
+++ b/include/effects/Bars.h
@@ -89,14 +89,14 @@ namespace openshot
std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< 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)
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
};
}
diff --git a/include/effects/Blur.h b/include/effects/Blur.h
index 167e93032..c254b8cde 100644
--- a/include/effects/Blur.h
+++ b/include/effects/Blur.h
@@ -67,7 +67,6 @@ namespace openshot
void init_effect_details();
/// Internal blur methods (inspired and credited to http://blog.ivank.net/fastest-gaussian-blur.html)
- int* initBoxes(float sigma, int n);
void boxBlurH(unsigned char *scl, unsigned char *tcl, int w, int h, int r);
void boxBlurT(unsigned char *scl, unsigned char *tcl, int w, int h, int r);
@@ -102,14 +101,14 @@ namespace openshot
std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< 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)
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
};
}
diff --git a/include/effects/Brightness.h b/include/effects/Brightness.h
index 2a6ab9129..69f2cf343 100644
--- a/include/effects/Brightness.h
+++ b/include/effects/Brightness.h
@@ -89,14 +89,14 @@ namespace openshot
std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< 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)
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
};
}
diff --git a/include/effects/ChromaKey.h b/include/effects/ChromaKey.h
index d0fa31d84..dbc81e9cf 100644
--- a/include/effects/ChromaKey.h
+++ b/include/effects/ChromaKey.h
@@ -86,13 +86,13 @@ namespace openshot
std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
// Get all properties for a specific frame
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
};
}
diff --git a/include/effects/ColorShift.h b/include/effects/ColorShift.h
index e9c11d68e..ada2acd68 100644
--- a/include/effects/ColorShift.h
+++ b/include/effects/ColorShift.h
@@ -93,14 +93,14 @@ namespace openshot
std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< 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)
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
};
}
diff --git a/include/effects/Crop.h b/include/effects/Crop.h
index 34cea89f5..2d4a2b2ee 100644
--- a/include/effects/Crop.h
+++ b/include/effects/Crop.h
@@ -88,14 +88,14 @@ namespace openshot
std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< 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)
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
};
}
diff --git a/include/effects/Deinterlace.h b/include/effects/Deinterlace.h
index b411b0230..eff7b2fe7 100644
--- a/include/effects/Deinterlace.h
+++ b/include/effects/Deinterlace.h
@@ -82,13 +82,13 @@ namespace openshot
std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
// Get all properties for a specific frame
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
};
}
diff --git a/include/effects/Hue.h b/include/effects/Hue.h
index 4670b6bff..9d86d5c2b 100644
--- a/include/effects/Hue.h
+++ b/include/effects/Hue.h
@@ -79,14 +79,14 @@ namespace openshot
std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< 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)
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
};
}
diff --git a/include/effects/Mask.h b/include/effects/Mask.h
index dba3b2d89..390ffa361 100644
--- a/include/effects/Mask.h
+++ b/include/effects/Mask.h
@@ -101,14 +101,14 @@ namespace openshot
std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< 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)
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
/// Get the reader object of the mask grayscale image
ReaderBase* Reader() { return reader; };
diff --git a/include/effects/Negate.h b/include/effects/Negate.h
index 3cbc7988d..6206a6607 100644
--- a/include/effects/Negate.h
+++ b/include/effects/Negate.h
@@ -70,13 +70,13 @@ namespace openshot
std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object
// Get all properties for a specific frame
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
};
}
diff --git a/include/effects/Pixelate.h b/include/effects/Pixelate.h
index 3146d456c..9348ce863 100644
--- a/include/effects/Pixelate.h
+++ b/include/effects/Pixelate.h
@@ -88,14 +88,14 @@ namespace openshot
std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< 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)
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
};
}
diff --git a/include/effects/Saturation.h b/include/effects/Saturation.h
index de3cc7714..e8d0d9409 100644
--- a/include/effects/Saturation.h
+++ b/include/effects/Saturation.h
@@ -86,14 +86,14 @@ namespace openshot
std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< 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)
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
};
}
diff --git a/include/effects/Shift.h b/include/effects/Shift.h
index 243e442eb..765da7555 100644
--- a/include/effects/Shift.h
+++ b/include/effects/Shift.h
@@ -82,14 +82,14 @@ namespace openshot
std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< 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)
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
};
}
diff --git a/include/effects/Wave.h b/include/effects/Wave.h
index 62b08d1fa..ad516bde3 100644
--- a/include/effects/Wave.h
+++ b/include/effects/Wave.h
@@ -88,14 +88,14 @@ namespace openshot
std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Get and Set JSON methods
- std::string Json(); ///< Generate JSON string of this object
- void SetJson(std::string value); ///< Load JSON string into this object
- Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
- void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object
+ 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 override; ///< Generate Json::Value for this object
+ void SetJsonValue(const Json::Value root); ///< 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)
- std::string PropertiesJSON(int64_t requested_frame);
+ std::string PropertiesJSON(int64_t requested_frame) const override;
};
}
diff --git a/src/AudioBufferSource.cpp b/src/AudioBufferSource.cpp
index 46b04916e..2f3d14ca3 100644
--- a/src/AudioBufferSource.cpp
+++ b/src/AudioBufferSource.cpp
@@ -43,7 +43,7 @@ AudioBufferSource::~AudioBufferSource()
{
// forget the AudioSampleBuffer. It still exists; we just don't know about it.
buffer = NULL;
-};
+}
// Get the next block of audio samples
void AudioBufferSource::getNextAudioBlock (const juce::AudioSourceChannelInfo& info)
diff --git a/src/AudioReaderSource.cpp b/src/AudioReaderSource.cpp
index 41c0b3f6b..c96d0bcc3 100644
--- a/src/AudioReaderSource.cpp
+++ b/src/AudioReaderSource.cpp
@@ -51,7 +51,7 @@ AudioReaderSource::~AudioReaderSource()
// Clear and delete the buffer
delete buffer;
buffer = NULL;
-};
+}
// Get more samples from the reader
void AudioReaderSource::GetMoreSamplesFromReader()
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0de15ded5..a57780b0d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -27,31 +27,25 @@
# Collect and display summary of options/dependencies
include(FeatureSummary)
-################ OPTIONS ##################
-# Optional build settings for libopenshot
-option(USE_SYSTEM_JSONCPP "Use system installed JsonCpp, if found" ON)
-option(DISABLE_BUNDLED_JSONCPP "Don't fall back to bundled JsonCpp" OFF)
-option(ENABLE_IWYU "Enable 'Include What You Use' scanner (CMake 3.3+)" OFF)
-
-# Automatically process Qt classes with meta-object compiler
-set(CMAKE_AUTOMOC True)
+include(GNUInstallDirs)
################ WINDOWS ##################
# Set some compiler options for Windows
# required for libopenshot-audio headers
-IF (WIN32)
+if (WIN32)
add_definitions( -DIGNORE_JUCE_HYPOT=1 )
- SET(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -include cmath")
-ENDIF(WIN32)
-IF (APPLE)
+ set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -include cmath")
+endif()
+
+if (APPLE)
# If you still get errors compiling with GCC 4.8, mac headers need to be patched: http://hamelot.co.uk/programming/osx-gcc-dispatch_block_t-has-not-been-declared-invalid-typedef/
- SET_PROPERTY(GLOBAL PROPERTY JUCE_MAC "JUCE_MAC")
- ADD_DEFINITIONS(-DNDEBUG)
- SET(EXTENSION "mm")
+ 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")
-ENDIF(APPLE)
+ 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")
+endif()
################ IMAGE MAGICK ##################
# Set the Quantum Depth that ImageMagick was built with (default to 16 bits)
@@ -72,52 +66,40 @@ ELSE (OPENSHOT_IMAGEMAGICK_COMPATIBILITY)
ENDIF (OPENSHOT_IMAGEMAGICK_COMPATIBILITY)
# Find the ImageMagick++ library
-FIND_PACKAGE(ImageMagick COMPONENTS Magick++ MagickWand MagickCore)
-IF (ImageMagick_FOUND)
+find_package(ImageMagick COMPONENTS Magick++ MagickWand MagickCore)
+if (ImageMagick_FOUND)
# Include ImageMagick++ headers (needed for compile)
include_directories(${ImageMagick_INCLUDE_DIRS})
# define a global var (used in the C++)
add_definitions( -DUSE_IMAGEMAGICK=1 )
- SET(CMAKE_SWIG_FLAGS "-DUSE_IMAGEMAGICK=1")
+ set(CMAKE_SWIG_FLAGS "-DUSE_IMAGEMAGICK=1")
-ENDIF (ImageMagick_FOUND)
+endif()
################# LIBOPENSHOT-AUDIO ###################
# Find JUCE-based openshot Audio libraries
-FIND_PACKAGE(OpenShotAudio 0.1.8 REQUIRED)
+find_package(OpenShotAudio 0.2.0 REQUIRED)
# Include Juce headers (needed for compile)
include_directories(${LIBOPENSHOT_AUDIO_INCLUDE_DIRS})
################# BLACKMAGIC DECKLINK ###################
# Find BlackMagic DeckLinkAPI libraries
-IF (ENABLE_BLACKMAGIC)
- FIND_PACKAGE(BlackMagic)
+if (ENABLE_BLACKMAGIC)
- IF (BLACKMAGIC_FOUND)
+ find_package(BlackMagic)
+
+ if (BLACKMAGIC_FOUND)
# Include Blackmagic headers (needed for compile)
include_directories(${BLACKMAGIC_INCLUDE_DIR})
# define a global var (used in the C++)
add_definitions( -DUSE_BLACKMAGIC=1 )
- SET(CMAKE_SWIG_FLAGS "-DUSE_BLACKMAGIC=1")
-
- ENDIF (BLACKMAGIC_FOUND)
-ENDIF (ENABLE_BLACKMAGIC)
-
-################### RESVG #####################
-# Find resvg library (used for rendering svg files)
-FIND_PACKAGE(RESVG)
-
-# Include resvg headers (optional SVG library)
-if (RESVG_FOUND)
- include_directories(${RESVG_INCLUDE_DIRS})
+ set(CMAKE_SWIG_FLAGS "-DUSE_BLACKMAGIC=1")
+ endif()
- # define a global var (used in the C++)
- add_definitions( -DUSE_RESVG=1 )
- SET(CMAKE_SWIG_FLAGS "-DUSE_RESVG=1")
-endif(RESVG_FOUND)
+endif()
############### PROFILING #################
#set(PROFILER "/usr/lib/libprofiler.so.0.3.2")
@@ -169,6 +151,7 @@ set(OPENSHOT_SOURCES
Fraction.cpp
Frame.cpp
FrameMapper.cpp
+ Json.cpp
KeyFrame.cpp
OpenShotVersion.cpp
ZmqLogger.cpp
@@ -209,30 +192,30 @@ set(QT_PLAYER_SOURCES
Qt/VideoRenderer.cpp
Qt/VideoRenderWidget.cpp)
-
-# Get list of headers
-file(GLOB_RECURSE headers ${CMAKE_SOURCE_DIR}/include/*.h)
+# Get list of MOC'able headers
+file(GLOB_RECURSE OPENSHOT_QT_HEADERS ${CMAKE_SOURCE_DIR}/include/Qt/*.h)
# Disable RPATH
-SET(CMAKE_MACOSX_RPATH 0)
+set(CMAKE_MACOSX_RPATH 0)
############### CREATE LIBRARY #################
# Create shared openshot library
add_library(openshot SHARED)
-target_sources(openshot
- PRIVATE
- ${OPENSHOT_SOURCES} ${EFFECTS_SOURCES} ${QT_PLAYER_SOURCES}
- PUBLIC
- ${headers})
+target_sources(openshot PRIVATE
+ ${OPENSHOT_SOURCES}
+ ${EFFECTS_SOURCES}
+ ${QT_PLAYER_SOURCES}
+ ${OPENSHOT_QT_HEADERS}
+ )
# Set SONAME and other library properties
-set_target_properties(openshot
- PROPERTIES
- VERSION ${PROJECT_VERSION}
- SOVERSION ${PROJECT_SO_VERSION}
- INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib"
- )
+set_target_properties(openshot PROPERTIES
+ AUTOMOC ON
+ VERSION ${PROJECT_VERSION}
+ SOVERSION ${PROJECT_SO_VERSION}
+ INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib"
+ )
# Add optional ImageMagic-dependent sources
if(ImageMagick_FOUND)
@@ -313,7 +296,7 @@ endforeach()
################### FFMPEG #####################
# Find FFmpeg libraries (used for video encoding / decoding)
-FIND_PACKAGE(FFmpeg REQUIRED COMPONENTS avcodec avdevice avformat avutil swscale)
+find_package(FFmpeg REQUIRED COMPONENTS avcodec avdevice avformat avutil swscale)
foreach(ff_comp avcodec avdevice avformat avfilter avutil postproc swscale swresample avresample)
if(TARGET FFmpeg::${ff_comp})
@@ -362,6 +345,26 @@ if (TARGET cppzmq)
target_link_libraries(openshot PUBLIC cppzmq)
endif()
+################### RESVG #####################
+# Migrate some legacy variable names
+if(DEFINED RESVGDIR AND NOT DEFINED RESVG_ROOT)
+ set(RESVG_ROOT ${RESVGDIR})
+endif()
+if(DEFINED ENV{RESVGDIR} AND NOT DEFINED RESVG_ROOT)
+ set(RESVG_ROOT $ENV{RESVGDIR})
+endif()
+
+# Find resvg library (used for rendering svg files)
+FIND_PACKAGE(RESVG)
+
+# Include resvg headers (optional SVG library)
+if (TARGET RESVG::resvg)
+ #include_directories(${RESVG_INCLUDE_DIRS})
+ target_link_libraries(openshot PUBLIC RESVG::resvg)
+
+ target_compile_definitions(openshot PUBLIC "-DUSE_RESVG=1")
+ set(CMAKE_SWIG_FLAGS "-DUSE_RESVG=1")
+endif()
############### LINK LIBRARY #################
# Link remaining dependency libraries
@@ -373,10 +376,6 @@ if(ImageMagick_FOUND)
target_link_libraries(openshot PUBLIC ${ImageMagick_LIBRARIES})
endif()
-if(RESVG_FOUND)
- target_link_libraries(openshot PUBLIC ${RESVG_LIBRARIES})
-endif()
-
if(BLACKMAGIC_FOUND)
target_link_libraries(openshot PUBLIC ${BLACKMAGIC_LIBRARY_DIR})
endif()
@@ -393,9 +392,9 @@ add_executable(openshot-example examples/Example.cpp)
# Define path to test input files
SET(TEST_MEDIA_PATH "${PROJECT_SOURCE_DIR}/src/examples/")
-IF (WIN32)
+if (WIN32)
STRING(REPLACE "/" "\\\\" TEST_MEDIA_PATH TEST_MEDIA_PATH)
-ENDIF(WIN32)
+endif()
target_compile_definitions(openshot-example PRIVATE
-DTEST_MEDIA_PATH="${TEST_MEDIA_PATH}" )
@@ -413,48 +412,40 @@ add_executable(openshot-player Qt/demo/main.cpp)
target_link_libraries(openshot-player openshot)
############### TEST BLACKMAGIC CAPTURE APP ################
-IF (BLACKMAGIC_FOUND)
+if (BLACKMAGIC_FOUND)
# Create test executable
add_executable(openshot-blackmagic
examples/ExampleBlackmagic.cpp)
# Link test executable to the new library
target_link_libraries(openshot-blackmagic openshot)
-ENDIF (BLACKMAGIC_FOUND)
+endif()
############### INCLUDE SWIG BINDINGS ################
add_subdirectory(bindings)
-########### PRINT FEATURE SUMMARY ##############
-feature_summary(WHAT ALL
- INCLUDE_QUIET_PACKAGES
- FATAL_ON_MISSING_REQUIRED_PACKAGES
- DESCRIPTION "Displaying feature summary\n\nBuild configuration:")
-
############### INSTALL HEADERS & LIBRARY ################
-set(LIB_INSTALL_DIR lib${LIB_SUFFIX}) # determine correct lib folder
# Install primary library
-INSTALL(TARGETS openshot
- ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
- LIBRARY DESTINATION ${LIB_INSTALL_DIR}
- RUNTIME DESTINATION ${LIB_INSTALL_DIR}
- COMPONENT library )
+install(TARGETS openshot
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR})
-INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/include/
- DESTINATION ${CMAKE_INSTALL_PREFIX}/include/libopenshot
- FILES_MATCHING PATTERN "*.h")
+install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libopenshot
+ FILES_MATCHING PATTERN "*.h")
############### CPACK PACKAGING ##############
-IF(MINGW)
- SET(CPACK_GENERATOR "NSIS")
-ENDIF(MINGW)
-IF(UNIX AND NOT APPLE)
- SET(CPACK_GENERATOR "DEB")
-ENDIF(UNIX AND NOT APPLE)
-#IF(UNIX AND APPLE)
-# SET(CPACK_GENERATOR "DragNDrop")
-#ENDIF(UNIX AND APPLE)
-SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Jonathan Thomas") #required
-
-INCLUDE(CPack)
+if(MINGW)
+ set(CPACK_GENERATOR "NSIS")
+endif()
+if(UNIX AND NOT APPLE)
+ set(CPACK_GENERATOR "DEB")
+endif()
+#if(UNIX AND APPLE)
+# set(CPACK_GENERATOR "DragNDrop")
+#endif()
+set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Jonathan Thomas") #required
+
+include(CPack)
diff --git a/src/CacheBase.cpp b/src/CacheBase.cpp
index 8a7d541ae..bc57f3f45 100644
--- a/src/CacheBase.cpp
+++ b/src/CacheBase.cpp
@@ -37,13 +37,13 @@ using namespace openshot;
CacheBase::CacheBase() : max_bytes(0) {
// Init the critical section
cacheCriticalSection = new CriticalSection();
-};
+}
// Constructor that sets the max frames to cache
CacheBase::CacheBase(int64_t max_bytes) : max_bytes(max_bytes) {
// Init the critical section
cacheCriticalSection = new CriticalSection();
-};
+}
// Set maximum bytes to a different amount based on a ReaderInfo struct
void CacheBase::SetMaxBytesFromInfo(int64_t number_of_frames, int width, int height, int sample_rate, int channels)
@@ -53,7 +53,7 @@ void CacheBase::SetMaxBytesFromInfo(int64_t number_of_frames, int width, int hei
SetMaxBytes(bytes);
}
-// Generate Json::JsonValue for this object
+// Generate Json::Value for this object
Json::Value CacheBase::JsonValue() {
// Create root json object
@@ -66,8 +66,8 @@ Json::Value CacheBase::JsonValue() {
return root;
}
-// Load Json::JsonValue into this object
-void CacheBase::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void CacheBase::SetJsonValue(const Json::Value root) {
// Set data from Json (if key is found)
if (!root["max_bytes"].isNull())
diff --git a/src/CacheDisk.cpp b/src/CacheDisk.cpp
index 5dc677e56..9f67ce994 100644
--- a/src/CacheDisk.cpp
+++ b/src/CacheDisk.cpp
@@ -47,7 +47,7 @@ CacheDisk::CacheDisk(std::string cache_path, std::string format, float quality,
// Init path directory
InitPath(cache_path);
-};
+}
// Constructor that sets the max bytes to cache
CacheDisk::CacheDisk(std::string cache_path, std::string format, float quality, float scale, int64_t max_bytes) : CacheBase(max_bytes) {
@@ -62,7 +62,7 @@ CacheDisk::CacheDisk(std::string cache_path, std::string format, float quality,
// Init path directory
InitPath(cache_path);
-};
+}
// Initialize cache directory
void CacheDisk::InitPath(std::string cache_path) {
@@ -103,25 +103,19 @@ void CacheDisk::CalculateRanges() {
// Increment range version
range_version++;
- std::vector::iterator itr_ordered;
int64_t starting_frame = *ordered_frame_numbers.begin();
- int64_t ending_frame = *ordered_frame_numbers.begin();
+ int64_t ending_frame = starting_frame;
// Loop through all known frames (in sequential order)
- for (itr_ordered = ordered_frame_numbers.begin(); itr_ordered != ordered_frame_numbers.end(); ++itr_ordered) {
- int64_t frame_number = *itr_ordered;
+ for (const auto frame_number : ordered_frame_numbers) {
if (frame_number - ending_frame > 1) {
// End of range detected
Json::Value range;
// Add JSON object with start/end attributes
// Use strings, since int64_ts are supported in JSON
- std::stringstream start_str;
- start_str << starting_frame;
- std::stringstream end_str;
- end_str << ending_frame;
- range["start"] = start_str.str();
- range["end"] = end_str.str();
+ range["start"] = std::to_string(starting_frame);
+ range["end"] = std::to_string(ending_frame);
ranges.append(range);
// Set new starting range
@@ -137,12 +131,8 @@ void CacheDisk::CalculateRanges() {
// Add JSON object with start/end attributes
// Use strings, since int64_ts are supported in JSON
- std::stringstream start_str;
- start_str << starting_frame;
- std::stringstream end_str;
- end_str << ending_frame;
- range["start"] = start_str.str();
- range["end"] = end_str.str();
+ range["start"] = std::to_string(starting_frame);
+ range["end"] = std::to_string(ending_frame);
ranges.append(range);
// Cache range JSON as string
@@ -471,7 +461,7 @@ std::string CacheDisk::Json() {
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
+// Generate Json::Value for this object
Json::Value CacheDisk::JsonValue() {
// Process range data (if anything has changed)
@@ -488,41 +478,23 @@ Json::Value CacheDisk::JsonValue() {
root["version"] = range_version_str.str();
// Parse and append range data (if any)
- Json::Value ranges;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( json_ranges.c_str(),
- json_ranges.c_str() + json_ranges.size(), &ranges, &errors );
- delete reader;
-
- if (success)
+ // Parse and append range data (if any)
+ try {
+ const Json::Value ranges = openshot::stringToJson(json_ranges);
root["ranges"] = ranges;
+ } catch (...) { }
// return JsonValue
return root;
}
// Load JSON string into this object
-void CacheDisk::SetJson(std::string value) {
+void CacheDisk::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -533,8 +505,8 @@ void CacheDisk::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void CacheDisk::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void CacheDisk::SetJsonValue(const Json::Value root) {
// Close timeline before we do anything (this also removes all open and closing clips)
Clear();
diff --git a/src/CacheMemory.cpp b/src/CacheMemory.cpp
index ff8963fdc..70feef03d 100644
--- a/src/CacheMemory.cpp
+++ b/src/CacheMemory.cpp
@@ -39,7 +39,7 @@ CacheMemory::CacheMemory() : CacheBase(0) {
cache_type = "CacheMemory";
range_version = 0;
needs_range_processing = false;
-};
+}
// Constructor that sets the max bytes to cache
CacheMemory::CacheMemory(int64_t max_bytes) : CacheBase(max_bytes) {
@@ -47,7 +47,7 @@ CacheMemory::CacheMemory(int64_t max_bytes) : CacheBase(max_bytes) {
cache_type = "CacheMemory";
range_version = 0;
needs_range_processing = false;
-};
+}
// Default destructor
CacheMemory::~CacheMemory()
@@ -92,12 +92,8 @@ void CacheMemory::CalculateRanges() {
// Add JSON object with start/end attributes
// Use strings, since int64_ts are supported in JSON
- std::stringstream start_str;
- start_str << starting_frame;
- std::stringstream end_str;
- end_str << ending_frame;
- range["start"] = start_str.str();
- range["end"] = end_str.str();
+ range["start"] = std::to_string(starting_frame);
+ range["end"] = std::to_string(ending_frame);
ranges.append(range);
// Set new starting range
@@ -113,12 +109,8 @@ void CacheMemory::CalculateRanges() {
// Add JSON object with start/end attributes
// Use strings, since int64_ts are not supported in JSON
- std::stringstream start_str;
- start_str << starting_frame;
- std::stringstream end_str;
- end_str << ending_frame;
- range["start"] = start_str.str();
- range["end"] = end_str.str();
+ range["start"] = std::to_string(starting_frame);
+ range["end"] = std::to_string(ending_frame);
ranges.append(range);
// Cache range JSON as string
@@ -327,7 +319,7 @@ std::string CacheMemory::Json() {
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
+// Generate Json::Value for this object
Json::Value CacheMemory::JsonValue() {
// Process range data (if anything has changed)
@@ -337,45 +329,25 @@ Json::Value CacheMemory::JsonValue() {
Json::Value root = CacheBase::JsonValue(); // get parent properties
root["type"] = cache_type;
- std::stringstream range_version_str;
- range_version_str << range_version;
- root["version"] = range_version_str.str();
+ root["version"] = std::to_string(range_version);
// Parse and append range data (if any)
- Json::Value ranges;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( json_ranges.c_str(),
- json_ranges.c_str() + json_ranges.size(), &ranges, &errors );
- delete reader;
-
- if (success)
+ try {
+ const Json::Value ranges = openshot::stringToJson(json_ranges);
root["ranges"] = ranges;
+ } catch (...) { }
// return JsonValue
return root;
}
// Load JSON string into this object
-void CacheMemory::SetJson(std::string value) {
-
- // Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
+void CacheMemory::SetJson(const std::string value) {
try
{
+ // Parse string to Json::Value
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -386,8 +358,8 @@ void CacheMemory::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void CacheMemory::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void CacheMemory::SetJsonValue(const Json::Value root) {
// Close timeline before we do anything (this also removes all open and closing clips)
Clear();
diff --git a/src/ChunkReader.cpp b/src/ChunkReader.cpp
index 7321cb268..c194ce33a 100644
--- a/src/ChunkReader.cpp
+++ b/src/ChunkReader.cpp
@@ -256,14 +256,14 @@ std::shared_ptr ChunkReader::GetFrame(int64_t requested_frame)
}
// Generate JSON string of this object
-std::string ChunkReader::Json() {
+std::string ChunkReader::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value ChunkReader::JsonValue() {
+// Generate Json::Value for this object
+Json::Value ChunkReader::JsonValue() const {
// Create root json object
Json::Value root = ReaderBase::JsonValue(); // get parent properties
@@ -279,23 +279,11 @@ Json::Value ChunkReader::JsonValue() {
}
// Load JSON string into this object
-void ChunkReader::SetJson(std::string value) {
-
- // Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
+void ChunkReader::SetJson(const std::string value) {
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -306,8 +294,8 @@ void ChunkReader::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void ChunkReader::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void ChunkReader::SetJsonValue(const Json::Value root) {
// Set parent data
ReaderBase::SetJsonValue(root);
diff --git a/src/Clip.cpp b/src/Clip.cpp
index 45afd2aa5..1968bb3b1 100644
--- a/src/Clip.cpp
+++ b/src/Clip.cpp
@@ -38,6 +38,7 @@
#include "../include/QtImageReader.h"
#include "../include/ChunkReader.h"
#include "../include/DummyReader.h"
+#include "../include/Timeline.h"
using namespace openshot;
@@ -159,7 +160,7 @@ Clip::Clip(std::string path) : resampler(NULL), audio_cache(NULL), reader(NULL),
// Get file extension (and convert to lower case)
std::string ext = get_file_extension(path);
- transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
+ std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
// Determine if common video formats
if (ext=="avi" || ext=="mov" || ext=="mkv" || ext=="mpg" || ext=="mpeg" || ext=="mp3" || ext=="mp4" || ext=="mts" ||
@@ -172,6 +173,16 @@ Clip::Clip(std::string path) : resampler(NULL), audio_cache(NULL), reader(NULL),
} catch(...) { }
}
+ if (ext=="osp")
+ {
+ try
+ {
+ // Open common video format
+ reader = new Timeline(path, true);
+
+ } catch(...) { }
+ }
+
// If no video found, try each reader
if (!reader)
@@ -270,7 +281,7 @@ void Clip::Close()
}
// Get end position of clip (trim end of video), which can be affected by the time curve.
-float Clip::End()
+float Clip::End() const
{
// if a time curve is present, use its length
if (time.GetCount() > 1)
@@ -319,12 +330,10 @@ std::shared_ptr Clip::GetFrame(int64_t requested_frame)
// Now that we have re-mapped what frame number is needed, go and get the frame pointer
std::shared_ptr original_frame;
- #pragma omp critical (Clip_GetFrame)
original_frame = GetOrCreateFrame(new_frame_number);
// Create a new frame
std::shared_ptr frame(new Frame(new_frame_number, 1, 1, "#000000", original_frame->GetAudioSamplesCount(), original_frame->GetAudioChannelsCount()));
- #pragma omp critical (Clip_GetFrame)
{
frame->SampleRate(original_frame->SampleRate());
frame->ChannelsLayout(original_frame->ChannelsLayout());
@@ -645,14 +654,14 @@ std::shared_ptr Clip::GetOrCreateFrame(int64_t number)
}
// Generate JSON string of this object
-std::string Clip::Json() {
+std::string Clip::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
// Get all properties for a specific frame
-std::string Clip::PropertiesJSON(int64_t requested_frame) {
+std::string Clip::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
@@ -739,8 +748,8 @@ std::string Clip::PropertiesJSON(int64_t requested_frame) {
return root.toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Clip::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Clip::JsonValue() const {
// Create root json object
Json::Value root = ClipBase::JsonValue(); // get parent properties
@@ -782,40 +791,27 @@ Json::Value Clip::JsonValue() {
root["effects"] = Json::Value(Json::arrayValue);
// loop through effects
- std::list::iterator effect_itr;
- for (effect_itr=effects.begin(); effect_itr != effects.end(); ++effect_itr)
+ for (auto existing_effect : effects)
{
- // Get clip object from the iterator
- EffectBase *existing_effect = (*effect_itr);
root["effects"].append(existing_effect->JsonValue());
}
if (reader)
root["reader"] = reader->JsonValue();
+ else
+ root["reader"] = Json::Value(Json::objectValue);
// return JsonValue
return root;
}
// Load JSON string into this object
-void Clip::SetJson(std::string value) {
+void Clip::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -826,8 +822,8 @@ void Clip::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Clip::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Clip::SetJsonValue(const Json::Value root) {
// Set parent data
ClipBase::SetJsonValue(root);
@@ -905,10 +901,7 @@ void Clip::SetJsonValue(Json::Value root) {
effects.clear();
// loop through effects
- for (int x = 0; x < root["effects"].size(); x++) {
- // Get each effect
- Json::Value existing_effect = root["effects"][x];
-
+ for (const auto existing_effect : root["effects"]) {
// Create Effect
EffectBase *e = NULL;
@@ -982,6 +975,12 @@ void Clip::SetJsonValue(Json::Value root) {
// Create new reader
reader = new DummyReader();
reader->SetJsonValue(root["reader"]);
+
+ } else if (type == "Timeline") {
+
+ // Create new reader (always load from file again)
+ // This prevents FrameMappers from being loaded on accident
+ reader = new Timeline(root["reader"]["path"].asString(), true);
}
// mark as managed reader and set parent
@@ -1025,12 +1024,8 @@ void Clip::RemoveEffect(EffectBase* effect)
std::shared_ptr Clip::apply_effects(std::shared_ptr frame)
{
// Find Effects at this position and layer
- std::list::iterator effect_itr;
- for (effect_itr=effects.begin(); effect_itr != effects.end(); ++effect_itr)
+ for (auto effect : effects)
{
- // Get clip object from the iterator
- EffectBase *effect = (*effect_itr);
-
// Apply the effect to this frame
frame = effect->GetFrame(frame, frame->number);
diff --git a/src/ClipBase.cpp b/src/ClipBase.cpp
index d1370205b..a51c65735 100644
--- a/src/ClipBase.cpp
+++ b/src/ClipBase.cpp
@@ -32,8 +32,8 @@
using namespace openshot;
-// Generate Json::JsonValue for this object
-Json::Value ClipBase::JsonValue() {
+// Generate Json::Value for this object
+Json::Value ClipBase::JsonValue() const {
// Create root json object
Json::Value root;
@@ -48,8 +48,8 @@ Json::Value ClipBase::JsonValue() {
return root;
}
-// Load Json::JsonValue into this object
-void ClipBase::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void ClipBase::SetJsonValue(const Json::Value root) {
// Set data from Json (if key is found)
if (!root["id"].isNull())
@@ -65,10 +65,10 @@ void ClipBase::SetJsonValue(Json::Value root) {
}
// Generate JSON for a property
-Json::Value ClipBase::add_property_json(std::string name, float value, std::string type, std::string memo, Keyframe* keyframe, float min_value, float max_value, bool readonly, int64_t requested_frame) {
+Json::Value ClipBase::add_property_json(std::string name, float value, std::string type, std::string memo, const Keyframe* keyframe, float min_value, float max_value, bool readonly, int64_t requested_frame) const {
// Requested Point
- Point requested_point(requested_frame, requested_frame);
+ const Point requested_point(requested_frame, requested_frame);
// Create JSON Object
Json::Value prop = Json::Value(Json::objectValue);
@@ -101,7 +101,7 @@ Json::Value ClipBase::add_property_json(std::string name, float value, std::stri
return prop;
}
-Json::Value ClipBase::add_property_choice_json(std::string name, int value, int selected_value) {
+Json::Value ClipBase::add_property_choice_json(std::string name, int value, int selected_value) const {
// Create choice
Json::Value new_choice = Json::Value(Json::objectValue);
diff --git a/src/Color.cpp b/src/Color.cpp
index 927fc1624..705ece4a1 100644
--- a/src/Color.cpp
+++ b/src/Color.cpp
@@ -85,14 +85,14 @@ long Color::GetDistance(long R1, long G1, long B1, long R2, long G2, long B2)
}
// Generate JSON string of this object
-std::string Color::Json() {
+std::string Color::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Color::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Color::JsonValue() const {
// Create root json object
Json::Value root;
@@ -106,24 +106,12 @@ Json::Value Color::JsonValue() {
}
// Load JSON string into this object
-void Color::SetJson(std::string value) {
+void Color::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -134,8 +122,8 @@ void Color::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Color::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Color::SetJsonValue(const Json::Value root) {
// Set data from Json (if key is found)
if (!root["red"].isNull())
diff --git a/src/Coordinate.cpp b/src/Coordinate.cpp
index a0bdabcc3..f87fb7a0e 100644
--- a/src/Coordinate.cpp
+++ b/src/Coordinate.cpp
@@ -45,14 +45,14 @@ Coordinate::Coordinate(double x, double y) :
// Generate JSON string of this object
-std::string Coordinate::Json() {
+std::string Coordinate::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Coordinate::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Coordinate::JsonValue() const {
// Create root json object
Json::Value root;
@@ -69,24 +69,12 @@ Json::Value Coordinate::JsonValue() {
}
// Load JSON string into this object
-void Coordinate::SetJson(std::string value) {
+void Coordinate::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -97,8 +85,8 @@ void Coordinate::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Coordinate::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Coordinate::SetJsonValue(const Json::Value root) {
// Set data from Json (if key is found)
if (!root["X"].isNull())
diff --git a/src/DecklinkReader.cpp b/src/DecklinkReader.cpp
index 35ed18578..14c2f87ca 100644
--- a/src/DecklinkReader.cpp
+++ b/src/DecklinkReader.cpp
@@ -246,14 +246,14 @@ std::shared_ptr DecklinkReader::GetFrame(int64_t requested_frame)
// Generate JSON string of this object
-std::string DecklinkReader::Json() {
+std::string DecklinkReader::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value DecklinkReader::JsonValue() {
+// Generate Json::Value for this object
+Json::Value DecklinkReader::JsonValue() const {
// Create root json object
Json::Value root = ReaderBase::JsonValue(); // get parent properties
@@ -264,24 +264,12 @@ Json::Value DecklinkReader::JsonValue() {
}
// Load JSON string into this object
-void DecklinkReader::SetJson(std::string value) {
+void DecklinkReader::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -292,8 +280,8 @@ void DecklinkReader::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void DecklinkReader::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void DecklinkReader::SetJsonValue(const Json::Value root) {
// Set parent data
ReaderBase::SetJsonValue(root);
diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp
index 997a020ae..8fd98bcbc 100644
--- a/src/DummyReader.cpp
+++ b/src/DummyReader.cpp
@@ -124,14 +124,14 @@ std::shared_ptr DummyReader::GetFrame(int64_t requested_frame)
}
// Generate JSON string of this object
-std::string DummyReader::Json() {
+std::string DummyReader::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value DummyReader::JsonValue() {
+// Generate Json::Value for this object
+Json::Value DummyReader::JsonValue() const {
// Create root json object
Json::Value root = ReaderBase::JsonValue(); // get parent properties
@@ -142,24 +142,12 @@ Json::Value DummyReader::JsonValue() {
}
// Load JSON string into this object
-void DummyReader::SetJson(std::string value) {
+void DummyReader::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -170,8 +158,8 @@ void DummyReader::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void DummyReader::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void DummyReader::SetJsonValue(const Json::Value root) {
// Set parent data
ReaderBase::SetJsonValue(root);
diff --git a/src/EffectBase.cpp b/src/EffectBase.cpp
index 30e837652..05ed97c2a 100644
--- a/src/EffectBase.cpp
+++ b/src/EffectBase.cpp
@@ -74,20 +74,19 @@ int EffectBase::constrain(int color_value)
}
// Generate JSON string of this object
-std::string EffectBase::Json() {
+std::string EffectBase::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value EffectBase::JsonValue() {
+// Generate Json::Value for this object
+Json::Value EffectBase::JsonValue() const {
// Create root json object
Json::Value root = ClipBase::JsonValue(); // get parent properties
root["name"] = info.name;
root["class_name"] = info.class_name;
- root["short_name"] = info.short_name;
root["description"] = info.description;
root["has_video"] = info.has_video;
root["has_audio"] = info.has_audio;
@@ -98,24 +97,12 @@ Json::Value EffectBase::JsonValue() {
}
// Load JSON string into this object
-void EffectBase::SetJson(std::string value) {
+void EffectBase::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -126,8 +113,8 @@ void EffectBase::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void EffectBase::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void EffectBase::SetJsonValue(const Json::Value root) {
// Set parent data
ClipBase::SetJsonValue(root);
@@ -137,14 +124,13 @@ void EffectBase::SetJsonValue(Json::Value root) {
Order(root["order"].asInt());
}
-// Generate Json::JsonValue for this object
-Json::Value EffectBase::JsonInfo() {
+// Generate Json::Value for this object
+Json::Value EffectBase::JsonInfo() const {
// Create root json object
Json::Value root;
root["name"] = info.name;
root["class_name"] = info.class_name;
- root["short_name"] = info.short_name;
root["description"] = info.description;
root["has_video"] = info.has_video;
root["has_audio"] = info.has_audio;
diff --git a/src/EffectInfo.cpp b/src/EffectInfo.cpp
index 8fb8a4fe4..6829f4eb5 100644
--- a/src/EffectInfo.cpp
+++ b/src/EffectInfo.cpp
@@ -56,7 +56,7 @@ EffectBase* EffectInfo::CreateEffect(std::string effect_type) {
else if (effect_type == "ChromaKey")
return new ChromaKey();
- else if (effect_type == "Color Shift")
+ else if (effect_type == "ColorShift")
return new ColorShift();
else if (effect_type == "Crop")
@@ -88,7 +88,7 @@ EffectBase* EffectInfo::CreateEffect(std::string effect_type) {
return NULL;
}
-// Generate Json::JsonValue for this object
+// Generate Json::Value for this object
Json::Value EffectInfo::JsonValue() {
// Create root json object
diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp
index e8ac4af91..2b03994be 100644
--- a/src/FFmpegReader.cpp
+++ b/src/FFmpegReader.cpp
@@ -35,13 +35,13 @@
#define ENABLE_VAAPI 0
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
#pragma message "You are compiling with experimental hardware decode"
#else
#pragma message "You are compiling only with software decode"
#endif
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
#define MAX_SUPPORTED_WIDTH 1950
#define MAX_SUPPORTED_HEIGHT 1100
@@ -71,14 +71,14 @@ typedef struct VAAPIDecodeContext {
enum AVPixelFormat surface_format;
int surface_count;
} VAAPIDecodeContext;
-#endif
-#endif
+#endif // ENABLE_VAAPI
+#endif // HAVE_HW_ACCEL
using namespace openshot;
int hw_de_on = 0;
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
AVPixelFormat hw_de_av_pix_fmt_global = AV_PIX_FMT_NONE;
AVHWDeviceType hw_de_av_device_type_global = AV_HWDEVICE_TYPE_NONE;
#endif
@@ -153,7 +153,7 @@ bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64
return false;
}
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
// Get hardware pix format
static enum AVPixelFormat get_hw_dec_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts)
@@ -191,10 +191,10 @@ static enum AVPixelFormat get_hw_dec_format(AVCodecContext *ctx, const enum AVPi
#if defined(__APPLE__)
// Apple pix formats
case AV_PIX_FMT_VIDEOTOOLBOX:
- hw_de_av_pix_fmt_global = AV_PIX_FMT_VIDEOTOOLBOX;
- hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VIDEOTOOLBOX;
- return *p;
- break;
+ hw_de_av_pix_fmt_global = AV_PIX_FMT_VIDEOTOOLBOX;
+ hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VIDEOTOOLBOX;
+ return *p;
+ break;
#endif
// Cross-platform pix formats
case AV_PIX_FMT_CUDA:
@@ -207,6 +207,9 @@ static enum AVPixelFormat get_hw_dec_format(AVCodecContext *ctx, const enum AVPi
hw_de_av_device_type_global = AV_HWDEVICE_TYPE_QSV;
return *p;
break;
+ default:
+ // This is only here to silence unused-enum warnings
+ break;
}
}
ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format (Unable to decode this file using hardware decode)");
@@ -231,7 +234,7 @@ int FFmpegReader::IsHardwareDecodeSupported(int codecid)
}
return ret;
}
-#endif
+#endif // HAVE_HW_ACCEL
void FFmpegReader::Open() {
// Open reader if not already open
@@ -284,7 +287,7 @@ void FFmpegReader::Open() {
// If hw accel is selected but hardware cannot handle repeat with software decoding
do {
pCodecCtx = AV_GET_CODEC_CONTEXT(pStream, pCodec);
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
if (hw_de_on && (retry_decode_open==2)) {
// Up to here no decision is made if hardware or software decode
hw_de_supported = IsHardwareDecodeSupported(pCodecCtx->codec_id);
@@ -301,7 +304,7 @@ void FFmpegReader::Open() {
// Init options
av_dict_set(&opts, "strict", "experimental", 0);
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
if (hw_de_on && hw_de_supported) {
// Open Hardware Acceleration
int i_decoder_hw = 0;
@@ -430,13 +433,13 @@ void FFmpegReader::Open() {
throw InvalidCodec("Hardware device create failed.", path);
}
}
-#endif
+#endif // HAVE_HW_ACCEL
// Open video codec
if (avcodec_open2(pCodecCtx, pCodec, &opts) < 0)
throw InvalidCodec("A video codec was found, but could not be opened.", path);
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
if (hw_de_on && hw_de_supported) {
AVHWFramesConstraints *constraints = NULL;
void *hwconfig = NULL;
@@ -446,7 +449,7 @@ void FFmpegReader::Open() {
#if ENABLE_VAAPI
((AVVAAPIHWConfig *)hwconfig)->config_id = ((VAAPIDecodeContext *)(pCodecCtx->priv_data))->va_config;
constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx,hwconfig);
-#endif
+#endif // ENABLE_VAAPI
if (constraints) {
if (pCodecCtx->coded_width < constraints->min_width ||
pCodecCtx->coded_height < constraints->min_height ||
@@ -503,7 +506,7 @@ void FFmpegReader::Open() {
}
#else
retry_decode_open = 0;
-#endif
+#endif // HAVE_HW_ACCEL
} while (retry_decode_open); // retry_decode_open
// Free options
av_dict_free(&opts);
@@ -589,14 +592,14 @@ void FFmpegReader::Close() {
if (info.has_video) {
avcodec_flush_buffers(pCodecCtx);
AV_FREE_CONTEXT(pCodecCtx);
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
if (hw_de_on) {
if (hw_device_ctx) {
av_buffer_unref(&hw_device_ctx);
hw_device_ctx = NULL;
}
}
-#endif
+#endif // HAVE_HW_ACCEL
}
if (info.has_audio) {
avcodec_flush_buffers(aCodecCtx);
@@ -1097,19 +1100,22 @@ bool FFmpegReader::GetAVFrame() {
ret = avcodec_send_packet(pCodecCtx, packet);
+ #if HAVE_HW_ACCEL
// Get the format from the variables set in get_hw_dec_format
hw_de_av_pix_fmt = hw_de_av_pix_fmt_global;
hw_de_av_device_type = hw_de_av_device_type_global;
-
+ #endif // HAVE_HW_ACCEL
if (ret < 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Packet not sent)");
}
else {
AVFrame *next_frame2;
+ #if HAVE_HW_ACCEL
if (hw_de_on && hw_de_supported) {
next_frame2 = AV_ALLOCATE_FRAME();
}
else
+ #endif // HAVE_HW_ACCEL
{
next_frame2 = next_frame;
}
@@ -1122,6 +1128,7 @@ bool FFmpegReader::GetAVFrame() {
if (ret != 0) {
ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (invalid return frame received)");
}
+ #if HAVE_HW_ACCEL
if (hw_de_on && hw_de_supported) {
int err;
if (next_frame2->format == hw_de_av_pix_fmt) {
@@ -1135,6 +1142,7 @@ bool FFmpegReader::GetAVFrame() {
}
}
else
+ #endif // HAVE_HW_ACCEL
{ // No hardware acceleration used -> no copy from GPU memory needed
next_frame = next_frame2;
}
@@ -1148,9 +1156,11 @@ bool FFmpegReader::GetAVFrame() {
(AVPixelFormat)(pStream->codecpar->format), info.width, info.height);
}
}
+ #if HAVE_HW_ACCEL
if (hw_de_on && hw_de_supported) {
AV_FREE_FRAME(&next_frame2);
}
+ #endif // HAVE_HW_ACCEL
}
#else
avcodec_decode_video2(pCodecCtx, next_frame, &frameFinished, packet);
@@ -1166,7 +1176,7 @@ bool FFmpegReader::GetAVFrame() {
av_picture_copy((AVPicture *) pFrame, (AVPicture *) next_frame, pCodecCtx->pix_fmt, info.width,
info.height);
}
-#endif
+#endif // IS_FFMPEG_3_2
}
// deallocate the frame
@@ -2083,7 +2093,7 @@ bool FFmpegReader::CheckMissingFrame(int64_t requested_frame) {
// CPU time looking for missing images for all the audio-only frames.
if (checked_frames[requested_frame] > 8 && !missing_video_frames.count(requested_frame) &&
!processing_audio_frames.count(requested_frame) && processed_audio_frames.count(requested_frame) &&
- last_frame && last_video_frame->has_image_data && aCodecId == AV_CODEC_ID_MP3 && (vCodecId == AV_CODEC_ID_MJPEGB || vCodecId == AV_CODEC_ID_MJPEG)) {
+ last_frame && last_video_frame && last_video_frame->has_image_data && aCodecId == AV_CODEC_ID_MP3 && (vCodecId == AV_CODEC_ID_MJPEGB || vCodecId == AV_CODEC_ID_MJPEG)) {
missing_video_frames.insert(std::pair(requested_frame, last_video_frame->number));
missing_video_frames_source.insert(std::pair(last_video_frame->number, requested_frame));
missing_frames.Add(last_video_frame);
@@ -2424,14 +2434,14 @@ int64_t FFmpegReader::GetSmallestAudioFrame() {
}
// Generate JSON string of this object
-std::string FFmpegReader::Json() {
+std::string FFmpegReader::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value FFmpegReader::JsonValue() {
+// Generate Json::Value for this object
+Json::Value FFmpegReader::JsonValue() const {
// Create root json object
Json::Value root = ReaderBase::JsonValue(); // get parent properties
@@ -2443,23 +2453,11 @@ Json::Value FFmpegReader::JsonValue() {
}
// Load JSON string into this object
-void FFmpegReader::SetJson(std::string value) {
+void FFmpegReader::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse(value.c_str(), value.c_str() + value.size(),
- &root, &errors);
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try {
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -2469,8 +2467,8 @@ void FFmpegReader::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void FFmpegReader::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void FFmpegReader::SetJsonValue(const Json::Value root) {
// Set parent data
ReaderBase::SetJsonValue(root);
diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp
index 645c0cca4..e6a1d180a 100644
--- a/src/FFmpegWriter.cpp
+++ b/src/FFmpegWriter.cpp
@@ -35,7 +35,7 @@
using namespace openshot;
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
#pragma message "You are compiling with experimental hardware encode"
#else
#pragma message "You are compiling only with software encode"
@@ -44,7 +44,7 @@ using namespace openshot;
// Multiplexer parameters temporary storage
AVDictionary *mux_dict = NULL;
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
int hw_en_on = 1; // Is set in UI
int hw_en_supported = 0; // Is set by FFmpegWriter
AVPixelFormat hw_en_av_pix_fmt = AV_PIX_FMT_NONE;
@@ -81,7 +81,7 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6
av_buffer_unref(&hw_frames_ref);
return err;
}
-#endif
+#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),
@@ -171,7 +171,7 @@ void FFmpegWriter::SetVideoOptions(bool has_video, std::string codec, Fraction f
if (codec.length() > 0) {
AVCodec *new_codec;
// Check if the codec selected is a hardware accelerated codec
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
#if defined(__linux__)
if (strstr(codec.c_str(), "_vaapi") != NULL) {
new_codec = avcodec_find_encoder_by_name(codec.c_str());
@@ -225,7 +225,7 @@ void FFmpegWriter::SetVideoOptions(bool has_video, std::string codec, Fraction f
#endif //__linux__
#else // not ffmpeg 3
new_codec = avcodec_find_encoder_by_name(codec.c_str());
-#endif //IS_FFMPEG_3_2
+#endif // HAVE_HW_ACCEL
if (new_codec == NULL)
throw InvalidCodec("A valid video codec could not be found for this file.", path);
else {
@@ -277,6 +277,14 @@ void FFmpegWriter::SetVideoOptions(bool has_video, std::string codec, Fraction f
info.has_video = has_video;
}
+// Set video export options (overloaded function)
+void FFmpegWriter::SetVideoOptions(std::string codec, int width, int height, Fraction fps, int bit_rate) {
+ // Call full signature with some default parameters
+ FFmpegWriter::SetVideoOptions(true, codec, fps, width, height,
+ openshot::Fraction(1, 1), false, true, bit_rate);
+}
+
+
// Set audio export options
void FFmpegWriter::SetAudioOptions(bool has_audio, std::string codec, int sample_rate, int channels, ChannelLayout channel_layout, int bit_rate) {
// Set audio options
@@ -312,6 +320,15 @@ void FFmpegWriter::SetAudioOptions(bool has_audio, std::string codec, int sample
info.has_audio = has_audio;
}
+
+// Set audio export options (overloaded function)
+void FFmpegWriter::SetAudioOptions(std::string codec, int sample_rate, int bit_rate) {
+ // Call full signature with some default parameters
+ FFmpegWriter::SetAudioOptions(true, codec, sample_rate, 2,
+ openshot::LAYOUT_STEREO, bit_rate);
+}
+
+
// Set custom options (some codecs accept additional params)
void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string value) {
// Declare codec context
@@ -392,11 +409,11 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
// This might be better in an extra methods as more options
// and way to set quality are possible
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101)
- #if IS_FFMPEG_3_2
+ #if HAVE_HW_ACCEL
if (hw_en_on) {
av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); // 0-63
} else
- #endif
+ #endif // HAVE_HW_ACCEL
{
switch (c->codec_id) {
#if (LIBAVCODEC_VERSION_MAJOR >= 58)
@@ -423,7 +440,7 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
av_opt_set(c->priv_data, "preset", "veryslow", 0);
}
break;
- case AV_CODEC_ID_H265 :
+ case AV_CODEC_ID_HEVC :
av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value), 51), 0); // 0-51
if (std::stoi(value) == 0) {
av_opt_set(c->priv_data, "preset", "veryslow", 0);
@@ -442,7 +459,7 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
// This might be better in an extra methods as more options
// and way to set quality are possible
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101)
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
if (hw_en_on) {
double mbs = 15000000.0;
if (info.video_bit_rate > 0) {
@@ -455,7 +472,7 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
}
c->bit_rate = (int)(mbs);
} else
-#endif
+#endif // HAVE_HW_ACCEL
{
switch (c->codec_id) {
#if (LIBAVCODEC_VERSION_MAJOR >= 58)
@@ -482,7 +499,7 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
av_opt_set(c->priv_data, "preset", "veryslow", 0);
}
break;
- case AV_CODEC_ID_H265 :
+ case AV_CODEC_ID_HEVC :
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);
@@ -615,7 +632,7 @@ void FFmpegWriter::WriteFrame(std::shared_ptr frame) {
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::WriteFrame", "frame->number", frame->number, "spooled_video_frames.size()", spooled_video_frames.size(), "spooled_audio_frames.size()", spooled_audio_frames.size(), "cache_size", cache_size, "is_writing", is_writing);
// Write the frames once it reaches the correct cache size
- if (spooled_video_frames.size() == cache_size || spooled_audio_frames.size() == cache_size) {
+ if ((int)spooled_video_frames.size() == cache_size || (int)spooled_audio_frames.size() == cache_size) {
// Is writer currently writing?
if (!is_writing)
// Write frames to video file
@@ -955,16 +972,14 @@ void FFmpegWriter::flush_encoders() {
// Close the video codec
void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st)
{
-#if IS_FFMPEG_3_2
- // #if defined(__linux__)
- if (hw_en_on && hw_en_supported) {
- if (hw_device_ctx) {
- av_buffer_unref(&hw_device_ctx);
- hw_device_ctx = NULL;
- }
+#if HAVE_HW_ACCEL
+ if (hw_en_on && hw_en_supported) {
+ if (hw_device_ctx) {
+ av_buffer_unref(&hw_device_ctx);
+ hw_device_ctx = NULL;
}
- // #endif
-#endif
+ }
+#endif // HAVE_HW_ACCEL
}
// Close the audio codec
@@ -1083,7 +1098,7 @@ AVStream *FFmpegWriter::add_audio_stream() {
// Set a valid number of channels (or throw error)
- int channel_layout = info.channel_layout;
+ const uint64_t channel_layout = info.channel_layout;
if (codec->channel_layouts) {
int i;
for (i = 0; codec->channel_layouts[i] != 0; i++)
@@ -1162,7 +1177,7 @@ AVStream *FFmpegWriter::add_video_stream() {
case AV_CODEC_ID_AV1 :
#endif
case AV_CODEC_ID_VP9 :
- case AV_CODEC_ID_H265 :
+ case AV_CODEC_ID_HEVC :
#endif
case AV_CODEC_ID_VP8 :
case AV_CODEC_ID_H264 :
@@ -1200,7 +1215,8 @@ AVStream *FFmpegWriter::add_video_stream() {
identically 1. */
c->time_base.num = info.video_timebase.num;
c->time_base.den = info.video_timebase.den;
-#if LIBAVFORMAT_VERSION_MAJOR >= 56
+// AVCodecContext->framerate was added in FFmpeg 2.2
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 26, 0)
c->framerate = av_inv_q(c->time_base);
#endif
st->avg_frame_rate = av_inv_q(c->time_base);
@@ -1341,7 +1357,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) {
// Set number of threads equal to number of processors (not to exceed 16)
video_codec->thread_count = std::min(FF_NUM_PROCESSORS, 16);
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
if (hw_en_on && hw_en_supported) {
//char *dev_hw = NULL;
char adapter[256];
@@ -1384,7 +1400,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) {
throw InvalidCodec("Could not create hwdevice", path);
}
}
-#endif
+#endif // HAVE_HW_ACCEL
/* find the video encoder */
codec = avcodec_find_encoder_by_name(info.vcodec.c_str());
@@ -1401,7 +1417,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) {
AVDictionary *opts = NULL;
av_dict_set(&opts, "strict", "experimental", 0);
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
if (hw_en_on && hw_en_supported) {
video_codec->pix_fmt = hw_en_av_pix_fmt;
@@ -1417,7 +1433,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) {
// unless "qp" was set for CQP, switch to VBR RC mode
av_opt_set(video_codec->priv_data, "rc_mode", "VBR", 0);
- // In the current state (ffmpeg-4.2-4 libva-mesa-driver-19.1.5-1) to use VBR,
+ // In the current state (ffmpeg-4.2-4 libva-mesa-driver-19.1.5-1) to use VBR,
// one has to specify both bit_rate and maxrate, otherwise a small low quality file is generated on Intel iGPU).
video_codec->rc_max_rate = video_codec->bit_rate;
}
@@ -1450,7 +1466,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) {
"width", info.width, "height", info.height, av_err2str(err), -1);
}
}
-#endif
+#endif // HAVE_HW_ACCEL
/* open the codec */
if (avcodec_open2(video_codec, codec, &opts) < 0)
@@ -1482,7 +1498,8 @@ void FFmpegWriter::write_audio_packets(bool is_final) {
ChannelLayout channel_layout_in_frame = LAYOUT_MONO; // default channel layout
// Create a new array (to hold all S16 audio samples, for the current queued frames
- int16_t *all_queued_samples = (int16_t *) av_malloc((sizeof(int16_t) * (queued_audio_frames.size() * AVCODEC_MAX_AUDIO_FRAME_SIZE)));
+ unsigned int all_queued_samples_size = sizeof(int16_t) * (queued_audio_frames.size() * AVCODEC_MAX_AUDIO_FRAME_SIZE);
+ int16_t *all_queued_samples = (int16_t *) av_malloc(all_queued_samples_size);
int16_t *all_resampled_samples = NULL;
int16_t *final_samples_planar = NULL;
int16_t *final_samples = NULL;
@@ -1542,8 +1559,10 @@ void FFmpegWriter::write_audio_packets(bool is_final) {
audio_frame->nb_samples = total_frame_samples / channels_in_frame;
// Fill input frame with sample data
- avcodec_fill_audio_frame(audio_frame, channels_in_frame, AV_SAMPLE_FMT_S16, (uint8_t *) all_queued_samples,
- audio_encoder_buffer_size, 0);
+ int error_code = avcodec_fill_audio_frame(audio_frame, channels_in_frame, AV_SAMPLE_FMT_S16, (uint8_t *) all_queued_samples, all_queued_samples_size, 0);
+ if (error_code < 0) {
+ ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets ERROR [" + (std::string) av_err2str(error_code) + "]", "error_code", error_code);
+ }
// Do not convert audio to planar format (yet). We need to keep everything interleaved at this point.
switch (audio_codec->sample_fmt) {
@@ -1563,15 +1582,16 @@ void FFmpegWriter::write_audio_packets(bool is_final) {
output_sample_fmt = AV_SAMPLE_FMT_U8;
break;
}
+ default: {
+ // This is only here to silence unused-enum warnings
+ break;
+ }
}
// Update total samples & input frame size (due to bigger or smaller data types)
total_frame_samples *= (float(info.sample_rate) / sample_rate_in_frame); // adjust for different byte sizes
total_frame_samples *= (float(info.channels) / channels_in_frame); // adjust for different # of channels
- // Set remaining samples
- remaining_frame_samples = total_frame_samples;
-
// Create output frame (and allocate arrays)
AVFrame *audio_converted = AV_ALLOCATE_FRAME();
AV_RESET_FRAME(audio_converted);
@@ -1604,6 +1624,9 @@ void FFmpegWriter::write_audio_packets(bool is_final) {
audio_frame->linesize[0], // input plane size, in bytes (0 if unknown)
audio_frame->nb_samples); // number of input samples to convert
+ // Set remaining samples
+ remaining_frame_samples = nb_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
+
// Create a new array (to hold all resampled S16 audio samples)
all_resampled_samples = (int16_t *) av_malloc(
sizeof(int16_t) * nb_samples * info.channels * (av_get_bytes_per_sample(output_sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)));
@@ -1892,14 +1915,17 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) {
frame_source = allocate_avframe(PIX_FMT_RGBA, source_image_width, source_image_height, &bytes_source, (uint8_t *) pixels);
#if IS_FFMPEG_3_2
AVFrame *frame_final;
+ #if HAVE_HW_ACCEL
if (hw_en_on && hw_en_supported) {
frame_final = allocate_avframe(AV_PIX_FMT_NV12, info.width, info.height, &bytes_final, NULL);
- } else {
+ } else
+ #endif // HAVE_HW_ACCEL
+ {
frame_final = allocate_avframe((AVPixelFormat)(video_st->codecpar->format), info.width, info.height, &bytes_final, NULL);
}
#else
AVFrame *frame_final = allocate_avframe(video_codec->pix_fmt, info.width, info.height, &bytes_final, NULL);
-#endif
+#endif // IS_FFMPEG_3_2
// Fill with data
AV_COPY_PICTURE_DATA(frame_source, (uint8_t *) pixels, PIX_FMT_RGBA, source_image_width, source_image_height);
@@ -1969,7 +1995,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
// Assign the initial AVFrame PTS from the frame counter
frame_final->pts = write_video_count;
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
if (hw_en_on && hw_en_supported) {
if (!(hw_frame = av_frame_alloc())) {
fprintf(stderr, "Error code: av_hwframe_alloc\n");
@@ -1986,7 +2012,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
}
av_frame_copy_props(hw_frame, frame_final);
}
-#endif
+#endif // HAVE_HW_ACCEL
/* encode the image */
int got_packet_ptr = 0;
int error_code = 0;
@@ -1995,9 +2021,12 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
int frameFinished = 0;
int ret;
+ #if HAVE_HW_ACCEL
if (hw_en_on && hw_en_supported) {
ret = avcodec_send_frame(video_codec, hw_frame); //hw_frame!!!
- } else {
+ } else
+ #endif // HAVE_HW_ACCEL
+ {
ret = avcodec_send_frame(video_codec, frame_final);
}
error_code = ret;
@@ -2054,8 +2083,8 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
// got data back (so encode this frame)
got_packet_ptr = 1;
}
-#endif
-#endif
+#endif // LIBAVFORMAT_VERSION_MAJOR >= 54
+#endif // IS_FFMPEG_3_2
/* if zero size, it means the image was buffered */
if (error_code == 0 && got_packet_ptr) {
@@ -2087,14 +2116,14 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
// Deallocate packet
AV_FREE_PACKET(&pkt);
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
if (hw_en_on && hw_en_supported) {
if (hw_frame) {
av_frame_free(&hw_frame);
hw_frame = NULL;
}
}
-#endif
+#endif // HAVE_HW_ACCEL
}
// Success
@@ -2117,11 +2146,11 @@ void FFmpegWriter::InitScalers(int source_width, int source_height) {
// Init software rescalers vector (many of them, one for each thread)
for (int x = 0; x < num_of_rescalers; x++) {
// Init the software scaler from FFMpeg
-#if IS_FFMPEG_3_2
+#if HAVE_HW_ACCEL
if (hw_en_on && hw_en_supported) {
img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_PIX_FMT_NV12, scale_mode, NULL, NULL, NULL);
} else
-#endif
+#endif // HAVE_HW_ACCEL
{
img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_GET_CODEC_PIXEL_FORMAT(video_st, video_st->codec), scale_mode,
NULL, NULL, NULL);
diff --git a/src/Frame.cpp b/src/Frame.cpp
index 40183422c..9577a7f9e 100644
--- a/src/Frame.cpp
+++ b/src/Frame.cpp
@@ -43,7 +43,7 @@ Frame::Frame() : number(1), pixel_ratio(1,1), channels(2), width(1), height(1),
// initialize the audio samples to zero (silence)
audio->clear();
-};
+}
// Constructor - image only (48kHz audio silence)
Frame::Frame(int64_t number, int width, int height, std::string color)
@@ -56,7 +56,7 @@ Frame::Frame(int64_t number, int width, int height, std::string color)
// initialize the audio samples to zero (silence)
audio->clear();
-};
+}
// Constructor - audio only (300x200 blank image)
Frame::Frame(int64_t number, int samples, int channels) :
@@ -69,7 +69,7 @@ Frame::Frame(int64_t number, int samples, int channels) :
// initialize the audio samples to zero (silence)
audio->clear();
-};
+}
// Constructor - image & audio
Frame::Frame(int64_t number, int width, int height, std::string color, int samples, int channels)
@@ -82,7 +82,7 @@ Frame::Frame(int64_t number, int width, int height, std::string color, int sampl
// initialize the audio samples to zero (silence)
audio->clear();
-};
+}
// Copy constructor
@@ -109,11 +109,12 @@ void Frame::DeepCopy(const Frame& other)
width = other.width;
height = other.height;
channel_layout = other.channel_layout;
- has_audio_data = other.has_image_data;
+ has_audio_data = other.has_audio_data;
has_image_data = other.has_image_data;
sample_rate = other.sample_rate;
pixel_ratio = Fraction(other.pixel_ratio.num, other.pixel_ratio.den);
color = other.color;
+ max_audio_sample = other.max_audio_sample;
if (other.image)
image = std::shared_ptr(new QImage(*(other.image)));
@@ -580,7 +581,7 @@ void Frame::Save(std::string path, float scale, std::string format, int quality)
std::shared_ptr previewImage = GetImage();
// scale image if needed
- if (abs(scale) > 1.001 || abs(scale) < 0.999)
+ if (fabs(scale) > 1.001 || fabs(scale) < 0.999)
{
int new_width = width;
int new_height = height;
@@ -817,16 +818,23 @@ void Frame::AddImage(std::shared_ptr new_image, bool only_odd_lines)
// Ignore image of different sizes or formats
bool ret=false;
#pragma omp critical (AddImage)
- if (image == new_image || image->size() != image->size() || image->format() != image->format())
- ret=true;
- if (ret)
+ {
+ if (image == new_image || image->size() != new_image->size()) {
+ ret = true;
+ }
+ else if (new_image->format() != image->format()) {
+ new_image = std::shared_ptr(new QImage(new_image->convertToFormat(image->format())));
+ }
+ }
+ if (ret) {
return;
-
+ }
+
// Get the frame's image
const GenericScopedLock lock(addingImageSection);
#pragma omp critical (AddImage)
{
- const unsigned char *pixels = image->constBits();
+ unsigned char *pixels = image->bits();
const unsigned char *new_pixels = new_image->constBits();
// Loop through the scanlines of the image (even or odd)
@@ -835,13 +843,13 @@ void Frame::AddImage(std::shared_ptr new_image, bool only_odd_lines)
start = 1;
for (int row = start; row < image->height(); row += 2) {
- memcpy((unsigned char *) pixels, new_pixels + (row * image->bytesPerLine()), image->bytesPerLine());
- new_pixels += image->bytesPerLine();
+ int offset = row * image->bytesPerLine();
+ memcpy(pixels + offset, new_pixels + offset, image->bytesPerLine());
}
// Update height and width
- width = image->width();
height = image->height();
+ width = image->width();
has_image_data = true;
}
}
diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp
index fe12a780b..7c4d04bb4 100644
--- a/src/FrameMapper.cpp
+++ b/src/FrameMapper.cpp
@@ -235,7 +235,7 @@ void FrameMapper::Init()
int64_t start_samples_frame = 1;
int start_samples_position = 0;
- for (int64_t field = 1; field <= fields.size(); field++)
+ for (std::vector::size_type field = 1; field <= fields.size(); field++)
{
// Get the current field
Field f = fields[field - 1];
@@ -337,7 +337,7 @@ MappedFrame FrameMapper::GetMappedFrame(int64_t TargetFrameNumber)
// frame too small, return error
throw OutOfBoundsFrame("An invalid frame was requested.", TargetFrameNumber, frames.size());
- else if (TargetFrameNumber > frames.size())
+ else if (TargetFrameNumber > (int64_t)frames.size())
// frame too large, set to end frame
TargetFrameNumber = frames.size();
@@ -675,14 +675,14 @@ void FrameMapper::Close()
// Generate JSON string of this object
-std::string FrameMapper::Json() {
+std::string FrameMapper::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value FrameMapper::JsonValue() {
+// Generate Json::Value for this object
+Json::Value FrameMapper::JsonValue() const {
// Create root json object
Json::Value root = ReaderBase::JsonValue(); // get parent properties
@@ -693,24 +693,12 @@ Json::Value FrameMapper::JsonValue() {
}
// Load JSON string into this object
-void FrameMapper::SetJson(std::string value) {
+void FrameMapper::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -721,8 +709,8 @@ void FrameMapper::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void FrameMapper::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void FrameMapper::SetJsonValue(const Json::Value root) {
// Set parent data
ReaderBase::SetJsonValue(root);
diff --git a/src/ImageReader.cpp b/src/ImageReader.cpp
index ad871f1f7..9ce3a70ff 100644
--- a/src/ImageReader.cpp
+++ b/src/ImageReader.cpp
@@ -136,14 +136,14 @@ std::shared_ptr ImageReader::GetFrame(int64_t requested_frame)
}
// Generate JSON string of this object
-std::string ImageReader::Json() {
+std::string ImageReader::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value ImageReader::JsonValue() {
+// Generate Json::Value for this object
+Json::Value ImageReader::JsonValue() const {
// Create root json object
Json::Value root = ReaderBase::JsonValue(); // get parent properties
@@ -155,24 +155,12 @@ Json::Value ImageReader::JsonValue() {
}
// Load JSON string into this object
-void ImageReader::SetJson(std::string value) {
+void ImageReader::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -183,8 +171,8 @@ void ImageReader::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void ImageReader::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void ImageReader::SetJsonValue(const Json::Value root) {
// Set parent data
ReaderBase::SetJsonValue(root);
diff --git a/src/Json.cpp b/src/Json.cpp
new file mode 100644
index 000000000..0c83d9d62
--- /dev/null
+++ b/src/Json.cpp
@@ -0,0 +1,50 @@
+/**
+ * @file
+ * @brief Helper functions for Json parsing
+ * @author FeRD (Frank Dana)
+ *
+ * @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 "../include/Json.h"
+
+const Json::Value openshot::stringToJson(const std::string value) {
+
+ // Parse JSON string into JSON objects
+ Json::Value root;
+ Json::CharReaderBuilder rbuilder;
+ Json::CharReader* reader(rbuilder.newCharReader());
+
+ std::string errors;
+ bool success = reader->parse( value.c_str(), value.c_str() + value.size(),
+ &root, &errors );
+ delete reader;
+
+ if (!success)
+ // Raise exception
+ throw openshot::InvalidJSON("JSON could not be parsed (or is invalid)");
+
+ return root;
+}
diff --git a/src/KeyFrame.cpp b/src/KeyFrame.cpp
index d16348a2e..57e424cf7 100644
--- a/src/KeyFrame.cpp
+++ b/src/KeyFrame.cpp
@@ -71,7 +71,7 @@ namespace {
}
double const x = p0.X * B[0] + p1.X * B[1] + p2.X * B[2] + p3.X * B[3];
double const y = p0.Y * B[0] + p1.Y * B[1] + p2.Y * B[2] + p3.Y * B[3];
- if (abs(target - x) < allowed_error) {
+ if (fabs(target - x) < allowed_error) {
return y;
}
if (x > target) {
@@ -169,7 +169,7 @@ void Keyframe::AddPoint(double x, double y, InterpolationType interpolate)
// Get the index of a point by matching a coordinate
int64_t Keyframe::FindIndex(Point p) const {
// loop through points, and find a matching coordinate
- for (int64_t x = 0; x < Points.size(); x++) {
+ for (std::vector::size_type x = 0; x < Points.size(); x++) {
// Get each point
Point existing_point = Points[x];
@@ -325,17 +325,15 @@ std::string Keyframe::Json() const {
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
+// Generate Json::Value for this object
Json::Value Keyframe::JsonValue() const {
// Create root json object
Json::Value root;
root["Points"] = Json::Value(Json::arrayValue);
- // loop through points, and find a matching coordinate
- for (int x = 0; x < Points.size(); x++) {
- // Get each point
- Point existing_point = Points[x];
+ // loop through points
+ for (const auto existing_point : Points) {
root["Points"].append(existing_point.JsonValue());
}
@@ -344,24 +342,12 @@ Json::Value Keyframe::JsonValue() const {
}
// Load JSON string into this object
-void Keyframe::SetJson(std::string value) {
+void Keyframe::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -372,17 +358,14 @@ void Keyframe::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Keyframe::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Keyframe::SetJsonValue(const Json::Value root) {
// Clear existing points
Points.clear();
if (!root["Points"].isNull())
// loop through points
- for (int64_t x = 0; x < root["Points"].size(); x++) {
- // Get each point
- Json::Value existing_point = root["Points"][(Json::UInt) x];
-
+ for (const auto existing_point : root["Points"]) {
// Create Point
Point p;
@@ -509,7 +492,7 @@ double Keyframe::GetDelta(int64_t index) const {
// Get a point at a specific index
Point const & Keyframe::GetPoint(int64_t index) const {
// Is index a valid point?
- if (index >= 0 && index < Points.size())
+ if (index >= 0 && index < (int64_t)Points.size())
return Points[index];
else
// Invalid index
@@ -532,7 +515,7 @@ int64_t Keyframe::GetCount() const {
// Remove a point by matching a coordinate
void Keyframe::RemovePoint(Point p) {
// loop through points, and find a matching coordinate
- for (int64_t x = 0; x < Points.size(); x++) {
+ for (std::vector::size_type x = 0; x < Points.size(); x++) {
// Get each point
Point existing_point = Points[x];
@@ -551,7 +534,7 @@ void Keyframe::RemovePoint(Point p) {
// Remove a point by index
void Keyframe::RemovePoint(int64_t index) {
// Is index a valid point?
- if (index >= 0 && index < Points.size())
+ if (index >= 0 && index < (int64_t)Points.size())
{
// Remove a specific point by index
Points.erase(Points.begin() + index);
@@ -581,7 +564,7 @@ void Keyframe::PrintValues() const {
cout << fixed << setprecision(4);
cout << "Frame Number (X)\tValue (Y)\tIs Increasing\tRepeat Numerator\tRepeat Denominator\tDelta (Y Difference)\n";
- for (uint64_t i = 1; i < GetLength(); ++i) {
+ for (int64_t i = 1; i < GetLength(); ++i) {
cout << i << "\t" << GetValue(i) << "\t" << IsIncreasing(i) << "\t" ;
cout << GetRepeatFraction(i).num << "\t" << GetRepeatFraction(i).den << "\t" << GetDelta(i) << "\n";
}
@@ -597,7 +580,7 @@ void Keyframe::ScalePoints(double scale)
// TODO: What if scale < 0?
// Loop through each point (skipping the 1st point)
- for (int64_t point_index = 1; point_index < Points.size(); point_index++) {
+ for (std::vector::size_type point_index = 1; point_index < Points.size(); point_index++) {
// Scale X value
Points[point_index].co.X = round(Points[point_index].co.X * scale);
}
@@ -605,7 +588,7 @@ void Keyframe::ScalePoints(double scale)
// Flip all the points in this openshot::Keyframe (useful for reversing an effect or transition, etc...)
void Keyframe::FlipPoints() {
- for (int64_t point_index = 0, reverse_index = Points.size() - 1; point_index < reverse_index; point_index++, reverse_index--) {
+ for (std::vector::size_type point_index = 0, reverse_index = Points.size() - 1; point_index < reverse_index; point_index++, reverse_index--) {
// Flip the points
using std::swap;
swap(Points[point_index].co.Y, Points[reverse_index].co.Y);
diff --git a/src/Point.cpp b/src/Point.cpp
index 52e7ffbe0..136799778 100644
--- a/src/Point.cpp
+++ b/src/Point.cpp
@@ -108,14 +108,14 @@ void Point::Initialize_RightHandle(float x, float y) {
}
// Generate JSON string of this object
-std::string Point::Json() {
+std::string Point::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Point::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Point::JsonValue() const {
// Create root json object
Json::Value root;
@@ -132,24 +132,12 @@ Json::Value Point::JsonValue() {
}
// Load JSON string into this object
-void Point::SetJson(std::string value) {
+void Point::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -160,8 +148,8 @@ void Point::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Point::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Point::SetJsonValue(const Json::Value root) {
if (!root["co"].isNull())
co.SetJsonValue(root["co"]); // update coordinate
diff --git a/src/Profiles.cpp b/src/Profiles.cpp
index e7c547717..5351520e9 100644
--- a/src/Profiles.cpp
+++ b/src/Profiles.cpp
@@ -133,14 +133,14 @@ Profile::Profile(std::string path) {
}
// Generate JSON string of this object
-std::string Profile::Json() {
+std::string Profile::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Profile::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Profile::JsonValue() const {
// Create root json object
Json::Value root;
@@ -163,24 +163,12 @@ Json::Value Profile::JsonValue() {
}
// Load JSON string into this object
-void Profile::SetJson(std::string value) {
+void Profile::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -191,8 +179,8 @@ void Profile::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Profile::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Profile::SetJsonValue(const Json::Value root) {
if (!root["height"].isNull())
info.height = root["height"].asInt();
diff --git a/src/Qt/VideoCacheThread.cpp b/src/Qt/VideoCacheThread.cpp
index 46b6f030a..6cff46ba8 100644
--- a/src/Qt/VideoCacheThread.cpp
+++ b/src/Qt/VideoCacheThread.cpp
@@ -29,13 +29,14 @@
*/
#include "../../include/Qt/VideoCacheThread.h"
+#include
namespace openshot
{
// Constructor
VideoCacheThread::VideoCacheThread()
: Thread("video-cache"), speed(1), is_playing(false), position(1)
- , reader(NULL), max_frames(OPEN_MP_NUM_PROCESSORS * 2), current_display_frame(1)
+ , reader(NULL), max_frames(std::min(OPEN_MP_NUM_PROCESSORS * 8, 64)), current_display_frame(1)
{
}
diff --git a/src/QtHtmlReader.cpp b/src/QtHtmlReader.cpp
index cfdde9f39..6b502fbd4 100644
--- a/src/QtHtmlReader.cpp
+++ b/src/QtHtmlReader.cpp
@@ -180,14 +180,14 @@ std::shared_ptr QtHtmlReader::GetFrame(int64_t requested_frame)
}
// Generate JSON string of this object
-std::string QtHtmlReader::Json() {
+std::string QtHtmlReader::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value QtHtmlReader::JsonValue() {
+// Generate Json::Value for this object
+Json::Value QtHtmlReader::JsonValue() const {
// Create root json object
Json::Value root = ReaderBase::JsonValue(); // get parent properties
@@ -206,24 +206,12 @@ Json::Value QtHtmlReader::JsonValue() {
}
// Load JSON string into this object
-void QtHtmlReader::SetJson(std::string value) {
+void QtHtmlReader::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -234,8 +222,8 @@ void QtHtmlReader::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void QtHtmlReader::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void QtHtmlReader::SetJsonValue(const Json::Value root) {
// Set parent data
ReaderBase::SetJsonValue(root);
diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp
index 7163b0979..864af23db 100644
--- a/src/QtImageReader.cpp
+++ b/src/QtImageReader.cpp
@@ -71,7 +71,7 @@ void QtImageReader::Open()
if (!is_open)
{
bool success = true;
- image = std::shared_ptr(new QImage());
+ bool loaded = false;
#if USE_RESVG == 1
// If defined and found in CMake, utilize the libresvg for parsing
@@ -80,38 +80,32 @@ void QtImageReader::Open()
if (path.toLower().endsWith(".svg") || path.toLower().endsWith(".svgz")) {
ResvgRenderer renderer(path);
- if (!renderer.isValid()) {
- // Attempt to open file (old method using Qt5 limited SVG parsing)
- success = image->load(path);
- if (success) {
- image = std::shared_ptr(new QImage(image->convertToFormat(QImage::Format_RGBA8888)));
- }
- } else {
-
- image = std::shared_ptr(new QImage(renderer.defaultSize(), QImage::Format_RGBA8888));
+ if (renderer.isValid()) {
+
+ image = std::shared_ptr(new QImage(renderer.defaultSize(), QImage::Format_ARGB32_Premultiplied));
image->fill(Qt::transparent);
QPainter p(image.get());
renderer.render(&p);
p.end();
+ loaded = true;
}
+ }
+#endif
- } else {
- // Attempt to open file (old method)
+ if (!loaded) {
+ // Attempt to open file using Qt's build in image processing capabilities
+ image = std::shared_ptr(new QImage());
success = image->load(path);
- if (success)
- image = std::shared_ptr(new QImage(image->convertToFormat(QImage::Format_RGBA8888)));
}
-#else
- // Attempt to open file using Qt's build in image processing capabilities
- success = image->load(path);
- if (success)
- image = std::shared_ptr(new QImage(image->convertToFormat(QImage::Format_RGBA8888)));
-#endif
- if (!success)
+ if (!success) {
// raise exception
throw InvalidFile("File could not be opened.", path.toStdString());
+ }
+
+ // Convert to proper format
+ image = std::shared_ptr(new QImage(image->convertToFormat(QImage::Format_RGBA8888)));
// Update image properties
info.has_audio = false;
@@ -224,11 +218,14 @@ std::shared_ptr QtImageReader::GetFrame(int64_t requested_frame)
// Scale image smaller (or use a previous scaled image)
if (!cached_image || (max_size.width() != max_width || max_size.height() != max_height)) {
+
+ bool rendered = false;
#if USE_RESVG == 1
// If defined and found in CMake, utilize the libresvg for parsing
// SVG files and rasterizing them to QImages.
// Only use resvg for files ending in '.svg' or '.svgz'
if (path.toLower().endsWith(".svg") || path.toLower().endsWith(".svgz")) {
+
ResvgRenderer renderer(path);
if (renderer.isValid()) {
// Scale SVG size to keep aspect ratio, and fill the max_size as best as possible
@@ -236,30 +233,25 @@ std::shared_ptr QtImageReader::GetFrame(int64_t requested_frame)
svg_size.scale(max_width, max_height, Qt::KeepAspectRatio);
// Create empty QImage
- cached_image = std::shared_ptr(new QImage(QSize(svg_size.width(), svg_size.height()), QImage::Format_RGBA8888));
+ cached_image = std::shared_ptr(new QImage(QSize(svg_size.width(), svg_size.height()), QImage::Format_ARGB32_Premultiplied));
cached_image->fill(Qt::transparent);
// Render SVG into QImage
QPainter p(cached_image.get());
renderer.render(&p);
p.end();
- } else {
- // Resize current rasterized SVG (since we failed to parse original SVG file with resvg)
- cached_image = std::shared_ptr(new QImage(image->scaled(max_width, max_height, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
- cached_image = std::shared_ptr(new QImage(cached_image->convertToFormat(QImage::Format_RGBA8888)));
+ rendered = true;
}
- } else {
+ }
+#endif
+
+ if (!rendered) {
// We need to resize the original image to a smaller image (for performance reasons)
// Only do this once, to prevent tons of unneeded scaling operations
cached_image = std::shared_ptr(new QImage(image->scaled(max_width, max_height, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
- cached_image = std::shared_ptr(new QImage(cached_image->convertToFormat(QImage::Format_RGBA8888)));
}
-#else
- // We need to resize the original image to a smaller image (for performance reasons)
- // Only do this once, to prevent tons of unneeded scaling operations
- cached_image = std::shared_ptr(new QImage(image->scaled(max_width, max_height, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
+
cached_image = std::shared_ptr(new QImage(cached_image->convertToFormat(QImage::Format_RGBA8888)));
-#endif
// Set max size (to later determine if max_size is changed)
max_size.setWidth(max_width);
@@ -277,14 +269,14 @@ std::shared_ptr QtImageReader::GetFrame(int64_t requested_frame)
}
// Generate JSON string of this object
-std::string QtImageReader::Json() {
+std::string QtImageReader::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value QtImageReader::JsonValue() {
+// Generate Json::Value for this object
+Json::Value QtImageReader::JsonValue() const {
// Create root json object
Json::Value root = ReaderBase::JsonValue(); // get parent properties
@@ -296,24 +288,12 @@ Json::Value QtImageReader::JsonValue() {
}
// Load JSON string into this object
-void QtImageReader::SetJson(std::string value) {
+void QtImageReader::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -324,8 +304,8 @@ void QtImageReader::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void QtImageReader::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void QtImageReader::SetJsonValue(const Json::Value root) {
// Set parent data
ReaderBase::SetJsonValue(root);
diff --git a/src/QtTextReader.cpp b/src/QtTextReader.cpp
index ee0c598a4..d91d164e6 100644
--- a/src/QtTextReader.cpp
+++ b/src/QtTextReader.cpp
@@ -197,14 +197,14 @@ std::shared_ptr QtTextReader::GetFrame(int64_t requested_frame)
}
// Generate JSON string of this object
-std::string QtTextReader::Json() {
+std::string QtTextReader::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value QtTextReader::JsonValue() {
+// Generate Json::Value for this object
+Json::Value QtTextReader::JsonValue() const {
// Create root json object
Json::Value root = ReaderBase::JsonValue(); // get parent properties
@@ -225,24 +225,12 @@ Json::Value QtTextReader::JsonValue() {
}
// Load JSON string into this object
-void QtTextReader::SetJson(std::string value) {
+void QtTextReader::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -253,8 +241,8 @@ void QtTextReader::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void QtTextReader::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void QtTextReader::SetJsonValue(const Json::Value root) {
// Set parent data
ReaderBase::SetJsonValue(root);
diff --git a/src/ReaderBase.cpp b/src/ReaderBase.cpp
index ccd271f48..474dc624e 100644
--- a/src/ReaderBase.cpp
+++ b/src/ReaderBase.cpp
@@ -108,13 +108,12 @@ void ReaderBase::DisplayInfo() {
std::cout << "----------------------------" << std::endl;
// Iterate through metadata
- std::map::iterator it;
- for (it = info.metadata.begin(); it != info.metadata.end(); it++)
- std::cout << "--> " << it->first << ": " << it->second << std::endl;
+ for (auto it : info.metadata)
+ std::cout << "--> " << it.first << ": " << it.second << std::endl;
}
-// Generate Json::JsonValue for this object
-Json::Value ReaderBase::JsonValue() {
+// Generate Json::Value for this object
+Json::Value ReaderBase::JsonValue() const {
// Create root json object
Json::Value root;
@@ -160,16 +159,16 @@ Json::Value ReaderBase::JsonValue() {
// Append metadata map
root["metadata"] = Json::Value(Json::objectValue);
- std::map::iterator it;
- for (it = info.metadata.begin(); it != info.metadata.end(); it++)
- root["metadata"][it->first] = it->second;
+
+ for (const auto it : info.metadata)
+ root["metadata"][it.first] = it.second;
// return JsonValue
return root;
}
-// Load Json::JsonValue into this object
-void ReaderBase::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void ReaderBase::SetJsonValue(const Json::Value root) {
// Set data from Json (if key is found)
if (!root["has_video"].isNull())
@@ -244,7 +243,7 @@ void ReaderBase::SetJsonValue(Json::Value root) {
info.audio_timebase.den = root["audio_timebase"]["den"].asInt();
}
if (!root["metadata"].isNull() && root["metadata"].isObject()) {
- for( Json::Value::iterator itr = root["metadata"].begin() ; itr != root["metadata"].end() ; itr++ ) {
+ for( Json::Value::const_iterator itr = root["metadata"].begin() ; itr != root["metadata"].end() ; itr++ ) {
std::string key = itr.key().asString();
info.metadata[key] = root["metadata"][key].asString();
}
diff --git a/src/TextReader.cpp b/src/TextReader.cpp
index 1983b104f..e317700c9 100644
--- a/src/TextReader.cpp
+++ b/src/TextReader.cpp
@@ -187,14 +187,14 @@ std::shared_ptr TextReader::GetFrame(int64_t requested_frame)
}
// Generate JSON string of this object
-std::string TextReader::Json() {
+std::string TextReader::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value TextReader::JsonValue() {
+// Generate Json::Value for this object
+Json::Value TextReader::JsonValue() const {
// Create root json object
Json::Value root = ReaderBase::JsonValue(); // get parent properties
@@ -216,24 +216,10 @@ Json::Value TextReader::JsonValue() {
}
// Load JSON string into this object
-void TextReader::SetJson(std::string value) {
-
- // Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
+void TextReader::SetJson(const std::string value) {
try
{
+ Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -244,8 +230,8 @@ void TextReader::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void TextReader::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void TextReader::SetJsonValue(const Json::Value root) {
// Set parent data
ReaderBase::SetJsonValue(root);
diff --git a/src/Timeline.cpp b/src/Timeline.cpp
index 86ef2911f..61ce31e33 100644
--- a/src/Timeline.cpp
+++ b/src/Timeline.cpp
@@ -34,7 +34,7 @@ using namespace openshot;
// Default Constructor for the timeline (which sets the canvas width and height)
Timeline::Timeline(int width, int height, Fraction fps, int sample_rate, int channels, ChannelLayout channel_layout) :
- is_open(false), auto_map_clips(true), managed_cache(true)
+ is_open(false), auto_map_clips(true), managed_cache(true), path("")
{
// Create CrashHandler and Attach (incase of errors)
CrashHandler::Instance();
@@ -64,6 +64,8 @@ Timeline::Timeline(int width, int height, Fraction fps, int sample_rate, int cha
info.display_ratio = openshot::Fraction(width, height);
info.display_ratio.Reduce();
info.pixel_ratio = openshot::Fraction(1, 1);
+ info.acodec = "openshot::timeline";
+ info.vcodec = "openshot::timeline";
// Init max image size
SetMaxSize(info.width, info.height);
@@ -73,21 +75,149 @@ Timeline::Timeline(int width, int height, Fraction fps, int sample_rate, int cha
final_cache->SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels);
}
+// Constructor for the timeline (which loads a JSON structure from a file path, and initializes a timeline)
+Timeline::Timeline(std::string projectPath, bool convert_absolute_paths) :
+ is_open(false), auto_map_clips(true), managed_cache(true), path(projectPath) {
+
+ // Create CrashHandler and Attach (incase of errors)
+ CrashHandler::Instance();
+
+ // Init final cache as NULL (will be created after loading json)
+ final_cache = NULL;
+
+ // Init viewport size (curve based, because it can be animated)
+ viewport_scale = Keyframe(100.0);
+ viewport_x = Keyframe(0.0);
+ viewport_y = Keyframe(0.0);
+
+ // Init background color
+ color.red = Keyframe(0.0);
+ color.green = Keyframe(0.0);
+ color.blue = Keyframe(0.0);
+
+ // Check if path exists
+ QFileInfo filePath(QString::fromStdString(path));
+ if (!filePath.exists()) {
+ throw InvalidFile("File could not be opened.", path);
+ }
+
+ // Check OpenShot Install Path exists
+ Settings *s = Settings::Instance();
+ QDir openshotPath(QString::fromStdString(s->PATH_OPENSHOT_INSTALL));
+ if (!openshotPath.exists()) {
+ throw InvalidFile("PATH_OPENSHOT_INSTALL could not be found.", s->PATH_OPENSHOT_INSTALL);
+ }
+ QDir openshotTransPath(openshotPath.filePath("transitions"));
+ if (!openshotTransPath.exists()) {
+ throw InvalidFile("PATH_OPENSHOT_INSTALL/transitions could not be found.", openshotTransPath.path().toStdString());
+ }
+
+ // Determine asset path
+ QString asset_name = filePath.baseName().left(30) + "_assets";
+ QDir asset_folder(filePath.dir().filePath(asset_name));
+ if (!asset_folder.exists()) {
+ // Create directory if needed
+ asset_folder.mkpath(".");
+ }
+
+ // Load UTF-8 project file into QString
+ QFile projectFile(QString::fromStdString(path));
+ projectFile.open(QFile::ReadOnly);
+ QString projectContents = QString::fromUtf8(projectFile.readAll());
+
+ // Convert all relative paths into absolute paths (if requested)
+ if (convert_absolute_paths) {
+
+ // Find all "image" or "path" references in JSON (using regex). Must loop through match results
+ // due to our path matching needs, which are not possible with the QString::replace() function.
+ QRegularExpression allPathsRegex(QStringLiteral("\"(image|path)\":.*?\"(.*?)\""));
+ std::vector matchedPositions;
+ QRegularExpressionMatchIterator i = allPathsRegex.globalMatch(projectContents);
+ while (i.hasNext()) {
+ QRegularExpressionMatch match = i.next();
+ if (match.hasMatch()) {
+ // Push all match objects into a vector (so we can reverse them later)
+ matchedPositions.push_back(match);
+ }
+ }
+
+ // Reverse the matches (bottom of file to top, so our replacements don't break our match positions)
+ std::vector::reverse_iterator itr;
+ for (itr = matchedPositions.rbegin(); itr != matchedPositions.rend(); itr++) {
+ QRegularExpressionMatch match = *itr;
+ QString relativeKey = match.captured(1); // image or path
+ QString relativePath = match.captured(2); // relative file path
+ QString absolutePath = "";
+
+ // Find absolute path of all path, image (including special replacements of @assets and @transitions)
+ if (relativePath.startsWith("@assets")) {
+ absolutePath = QFileInfo(asset_folder.absoluteFilePath(relativePath.replace("@assets", "."))).canonicalFilePath();
+ } else if (relativePath.startsWith("@transitions")) {
+ absolutePath = QFileInfo(openshotTransPath.absoluteFilePath(relativePath.replace("@transitions", "."))).canonicalFilePath();
+ } else {
+ absolutePath = QFileInfo(filePath.absoluteDir().absoluteFilePath(relativePath)).canonicalFilePath();
+ }
+
+ // Replace path in JSON content, if an absolute path was successfully found
+ if (!absolutePath.isEmpty()) {
+ projectContents.replace(match.capturedStart(0), match.capturedLength(0), "\"" + relativeKey + "\": \"" + absolutePath + "\"");
+ }
+ }
+ // Clear matches
+ matchedPositions.clear();
+ }
+
+ // Set JSON of project
+ SetJson(projectContents.toStdString());
+
+ // Calculate valid duration and set has_audio and has_video
+ // based on content inside this Timeline's clips.
+ float calculated_duration = 0.0;
+ for (auto clip : clips)
+ {
+ float clip_last_frame = clip->Position() + clip->Duration();
+ if (clip_last_frame > calculated_duration)
+ calculated_duration = clip_last_frame;
+ if (clip->Reader() && clip->Reader()->info.has_audio)
+ info.has_audio = true;
+ if (clip->Reader() && clip->Reader()->info.has_video)
+ info.has_video = true;
+
+ }
+ info.video_length = calculated_duration * info.fps.ToFloat();
+ info.duration = calculated_duration;
+
+ // Init FileInfo settings
+ info.acodec = "openshot::timeline";
+ info.vcodec = "openshot::timeline";
+ info.video_timebase = info.fps.Reciprocal();
+ info.has_video = true;
+ info.has_audio = true;
+
+ // Init max image size
+ SetMaxSize(info.width, info.height);
+
+ // Init cache
+ final_cache = new CacheMemory();
+ final_cache->SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels);
+}
+
Timeline::~Timeline() {
if (is_open)
// Auto Close if not already
Close();
// Free all allocated frame mappers
- std::set::iterator frame_mapper_itr;
- for (frame_mapper_itr = allocated_frame_mappers.begin(); frame_mapper_itr != allocated_frame_mappers.end(); ++frame_mapper_itr) {
- // Get frame mapper object from the iterator
- FrameMapper *frame_mapper = (*frame_mapper_itr);
- frame_mapper->Reader(NULL);
- frame_mapper->Close();
- delete frame_mapper;
+ std::set::iterator it;
+ for (it = allocated_frame_mappers.begin(); it != allocated_frame_mappers.end(); ) {
+ // Dereference and clean up FrameMapper object
+ FrameMapper *mapper = (*it);
+ mapper->Reader(NULL);
+ mapper->Close();
+ delete mapper;
+ // Remove reference and proceed to next element
+ it = allocated_frame_mappers.erase(it);
}
- allocated_frame_mappers.clear();
// Destroy previous cache (if managed by timeline)
if (managed_cache && final_cache) {
@@ -169,12 +299,8 @@ void Timeline::ApplyMapperToClips()
ClearAllCache();
// Loop through all clips
- std::list::iterator clip_itr;
- for (clip_itr=clips.begin(); clip_itr != clips.end(); ++clip_itr)
+ for (auto clip : clips)
{
- // Get clip object from the iterator
- Clip *clip = (*clip_itr);
-
// Apply framemapper (or update existing framemapper)
apply_mapper_to_clip(clip);
}
@@ -197,12 +323,8 @@ std::shared_ptr Timeline::apply_effects(std::shared_ptr frame, int
ZmqLogger::Instance()->AppendDebugMethod("Timeline::apply_effects", "frame->number", frame->number, "timeline_frame_number", timeline_frame_number, "layer", layer);
// Find Effects at this position and layer
- std::list::iterator effect_itr;
- for (effect_itr=effects.begin(); effect_itr != effects.end(); ++effect_itr)
+ for (auto effect : effects)
{
- // Get effect object from the iterator
- EffectBase *effect = (*effect_itr);
-
// Does clip intersect the current requested time
long effect_start_position = round(effect->Position() * info.fps.ToDouble()) + 1;
long effect_end_position = round((effect->Position() + (effect->Duration())) * info.fps.ToDouble()) + 1;
@@ -379,8 +501,9 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in
}
- // Skip out if only an audio frame
- if (!source_clip->Waveform() && !source_clip->Reader()->info.has_video)
+ // Skip out if video was disabled or only an audio frame (no visualisation in use)
+ if (source_clip->has_video.GetInt(clip_frame_number) == 0 ||
+ (!source_clip->Waveform() && !source_clip->Reader()->info.has_video))
// Skip the rest of the image processing for performance reasons
return;
@@ -466,34 +589,37 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in
float crop_h = source_clip->crop_height.GetValue(clip_frame_number);
switch(source_clip->crop_gravity)
{
- case (GRAVITY_TOP):
- crop_x += 0.5;
- break;
- case (GRAVITY_TOP_RIGHT):
- crop_x += 1.0;
- break;
- case (GRAVITY_LEFT):
- crop_y += 0.5;
- break;
- case (GRAVITY_CENTER):
- crop_x += 0.5;
- crop_y += 0.5;
- break;
- case (GRAVITY_RIGHT):
- crop_x += 1.0;
- crop_y += 0.5;
- break;
- case (GRAVITY_BOTTOM_LEFT):
- crop_y += 1.0;
- break;
- case (GRAVITY_BOTTOM):
- crop_x += 0.5;
- crop_y += 1.0;
- break;
- case (GRAVITY_BOTTOM_RIGHT):
- crop_x += 1.0;
- crop_y += 1.0;
- break;
+ case (GRAVITY_TOP_LEFT):
+ // This is only here to prevent unused-enum warnings
+ break;
+ case (GRAVITY_TOP):
+ crop_x += 0.5;
+ break;
+ case (GRAVITY_TOP_RIGHT):
+ crop_x += 1.0;
+ break;
+ case (GRAVITY_LEFT):
+ crop_y += 0.5;
+ break;
+ case (GRAVITY_CENTER):
+ crop_x += 0.5;
+ crop_y += 0.5;
+ break;
+ case (GRAVITY_RIGHT):
+ crop_x += 1.0;
+ crop_y += 0.5;
+ break;
+ case (GRAVITY_BOTTOM_LEFT):
+ crop_y += 1.0;
+ break;
+ case (GRAVITY_BOTTOM):
+ crop_x += 0.5;
+ crop_y += 1.0;
+ break;
+ case (GRAVITY_BOTTOM_RIGHT):
+ crop_x += 1.0;
+ crop_y += 1.0;
+ break;
}
@@ -509,6 +635,9 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in
switch (source_clip->gravity)
{
+ case (GRAVITY_TOP_LEFT):
+ // This is only here to prevent unused-enum warnings
+ break;
case (GRAVITY_TOP):
x = (Settings::Instance()->MAX_WIDTH - scaled_source_width) / 2.0; // center
break;
@@ -611,6 +740,10 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in
std::stringstream frame_number_str;
switch (source_clip->display)
{
+ case (FRAME_DISPLAY_NONE):
+ // This is only here to prevent unused-enum warnings
+ break;
+
case (FRAME_DISPLAY_CLIP):
frame_number_str << clip_frame_number;
break;
@@ -692,12 +825,8 @@ void Timeline::Close()
ZmqLogger::Instance()->AppendDebugMethod("Timeline::Close");
// Close all open clips
- std::list::iterator clip_itr;
- for (clip_itr=clips.begin(); clip_itr != clips.end(); ++clip_itr)
+ for (auto clip : clips)
{
- // Get clip object from the iterator
- Clip *clip = (*clip_itr);
-
// Open or Close this clip, based on if it's intersecting or not
update_open_clips(clip, false);
}
@@ -706,7 +835,8 @@ void Timeline::Close()
is_open = false;
// Clear cache
- final_cache->Clear();
+ if (final_cache)
+ final_cache->Clear();
}
// Open the reader (and start consuming resources)
@@ -780,10 +910,8 @@ std::shared_ptr Timeline::GetFrame(int64_t requested_frame)
for (int64_t frame_number = requested_frame; frame_number < requested_frame + minimum_frames; frame_number++)
{
// Loop through clips
- for (int clip_index = 0; clip_index < nearby_clips.size(); clip_index++)
+ for (auto clip : nearby_clips)
{
- // Get clip object from the iterator
- Clip *clip = nearby_clips[clip_index];
long clip_start_position = round(clip->Position() * info.fps.ToDouble()) + 1;
long clip_end_position = round((clip->Position() + clip->Duration()) * info.fps.ToDouble()) + 1;
@@ -832,10 +960,8 @@ std::shared_ptr Timeline::GetFrame(int64_t requested_frame)
ZmqLogger::Instance()->AppendDebugMethod("Timeline::GetFrame (Loop through clips)", "frame_number", frame_number, "clips.size()", clips.size(), "nearby_clips.size()", nearby_clips.size());
// Find Clips near this time
- for (int clip_index = 0; clip_index < nearby_clips.size(); clip_index++)
+ for (auto clip : nearby_clips)
{
- // Get clip object from the iterator
- Clip *clip = nearby_clips[clip_index];
long clip_start_position = round(clip->Position() * info.fps.ToDouble()) + 1;
long clip_end_position = round((clip->Position() + clip->Duration()) * info.fps.ToDouble()) + 1;
@@ -850,9 +976,8 @@ std::shared_ptr Timeline::GetFrame(int64_t requested_frame)
// Determine if clip is "top" clip on this layer (only happens when multiple clips are overlapping)
bool is_top_clip = true;
float max_volume = 0.0;
- for (int top_clip_index = 0; top_clip_index < nearby_clips.size(); top_clip_index++)
+ for (auto nearby_clip : nearby_clips)
{
- Clip *nearby_clip = nearby_clips[top_clip_index];
long nearby_clip_start_position = round(nearby_clip->Position() * info.fps.ToDouble()) + 1;
long nearby_clip_end_position = round((nearby_clip->Position() + nearby_clip->Duration()) * info.fps.ToDouble()) + 1;
long nearby_clip_start_frame = (nearby_clip->Start() * info.fps.ToDouble()) + 1;
@@ -927,12 +1052,8 @@ std::vector Timeline::find_intersecting_clips(int64_t requested_frame, in
sort_clips();
// Find Clips at this time
- std::list::iterator clip_itr;
- for (clip_itr=clips.begin(); clip_itr != clips.end(); ++clip_itr)
+ for (auto clip : clips)
{
- // Get clip object from the iterator
- Clip *clip = (*clip_itr);
-
// Does clip intersect the current requested time
long clip_start_position = round(clip->Position() * info.fps.ToDouble()) + 1;
long clip_end_position = round((clip->Position() + clip->Duration()) * info.fps.ToDouble()) + 1;
@@ -977,14 +1098,14 @@ void Timeline::SetCache(CacheBase* new_cache) {
}
// Generate JSON string of this object
-std::string Timeline::Json() {
+std::string Timeline::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Timeline::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Timeline::JsonValue() const {
// Create root json object
Json::Value root = ReaderBase::JsonValue(); // get parent properties
@@ -993,16 +1114,14 @@ Json::Value Timeline::JsonValue() {
root["viewport_x"] = viewport_x.JsonValue();
root["viewport_y"] = viewport_y.JsonValue();
root["color"] = color.JsonValue();
+ root["path"] = path;
// Add array of clips
root["clips"] = Json::Value(Json::arrayValue);
// Find Clips at this time
- std::list::iterator clip_itr;
- for (clip_itr=clips.begin(); clip_itr != clips.end(); ++clip_itr)
+ for (const auto existing_clip : clips)
{
- // Get clip object from the iterator
- Clip *existing_clip = (*clip_itr);
root["clips"].append(existing_clip->JsonValue());
}
@@ -1010,11 +1129,8 @@ Json::Value Timeline::JsonValue() {
root["effects"] = Json::Value(Json::arrayValue);
// loop through effects
- std::list::iterator effect_itr;
- for (effect_itr=effects.begin(); effect_itr != effects.end(); ++effect_itr)
+ for (const auto existing_effect: effects)
{
- // Get clip object from the iterator
- EffectBase *existing_effect = (*effect_itr);
root["effects"].append(existing_effect->JsonValue());
}
@@ -1023,27 +1139,15 @@ Json::Value Timeline::JsonValue() {
}
// Load JSON string into this object
-void Timeline::SetJson(std::string value) {
+void Timeline::SetJson(const std::string value) {
// Get lock (prevent getting frames while this happens)
const GenericScopedLock lock(getFrameCriticalSection);
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -1054,8 +1158,8 @@ void Timeline::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Timeline::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Timeline::SetJsonValue(const Json::Value root) {
// Close timeline before we do anything (this also removes all open and closing clips)
bool was_open = is_open;
@@ -1064,15 +1168,16 @@ void Timeline::SetJsonValue(Json::Value root) {
// Set parent data
ReaderBase::SetJsonValue(root);
+ // Set data from Json (if key is found)
+ if (!root["path"].isNull())
+ path = root["path"].asString();
+
if (!root["clips"].isNull()) {
// Clear existing clips
clips.clear();
// loop through clips
- for (int x = 0; x < root["clips"].size(); x++) {
- // Get each clip
- Json::Value existing_clip = root["clips"][x];
-
+ for (const Json::Value existing_clip : root["clips"]) {
// Create Clip
Clip *c = new Clip();
@@ -1089,10 +1194,7 @@ void Timeline::SetJsonValue(Json::Value root) {
effects.clear();
// loop through effects
- for (int x = 0; x < root["effects"].size(); x++) {
- // Get each effect
- Json::Value existing_effect = root["effects"][x];
-
+ for (const Json::Value existing_effect :root["effects"]) {
// Create Effect
EffectBase *e = NULL;
@@ -1128,33 +1230,19 @@ void Timeline::ApplyJsonDiff(std::string value) {
const GenericScopedLock lock(getFrameCriticalSection);
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success || !root.isArray())
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid).");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Process the JSON change array, loop through each item
- for (int x = 0; x < root.size(); x++) {
- // Get each change
- Json::Value change = root[x];
- std::string root_key = change["key"][(uint)0].asString();
+ for (const Json::Value change : root) {
+ std::string change_key = change["key"][(uint)0].asString();
// Process each type of change
- if (root_key == "clips")
+ if (change_key == "clips")
// Apply to CLIPS
apply_json_to_clips(change);
- else if (root_key == "effects")
+ else if (change_key == "effects")
// Apply to EFFECTS
apply_json_to_effects(change);
@@ -1180,10 +1268,8 @@ void Timeline::apply_json_to_clips(Json::Value change) {
Clip *existing_clip = NULL;
// Find id of clip (if any)
- for (int x = 0; x < change["key"].size(); x++) {
+ for (auto key_part : change["key"]) {
// Get each change
- Json::Value key_part = change["key"][x];
-
if (key_part.isObject()) {
// Check for id
if (!key_part["id"].isNull()) {
@@ -1191,11 +1277,8 @@ void Timeline::apply_json_to_clips(Json::Value change) {
clip_id = key_part["id"].asString();
// Find matching clip in timeline (if any)
- std::list::iterator clip_itr;
- for (clip_itr=clips.begin(); clip_itr != clips.end(); ++clip_itr)
+ for (auto c : clips)
{
- // Get clip object from the iterator
- Clip *c = (*clip_itr);
if (c->Id() == clip_id) {
existing_clip = c;
break; // clip found, exit loop
@@ -1222,11 +1305,8 @@ void Timeline::apply_json_to_clips(Json::Value change) {
// Find matching effect in timeline (if any)
std::list effect_list = existing_clip->Effects();
- std::list::iterator effect_itr;
- for (effect_itr=effect_list.begin(); effect_itr != effect_list.end(); ++effect_itr)
+ for (auto e : effect_list)
{
- // Get effect object from the iterator
- EffectBase *e = (*effect_itr);
if (e->Id() == effect_id) {
// Apply the change to the effect directly
apply_json_to_effects(change, e);
@@ -1308,9 +1388,7 @@ void Timeline::apply_json_to_effects(Json::Value change) {
EffectBase *existing_effect = NULL;
// Find id of an effect (if any)
- for (int x = 0; x < change["key"].size(); x++) {
- // Get each change
- Json::Value key_part = change["key"][x];
+ for (auto key_part : change["key"]) {
if (key_part.isObject()) {
// Check for id
@@ -1320,11 +1398,8 @@ void Timeline::apply_json_to_effects(Json::Value change) {
std::string effect_id = key_part["id"].asString();
// Find matching effect in timeline (if any)
- std::list::iterator effect_itr;
- for (effect_itr=effects.begin(); effect_itr != effects.end(); ++effect_itr)
+ for (auto e : effects)
{
- // Get effect object from the iterator
- EffectBase *e = (*effect_itr);
if (e->Id() == effect_id) {
existing_effect = e;
break; // effect found, exit loop
@@ -1533,12 +1608,8 @@ void Timeline::ClearAllCache() {
final_cache->Clear();
// Loop through all clips
- std::list::iterator clip_itr;
- for (clip_itr=clips.begin(); clip_itr != clips.end(); ++clip_itr)
+ for (auto clip : clips)
{
- // Get clip object from the iterator
- Clip *clip = (*clip_itr);
-
// Clear cache on clip
clip->Reader()->GetCache()->Clear();
diff --git a/src/WriterBase.cpp b/src/WriterBase.cpp
index 72b86b611..388219179 100644
--- a/src/WriterBase.cpp
+++ b/src/WriterBase.cpp
@@ -139,14 +139,14 @@ void WriterBase::DisplayInfo() {
}
// Generate JSON string of this object
-std::string WriterBase::Json() {
+std::string WriterBase::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value WriterBase::JsonValue() {
+// Generate Json::Value for this object
+Json::Value WriterBase::JsonValue() const {
// Create root json object
Json::Value root;
@@ -195,24 +195,12 @@ Json::Value WriterBase::JsonValue() {
}
// Load JSON string into this object
-void WriterBase::SetJson(std::string value) {
+void WriterBase::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -223,8 +211,8 @@ void WriterBase::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void WriterBase::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void WriterBase::SetJsonValue(const Json::Value root) {
// Set data from Json (if key is found)
if (!root["has_video"].isNull())
diff --git a/src/effects/Bars.cpp b/src/effects/Bars.cpp
index fcb684e3f..3f9aac344 100644
--- a/src/effects/Bars.cpp
+++ b/src/effects/Bars.cpp
@@ -114,14 +114,14 @@ std::shared_ptr Bars::GetFrame(std::shared_ptr frame, int64_t fram
}
// Generate JSON string of this object
-std::string Bars::Json() {
+std::string Bars::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Bars::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Bars::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
@@ -137,24 +137,12 @@ Json::Value Bars::JsonValue() {
}
// Load JSON string into this object
-void Bars::SetJson(std::string value) {
+void Bars::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -165,8 +153,8 @@ void Bars::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Bars::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Bars::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
@@ -185,7 +173,7 @@ void Bars::SetJsonValue(Json::Value root) {
}
// Get all properties for a specific frame
-std::string Bars::PropertiesJSON(int64_t requested_frame) {
+std::string Bars::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
diff --git a/src/effects/Blur.cpp b/src/effects/Blur.cpp
index e0315fda4..6ddba88e6 100644
--- a/src/effects/Blur.cpp
+++ b/src/effects/Blur.cpp
@@ -74,192 +74,109 @@ std::shared_ptr Blur::GetFrame(std::shared_ptr frame, int64_t fram
float sigma_value = sigma.GetValue(frame_number);
int iteration_value = iterations.GetInt(frame_number);
+ int w = frame_image->width();
+ int h = frame_image->height();
- // Declare arrays for each color channel
- unsigned char *red = new unsigned char[frame_image->width() * frame_image->height()]();
- unsigned char *green = new unsigned char[frame_image->width() * frame_image->height()]();
- unsigned char *blue = new unsigned char[frame_image->width() * frame_image->height()]();
- unsigned char *alpha = new unsigned char[frame_image->width() * frame_image->height()]();
- // Create empty target RGBA arrays (for the results of our blur)
- unsigned char *blur_red = new unsigned char[frame_image->width() * frame_image->height()]();
- unsigned char *blur_green = new unsigned char[frame_image->width() * frame_image->height()]();
- unsigned char *blur_blue = new unsigned char[frame_image->width() * frame_image->height()]();
- unsigned char *blur_alpha = new unsigned char[frame_image->width() * frame_image->height()]();
-
- // Loop through pixels and split RGBA channels into separate arrays
- unsigned char *pixels = (unsigned char *) frame_image->bits();
- for (int pixel = 0, byte_index=0; pixel < frame_image->width() * frame_image->height(); pixel++, byte_index+=4)
- {
- // Get the RGBA values from each pixel
- unsigned char R = pixels[byte_index];
- unsigned char G = pixels[byte_index + 1];
- unsigned char B = pixels[byte_index + 2];
- unsigned char A = pixels[byte_index + 3];
-
- // Split channels into their own arrays
- red[pixel] = R;
- green[pixel] = G;
- blue[pixel] = B;
- alpha[pixel] = A;
- }
-
- // Init target RGBA arrays
- for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) blur_red[i] = red[i];
- for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) blur_green[i] = green[i];
- for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) blur_blue[i] = blue[i];
- for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) blur_alpha[i] = alpha[i];
+ // Grab two copies of the image pixel data
+ QImage image_copy = frame_image->copy();
+ std::shared_ptr frame_image_2 = std::make_shared(image_copy);
// Loop through each iteration
- for (int iteration = 0; iteration < iteration_value; iteration++)
+ for (int iteration = 0; iteration < iteration_value; ++iteration)
{
// HORIZONTAL BLUR (if any)
if (horizontal_radius_value > 0.0) {
- // Init boxes for computing blur
- int *bxs = initBoxes(sigma_value, horizontal_radius_value);
-
// Apply horizontal blur to target RGBA channels
- boxBlurH(red, blur_red, frame_image->width(), frame_image->height(), horizontal_radius_value);
- boxBlurH(green, blur_green, frame_image->width(), frame_image->height(), horizontal_radius_value);
- boxBlurH(blue, blur_blue, frame_image->width(), frame_image->height(), horizontal_radius_value);
- boxBlurH(alpha, blur_alpha, frame_image->width(), frame_image->height(), horizontal_radius_value);
-
- // Remove boxes
- delete[] bxs;
-
- // Copy blur_ back to for vertical blur or next iteration
- for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) red[i] = blur_red[i];
- for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) green[i] = blur_green[i];
- for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) blue[i] = blur_blue[i];
- for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) alpha[i] = blur_alpha[i];
+ boxBlurH(frame_image->bits(), frame_image_2->bits(), w, h, horizontal_radius_value);
+
+ // Swap output image back to input
+ frame_image.swap(frame_image_2);
}
// VERTICAL BLUR (if any)
if (vertical_radius_value > 0.0) {
- // Init boxes for computing blur
- int *bxs = initBoxes(sigma_value, vertical_radius_value);
-
// Apply vertical blur to target RGBA channels
- boxBlurT(red, blur_red, frame_image->width(), frame_image->height(), vertical_radius_value);
- boxBlurT(green, blur_green, frame_image->width(), frame_image->height(), vertical_radius_value);
- boxBlurT(blue, blur_blue, frame_image->width(), frame_image->height(), vertical_radius_value);
- boxBlurT(alpha, blur_alpha, frame_image->width(), frame_image->height(), vertical_radius_value);
-
- // Remove boxes
- delete[] bxs;
-
- // Copy blur_ back to for vertical blur or next iteration
- for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) red[i] = blur_red[i];
- for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) green[i] = blur_green[i];
- for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) blue[i] = blur_blue[i];
- for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) alpha[i] = blur_alpha[i];
- }
- }
+ boxBlurT(frame_image->bits(), frame_image_2->bits(), w, h, vertical_radius_value);
- // Copy RGBA channels back to original image
- for (int pixel = 0, byte_index=0; pixel < frame_image->width() * frame_image->height(); pixel++, byte_index+=4)
- {
- // Get the RGB values from the pixel
- unsigned char R = blur_red[pixel];
- unsigned char G = blur_green[pixel];
- unsigned char B = blur_blue[pixel];
- unsigned char A = blur_alpha[pixel];
-
- // Split channels into their own arrays
- pixels[byte_index] = R;
- pixels[byte_index + 1] = G;
- pixels[byte_index + 2] = B;
- pixels[byte_index + 3] = A;
+ // Swap output image back to input
+ frame_image.swap(frame_image_2);
+ }
}
- // Delete channel arrays
- delete[] red;
- delete[] green;
- delete[] blue;
- delete[] alpha;
- delete[] blur_red;
- delete[] blur_green;
- delete[] blur_blue;
- delete[] blur_alpha;
-
// return the modified frame
return frame;
}
// Credit: http://blog.ivank.net/fastest-gaussian-blur.html (MIT License)
-int* Blur::initBoxes(float sigma, int n) // standard deviation, number of boxes
-{
- float wIdeal = sqrt((12.0 * sigma * sigma / n) + 1.0); // Ideal averaging filter width
- int wl = floor(wIdeal);
- if (wl % 2 == 0) wl--;
- int wu = wl + 2;
-
- float mIdeal = (12.0 * sigma * sigma - n * wl * wl - 4 * n * wl - 3 * n) / (-4.0 * wl - 4);
- int m = round(mIdeal);
-
- int *sizes = new int[n]();
- for (int i = 0; i < n; i++) sizes[i] = i < m ? wl : wu;
- return sizes;
-}
-
-// Credit: http://blog.ivank.net/fastest-gaussian-blur.html (MIT License)
+// Modified to process all four channels in a pixel array
void Blur::boxBlurH(unsigned char *scl, unsigned char *tcl, int w, int h, int r) {
float iarr = 1.0 / (r + r + 1);
- for (int i = 0; i < h; i++) {
- int ti = i * w, li = ti, ri = ti + r;
- int fv = scl[ti], lv = scl[ti + w - 1], val = (r + 1) * fv;
- for (int j = 0; j < r; j++) val += scl[ti + j];
- for (int j = 0; j <= r; j++) {
- val += scl[ri++] - fv;
- tcl[ti++] = round(val * iarr);
- }
- for (int j = r + 1; j < w - r; j++) {
- val += scl[ri++] - scl[li++];
- tcl[ti++] = round(val * iarr);
- }
- for (int j = w - r; j < w; j++) {
- val += lv - scl[li++];
- tcl[ti++] = round(val * iarr);
+
+ #pragma omp parallel for shared (scl, tcl)
+ for (int i = 0; i < h; ++i) {
+ for (int ch = 0; ch < 4; ++ch) {
+ int ti = i * w, li = ti, ri = ti + r;
+ int fv = scl[ti * 4 + ch], lv = scl[(ti + w - 1) * 4 + ch], val = (r + 1) * fv;
+ for (int j = 0; j < r; ++j) {
+ val += scl[(ti + j) * 4 + ch];
+ }
+ for (int j = 0; j <= r; ++j) {
+ val += scl[ri++ * 4 + ch] - fv;
+ tcl[ti++ * 4 + ch] = round(val * iarr);
+ }
+ for (int j = r + 1; j < w - r; ++j) {
+ val += scl[ri++ * 4 + ch] - scl[li++ * 4 + ch];
+ tcl[ti++ * 4 + ch] = round(val * iarr);
+ }
+ for (int j = w - r; j < w; ++j) {
+ val += lv - scl[li++ * 4 + ch];
+ tcl[ti++ * 4 + ch] = round(val * iarr);
+ }
}
}
}
void Blur::boxBlurT(unsigned char *scl, unsigned char *tcl, int w, int h, int r) {
float iarr = 1.0 / (r + r + 1);
+
+ #pragma omp parallel for shared (scl, tcl)
for (int i = 0; i < w; i++) {
- int ti = i, li = ti, ri = ti + r * w;
- int fv = scl[ti], lv = scl[ti + w * (h - 1)], val = (r + 1) * fv;
- for (int j = 0; j < r; j++) val += scl[ti + j * w];
- for (int j = 0; j <= r; j++) {
- val += scl[ri] - fv;
- tcl[ti] = round(val * iarr);
- ri += w;
- ti += w;
- }
- for (int j = r + 1; j < h - r; j++) {
- val += scl[ri] - scl[li];
- tcl[ti] = round(val * iarr);
- li += w;
- ri += w;
- ti += w;
- }
- for (int j = h - r; j < h; j++) {
- val += lv - scl[li];
- tcl[ti] = round(val * iarr);
- li += w;
- ti += w;
+ for (int ch = 0; ch < 4; ++ch) {
+ int ti = i, li = ti, ri = ti + r * w;
+ int fv = scl[ti * 4 + ch], lv = scl[(ti + w * (h - 1)) * 4 + ch], val = (r + 1) * fv;
+ for (int j = 0; j < r; j++) val += scl[(ti + j * w) * 4 + ch];
+ for (int j = 0; j <= r; j++) {
+ val += scl[ri * 4 + ch] - fv;
+ tcl[ti * 4 + ch] = round(val * iarr);
+ ri += w;
+ ti += w;
+ }
+ for (int j = r + 1; j < h - r; j++) {
+ val += scl[ri * 4 + ch] - scl[li * 4 + ch];
+ tcl[ti * 4 + ch] = round(val * iarr);
+ li += w;
+ ri += w;
+ ti += w;
+ }
+ for (int j = h - r; j < h; j++) {
+ val += lv - scl[li * 4 + ch];
+ tcl[ti * 4 + ch] = round(val * iarr);
+ li += w;
+ ti += w;
+ }
}
}
}
// Generate JSON string of this object
-std::string Blur::Json() {
+std::string Blur::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Blur::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Blur::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
@@ -274,24 +191,12 @@ Json::Value Blur::JsonValue() {
}
// Load JSON string into this object
-void Blur::SetJson(std::string value) {
+void Blur::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -302,8 +207,8 @@ void Blur::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Blur::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Blur::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
@@ -320,7 +225,7 @@ void Blur::SetJsonValue(Json::Value root) {
}
// Get all properties for a specific frame
-std::string Blur::PropertiesJSON(int64_t requested_frame) {
+std::string Blur::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
diff --git a/src/effects/Brightness.cpp b/src/effects/Brightness.cpp
index b8113b876..321a19a78 100644
--- a/src/effects/Brightness.cpp
+++ b/src/effects/Brightness.cpp
@@ -72,35 +72,24 @@ std::shared_ptr Brightness::GetFrame(std::shared_ptr frame, int64_
// Loop through pixels
unsigned char *pixels = (unsigned char *) frame_image->bits();
- for (int pixel = 0, byte_index=0; pixel < frame_image->width() * frame_image->height(); pixel++, byte_index+=4)
- {
- // Get the RGB values from the pixel
- int R = pixels[byte_index];
- int G = pixels[byte_index + 1];
- int B = pixels[byte_index + 2];
- int A = pixels[byte_index + 3];
+ int pixel_count = frame_image->width() * frame_image->height();
- // Adjust the contrast
+ #pragma omp parallel for
+ for (int pixel = 0; pixel < pixel_count; ++pixel)
+ {
+ // Compute contrast adjustment factor
float factor = (259 * (contrast_value + 255)) / (255 * (259 - contrast_value));
- R = constrain((factor * (R - 128)) + 128);
- G = constrain((factor * (G - 128)) + 128);
- B = constrain((factor * (B - 128)) + 128);
-
- // Adjust the brightness
- R += (255 * brightness_value);
- G += (255 * brightness_value);
- B += (255 * brightness_value);
-
- // Constrain the value from 0 to 255
- R = constrain(R);
- G = constrain(G);
- B = constrain(B);
-
- // Set all pixels to new value
- pixels[byte_index] = R;
- pixels[byte_index + 1] = G;
- pixels[byte_index + 2] = B;
- pixels[byte_index + 3] = A; // leave the alpha value alone
+
+ // Get RGB pixels from image and apply constrained contrast adjustment
+ int R = constrain((factor * (pixels[pixel * 4] - 128)) + 128);
+ int G = constrain((factor * (pixels[pixel * 4 + 1] - 128)) + 128);
+ int B = constrain((factor * (pixels[pixel * 4 + 2] - 128)) + 128);
+ // (Don't modify Alpha value)
+
+ // Adjust brightness and write constrained values back to image
+ pixels[pixel * 4] = constrain(R + (255 * brightness_value));
+ pixels[pixel * 4 + 1] = constrain(G + (255 * brightness_value));
+ pixels[pixel * 4 + 2] = constrain(B + (255 * brightness_value));
}
// return the modified frame
@@ -108,14 +97,14 @@ std::shared_ptr Brightness::GetFrame(std::shared_ptr frame, int64_
}
// Generate JSON string of this object
-std::string Brightness::Json() {
+std::string Brightness::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Brightness::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Brightness::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
@@ -128,24 +117,12 @@ Json::Value Brightness::JsonValue() {
}
// Load JSON string into this object
-void Brightness::SetJson(std::string value) {
+void Brightness::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -156,8 +133,8 @@ void Brightness::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Brightness::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Brightness::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
@@ -170,7 +147,7 @@ void Brightness::SetJsonValue(Json::Value root) {
}
// Get all properties for a specific frame
-std::string Brightness::PropertiesJSON(int64_t requested_frame) {
+std::string Brightness::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
diff --git a/src/effects/ChromaKey.cpp b/src/effects/ChromaKey.cpp
index 30c4dfce8..dbb56a693 100644
--- a/src/effects/ChromaKey.cpp
+++ b/src/effects/ChromaKey.cpp
@@ -101,14 +101,14 @@ std::shared_ptr ChromaKey::GetFrame(std::shared_ptr frame, int64_t
}
// Generate JSON string of this object
-std::string ChromaKey::Json() {
+std::string ChromaKey::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value ChromaKey::JsonValue() {
+// Generate Json::Value for this object
+Json::Value ChromaKey::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
@@ -121,24 +121,12 @@ Json::Value ChromaKey::JsonValue() {
}
// Load JSON string into this object
-void ChromaKey::SetJson(std::string value) {
+void ChromaKey::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -149,8 +137,8 @@ void ChromaKey::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void ChromaKey::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void ChromaKey::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
@@ -163,7 +151,7 @@ void ChromaKey::SetJsonValue(Json::Value root) {
}
// Get all properties for a specific frame
-std::string ChromaKey::PropertiesJSON(int64_t requested_frame) {
+std::string ChromaKey::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
diff --git a/src/effects/ColorShift.cpp b/src/effects/ColorShift.cpp
index ea8ae136e..7ec62e14c 100644
--- a/src/effects/ColorShift.cpp
+++ b/src/effects/ColorShift.cpp
@@ -33,7 +33,7 @@
using namespace openshot;
/// Blank constructor, useful when using Json to load the effect properties
-ColorShift::ColorShift() : red_x(-0.05), red_y(0.0), green_x(0.05), green_y(0.0), blue_x(0.0), blue_y(0.0), alpha_x(0.0), alpha_y(0.0) {
+ColorShift::ColorShift() : red_x(0.0), red_y(0.0), green_x(0.0), green_y(0.0), blue_x(0.0), blue_y(0.0), alpha_x(0.0), alpha_y(0.0) {
// Init effect properties
init_effect_details();
}
@@ -53,7 +53,7 @@ void ColorShift::init_effect_details()
InitEffectInfo();
/// Set the effect info
- info.class_name = "Color Shift";
+ info.class_name = "ColorShift";
info.name = "Color Shift";
info.description = "Shift the colors of an image up, down, left, and right (with infinite wrapping).";
info.has_audio = false;
@@ -75,25 +75,24 @@ std::shared_ptr ColorShift::GetFrame(std::shared_ptr frame, int64_
// Get the current shift amount, and clamp to range (-1 to 1 range)
// Red Keyframes
float red_x_shift = red_x.GetValue(frame_number);
- int red_x_shift_limit = round(frame_image_width * fmod(abs(red_x_shift), 1.0));
+ int red_x_shift_limit = round(frame_image_width * fmod(fabs(red_x_shift), 1.0));
float red_y_shift = red_y.GetValue(frame_number);
- int red_y_shift_limit = round(frame_image_height * fmod(abs(red_y_shift), 1.0));
+ int red_y_shift_limit = round(frame_image_height * fmod(fabs(red_y_shift), 1.0));
// Green Keyframes
float green_x_shift = green_x.GetValue(frame_number);
- int green_x_shift_limit = round(frame_image_width * fmod(abs(green_x_shift), 1.0));
+ int green_x_shift_limit = round(frame_image_width * fmod(fabs(green_x_shift), 1.0));
float green_y_shift = green_y.GetValue(frame_number);
- int green_y_shift_limit = round(frame_image_height * fmod(abs(green_y_shift), 1.0));
+ int green_y_shift_limit = round(frame_image_height * fmod(fabs(green_y_shift), 1.0));
// Blue Keyframes
float blue_x_shift = blue_x.GetValue(frame_number);
- int blue_x_shift_limit = round(frame_image_width * fmod(abs(blue_x_shift), 1.0));
+ int blue_x_shift_limit = round(frame_image_width * fmod(fabs(blue_x_shift), 1.0));
float blue_y_shift = blue_y.GetValue(frame_number);
- int blue_y_shift_limit = round(frame_image_height * fmod(abs(blue_y_shift), 1.0));
+ int blue_y_shift_limit = round(frame_image_height * fmod(fabs(blue_y_shift), 1.0));
// Alpha Keyframes
float alpha_x_shift = alpha_x.GetValue(frame_number);
- int alpha_x_shift_limit = round(frame_image_width * fmod(abs(alpha_x_shift), 1.0));
+ int alpha_x_shift_limit = round(frame_image_width * fmod(fabs(alpha_x_shift), 1.0));
float alpha_y_shift = alpha_y.GetValue(frame_number);
- int alpha_y_shift_limit = round(frame_image_height * fmod(abs(alpha_y_shift), 1.0));
-
+ int alpha_y_shift_limit = round(frame_image_height * fmod(fabs(alpha_y_shift), 1.0));
// Make temp copy of pixels
unsigned char *temp_image = new unsigned char[frame_image_width * frame_image_height * 4]();
@@ -130,7 +129,6 @@ std::shared_ptr ColorShift::GetFrame(std::shared_ptr frame, int64_
blue_starting_row_index = starting_row_index;
alpha_starting_row_index = starting_row_index;
-
red_pixel_offset = 0;
green_pixel_offset = 0;
blue_pixel_offset = 0;
@@ -194,14 +192,14 @@ std::shared_ptr ColorShift::GetFrame(std::shared_ptr frame, int64_
}
// Generate JSON string of this object
-std::string ColorShift::Json() {
+std::string ColorShift::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value ColorShift::JsonValue() {
+// Generate Json::Value for this object
+Json::Value ColorShift::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
@@ -220,24 +218,12 @@ Json::Value ColorShift::JsonValue() {
}
// Load JSON string into this object
-void ColorShift::SetJson(std::string value) {
+void ColorShift::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -248,8 +234,8 @@ void ColorShift::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void ColorShift::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void ColorShift::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
@@ -274,7 +260,7 @@ void ColorShift::SetJsonValue(Json::Value root) {
}
// Get all properties for a specific frame
-std::string ColorShift::PropertiesJSON(int64_t requested_frame) {
+std::string ColorShift::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
diff --git a/src/effects/Crop.cpp b/src/effects/Crop.cpp
index 8a4afa5e1..b1c3d38d9 100644
--- a/src/effects/Crop.cpp
+++ b/src/effects/Crop.cpp
@@ -114,14 +114,14 @@ std::shared_ptr Crop::GetFrame(std::shared_ptr frame, int64_t fram
}
// Generate JSON string of this object
-std::string Crop::Json() {
+std::string Crop::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Crop::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Crop::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
@@ -136,24 +136,12 @@ Json::Value Crop::JsonValue() {
}
// Load JSON string into this object
-void Crop::SetJson(std::string value) {
+void Crop::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -164,8 +152,8 @@ void Crop::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Crop::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Crop::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
@@ -182,7 +170,7 @@ void Crop::SetJsonValue(Json::Value root) {
}
// Get all properties for a specific frame
-std::string Crop::PropertiesJSON(int64_t requested_frame) {
+std::string Crop::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
diff --git a/src/effects/Deinterlace.cpp b/src/effects/Deinterlace.cpp
index a78af9314..39b3316a5 100644
--- a/src/effects/Deinterlace.cpp
+++ b/src/effects/Deinterlace.cpp
@@ -96,14 +96,14 @@ std::shared_ptr Deinterlace::GetFrame(std::shared_ptr frame, int64
}
// Generate JSON string of this object
-std::string Deinterlace::Json() {
+std::string Deinterlace::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Deinterlace::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Deinterlace::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
@@ -115,24 +115,12 @@ Json::Value Deinterlace::JsonValue() {
}
// Load JSON string into this object
-void Deinterlace::SetJson(std::string value) {
+void Deinterlace::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -143,8 +131,8 @@ void Deinterlace::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Deinterlace::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Deinterlace::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
@@ -155,7 +143,7 @@ void Deinterlace::SetJsonValue(Json::Value root) {
}
// Get all properties for a specific frame
-std::string Deinterlace::PropertiesJSON(int64_t requested_frame) {
+std::string Deinterlace::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
diff --git a/src/effects/Hue.cpp b/src/effects/Hue.cpp
index 4083d0356..eb4808e31 100644
--- a/src/effects/Hue.cpp
+++ b/src/effects/Hue.cpp
@@ -66,36 +66,35 @@ std::shared_ptr Hue::GetFrame(std::shared_ptr frame, int64_t frame
// Get the frame's image
std::shared_ptr frame_image = frame->GetImage();
+ int pixel_count = frame_image->width() * frame_image->height();
+
// Get the current hue percentage shift amount, and convert to degrees
double degrees = 360.0 * hue.GetValue(frame_number);
float cosA = cos(degrees*3.14159265f/180);
float sinA = sin(degrees*3.14159265f/180);
// Calculate a rotation matrix for the RGB colorspace (based on the current hue shift keyframe value)
- float matrix[3][3] = {{cosA + (1.0f - cosA) / 3.0f, 1.0f/3.0f * (1.0f - cosA) - sqrtf(1.0f/3.0f) * sinA, 1.0f/3.0f * (1.0f - cosA) + sqrtf(1.0f/3.0f) * sinA},
- {1.0f/3.0f * (1.0f - cosA) + sqrtf(1.0f/3.0f) * sinA, cosA + 1.0f/3.0f*(1.0f - cosA), 1.0f/3.0f * (1.0f - cosA) - sqrtf(1.0f/3.0f) * sinA},
- {1.0f/3.0f * (1.0f - cosA) - sqrtf(1.0f/3.0f) * sinA, 1.0f/3.0f * (1.0f - cosA) + sqrtf(1.0f/3.0f) * sinA, cosA + 1.0f/3.0f * (1.0f - cosA)}};
+ float matrix[3] = {
+ cosA + (1.0f - cosA) / 3.0f,
+ 1.0f/3.0f * (1.0f - cosA) - sqrtf(1.0f/3.0f) * sinA,
+ 1.0f/3.0f * (1.0f - cosA) + sqrtf(1.0f/3.0f) * sinA
+ };
// Loop through pixels
unsigned char *pixels = (unsigned char *) frame_image->bits();
- for (int pixel = 0, byte_index=0; pixel < frame_image->width() * frame_image->height(); pixel++, byte_index+=4)
+
+ #pragma omp parallel for shared (pixels)
+ for (int pixel = 0; pixel < pixel_count; ++pixel)
{
- // Get the RGB values from the pixel
- int R = pixels[byte_index];
- int G = pixels[byte_index + 1];
- int B = pixels[byte_index + 2];
- int A = pixels[byte_index + 3];
+ // Get the RGB values from the pixel (ignore the alpha channel)
+ int R = pixels[pixel * 4];
+ int G = pixels[pixel * 4 + 1];
+ int B = pixels[pixel * 4 + 2];
// Multiply each color by the hue rotation matrix
- float rx = constrain(R * matrix[0][0] + G * matrix[0][1] + B * matrix[0][2]);
- float gx = constrain(R * matrix[1][0] + G * matrix[1][1] + B * matrix[1][2]);
- float bx = constrain(R * matrix[2][0] + G * matrix[2][1] + B * matrix[2][2]);
-
- // Set all pixels to new value
- pixels[byte_index] = rx;
- pixels[byte_index + 1] = gx;
- pixels[byte_index + 2] = bx;
- pixels[byte_index + 3] = A; // leave the alpha value alone
+ pixels[pixel * 4] = constrain(R * matrix[0] + G * matrix[1] + B * matrix[2]);
+ pixels[pixel * 4 + 1] = constrain(R * matrix[2] + G * matrix[0] + B * matrix[1]);
+ pixels[pixel * 4 + 2] = constrain(R * matrix[1] + G * matrix[2] + B * matrix[0]);
}
// return the modified frame
@@ -103,14 +102,14 @@ std::shared_ptr Hue::GetFrame(std::shared_ptr frame, int64_t frame
}
// Generate JSON string of this object
-std::string Hue::Json() {
+std::string Hue::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Hue::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Hue::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
@@ -122,24 +121,12 @@ Json::Value Hue::JsonValue() {
}
// Load JSON string into this object
-void Hue::SetJson(std::string value) {
+void Hue::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -150,8 +137,8 @@ void Hue::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Hue::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Hue::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
@@ -162,7 +149,7 @@ void Hue::SetJsonValue(Json::Value root) {
}
// Get all properties for a specific frame
-std::string Hue::PropertiesJSON(int64_t requested_frame) {
+std::string Hue::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
diff --git a/src/effects/Mask.cpp b/src/effects/Mask.cpp
index b804c2148..11c37f053 100644
--- a/src/effects/Mask.cpp
+++ b/src/effects/Mask.cpp
@@ -150,14 +150,14 @@ std::shared_ptr Mask::GetFrame(std::shared_ptr frame, int64_t fram
}
// Generate JSON string of this object
-std::string Mask::Json() {
+std::string Mask::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Mask::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Mask::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
@@ -175,24 +175,12 @@ Json::Value Mask::JsonValue() {
}
// Load JSON string into this object
-void Mask::SetJson(std::string value) {
+void Mask::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -203,8 +191,8 @@ void Mask::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Mask::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Mask::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
@@ -271,7 +259,7 @@ void Mask::SetJsonValue(Json::Value root) {
}
// Get all properties for a specific frame
-std::string Mask::PropertiesJSON(int64_t requested_frame) {
+std::string Mask::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
diff --git a/src/effects/Negate.cpp b/src/effects/Negate.cpp
index cce594984..18a5d194c 100644
--- a/src/effects/Negate.cpp
+++ b/src/effects/Negate.cpp
@@ -58,14 +58,14 @@ std::shared_ptr Negate::GetFrame(std::shared_ptr frame, int64_t fr
}
// Generate JSON string of this object
-std::string Negate::Json() {
+std::string Negate::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Negate::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Negate::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
@@ -76,24 +76,12 @@ Json::Value Negate::JsonValue() {
}
// Load JSON string into this object
-void Negate::SetJson(std::string value) {
+void Negate::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -104,8 +92,8 @@ void Negate::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Negate::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Negate::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
@@ -113,7 +101,7 @@ void Negate::SetJsonValue(Json::Value root) {
}
// Get all properties for a specific frame
-std::string Negate::PropertiesJSON(int64_t requested_frame) {
+std::string Negate::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
diff --git a/src/effects/Pixelate.cpp b/src/effects/Pixelate.cpp
index a57a186f1..c993915c5 100644
--- a/src/effects/Pixelate.cpp
+++ b/src/effects/Pixelate.cpp
@@ -75,34 +75,20 @@ std::shared_ptr Pixelate::GetFrame(std::shared_ptr frame, int64_t
double bottom_value = bottom.GetValue(frame_number);
if (pixelization_value > 0.0) {
- // Resize frame image smaller (based on pixelization value)
- std::shared_ptr smaller_frame_image = std::shared_ptr(new QImage(frame_image->scaledToWidth(std::max(frame_image->width() * pixelization_value, 2.0), Qt::SmoothTransformation)));
-
- // Resize image back to original size (with no smoothing to create pixelated image)
- std::shared_ptr pixelated_image = std::shared_ptr(new QImage(smaller_frame_image->scaledToWidth(frame_image->width(), Qt::FastTransformation).convertToFormat(QImage::Format_RGBA8888)));
-
- // Get pixel array pointer
- unsigned char *pixels = (unsigned char *) frame_image->bits();
- unsigned char *pixelated_pixels = (unsigned char *) pixelated_image->bits();
-
- // Get pixels sizes of all margins
- int top_bar_height = top_value * frame_image->height();
- int bottom_bar_height = bottom_value * frame_image->height();
- int left_bar_width = left_value * frame_image->width();
- int right_bar_width = right_value * frame_image->width();
-
- // Loop through rows
- for (int row = 0; row < frame_image->height(); row++) {
-
- // Copy pixelated pixels into original frame image (where needed)
- if ((row >= top_bar_height) && (row <= frame_image->height() - bottom_bar_height)) {
- memcpy(&pixels[(row * frame_image->width() + left_bar_width) * 4], &pixelated_pixels[(row * frame_image->width() + left_bar_width) * 4], sizeof(char) * (frame_image->width() - left_bar_width - right_bar_width) * 4);
- }
- }
-
- // Cleanup temp images
- smaller_frame_image.reset();
- pixelated_image.reset();
+ int w = frame_image->width();
+ int h = frame_image->height();
+
+ // Define area we're working on in terms of a QRect with QMargins applied
+ QRect area(QPoint(0,0), frame_image->size());
+ area = area.marginsRemoved({int(left_value * w), int(top_value * h), int(right_value * w), int(bottom_value * h)});
+
+ // Copy and scale pixels in area to be pixelated
+ auto frame_scaled = frame_image->copy(area).scaledToWidth(area.width() * pixelization_value, Qt::SmoothTransformation);
+
+ // Draw pixelated image back over original
+ QPainter painter(frame_image.get());
+ painter.drawImage(area, frame_scaled);
+ painter.end();
}
// return the modified frame
@@ -110,14 +96,14 @@ std::shared_ptr Pixelate::GetFrame(std::shared_ptr frame, int64_t
}
// Generate JSON string of this object
-std::string Pixelate::Json() {
+std::string Pixelate::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Pixelate::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Pixelate::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
@@ -133,24 +119,12 @@ Json::Value Pixelate::JsonValue() {
}
// Load JSON string into this object
-void Pixelate::SetJson(std::string value) {
+void Pixelate::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -161,8 +135,8 @@ void Pixelate::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Pixelate::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Pixelate::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
@@ -181,7 +155,7 @@ void Pixelate::SetJsonValue(Json::Value root) {
}
// Get all properties for a specific frame
-std::string Pixelate::PropertiesJSON(int64_t requested_frame) {
+std::string Pixelate::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
diff --git a/src/effects/Saturation.cpp b/src/effects/Saturation.cpp
index 06bcb02c2..d5c295eb2 100644
--- a/src/effects/Saturation.cpp
+++ b/src/effects/Saturation.cpp
@@ -69,44 +69,36 @@ std::shared_ptr Saturation::GetFrame(std::shared_ptr frame, int64_
if (!frame_image)
return frame;
+ int pixel_count = frame_image->width() * frame_image->height();
+
// Get keyframe values for this frame
float saturation_value = saturation.GetValue(frame_number);
// Constants used for color saturation formula
- double pR = .299;
- double pG = .587;
- double pB = .114;
+ const double pR = .299;
+ const double pG = .587;
+ const double pB = .114;
// Loop through pixels
unsigned char *pixels = (unsigned char *) frame_image->bits();
- for (int pixel = 0, byte_index=0; pixel < frame_image->width() * frame_image->height(); pixel++, byte_index+=4)
+
+ #pragma omp parallel for shared (pixels)
+ for (int pixel = 0; pixel < pixel_count; ++pixel)
{
// Get the RGB values from the pixel
- int R = pixels[byte_index];
- int G = pixels[byte_index + 1];
- int B = pixels[byte_index + 2];
- int A = pixels[byte_index + 3];
+ int R = pixels[pixel * 4];
+ int G = pixels[pixel * 4 + 1];
+ int B = pixels[pixel * 4 + 2];
// Calculate the saturation multiplier
double p = sqrt( (R * R * pR) +
- (G * G * pG) +
- (B * B * pB) );
-
- // Adjust the saturation
- R = p + (R - p) * saturation_value;
- G = p + (G - p) * saturation_value;
- B = p + (B - p) * saturation_value;
-
- // Constrain the value from 0 to 255
- R = constrain(R);
- G = constrain(G);
- B = constrain(B);
-
- // Set all pixels to new value
- pixels[byte_index] = R;
- pixels[byte_index + 1] = G;
- pixels[byte_index + 2] = B;
- pixels[byte_index + 3] = A; // leave the alpha value alone
+ (G * G * pG) +
+ (B * B * pB) );
+
+ // Apply adjusted and constrained saturation
+ pixels[pixel * 4] = constrain(p + (R - p) * saturation_value);
+ pixels[pixel * 4 + 1] = constrain(p + (G - p) * saturation_value);
+ pixels[pixel * 4 + 2] = constrain(p + (B - p) * saturation_value);
}
// return the modified frame
@@ -114,14 +106,14 @@ std::shared_ptr Saturation::GetFrame(std::shared_ptr frame, int64_
}
// Generate JSON string of this object
-std::string Saturation::Json() {
+std::string Saturation::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Saturation::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Saturation::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
@@ -133,24 +125,12 @@ Json::Value Saturation::JsonValue() {
}
// Load JSON string into this object
-void Saturation::SetJson(std::string value) {
+void Saturation::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -161,8 +141,8 @@ void Saturation::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Saturation::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Saturation::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
@@ -173,7 +153,7 @@ void Saturation::SetJsonValue(Json::Value root) {
}
// Get all properties for a specific frame
-std::string Saturation::PropertiesJSON(int64_t requested_frame) {
+std::string Saturation::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
diff --git a/src/effects/Shift.cpp b/src/effects/Shift.cpp
index d0908fd88..ee5815912 100644
--- a/src/effects/Shift.cpp
+++ b/src/effects/Shift.cpp
@@ -69,9 +69,9 @@ std::shared_ptr Shift::GetFrame(std::shared_ptr frame, int64_t fra
// Get the current shift amount, and clamp to range (-1 to 1 range)
double x_shift = x.GetValue(frame_number);
- double x_shift_limit = fmod(abs(x_shift), 1.0);
+ double x_shift_limit = fmod(fabs(x_shift), 1.0);
double y_shift = y.GetValue(frame_number);
- double y_shift_limit = fmod(abs(y_shift), 1.0);
+ double y_shift_limit = fmod(fabs(y_shift), 1.0);
// Declare temp arrays to hold pixels while we move things around
unsigned char *temp_row = new unsigned char[frame_image->width() * 4]();
@@ -133,14 +133,14 @@ std::shared_ptr Shift::GetFrame(std::shared_ptr frame, int64_t fra
}
// Generate JSON string of this object
-std::string Shift::Json() {
+std::string Shift::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Shift::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Shift::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
@@ -153,24 +153,12 @@ Json::Value Shift::JsonValue() {
}
// Load JSON string into this object
-void Shift::SetJson(std::string value) {
+void Shift::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -181,8 +169,8 @@ void Shift::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Shift::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Shift::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
@@ -195,7 +183,7 @@ void Shift::SetJsonValue(Json::Value root) {
}
// Get all properties for a specific frame
-std::string Shift::PropertiesJSON(int64_t requested_frame) {
+std::string Shift::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
diff --git a/src/effects/Wave.cpp b/src/effects/Wave.cpp
index 2139e4ac8..499fc9588 100644
--- a/src/effects/Wave.cpp
+++ b/src/effects/Wave.cpp
@@ -68,15 +68,13 @@ std::shared_ptr Wave::GetFrame(std::shared_ptr frame, int64_t fram
// Get the frame's image
std::shared_ptr frame_image = frame->GetImage();
- // Get pixels for frame image
+ // Get original pixels for frame image, and also make a copy for editing
+ const unsigned char *original_pixels = (unsigned char *) frame_image->constBits();
unsigned char *pixels = (unsigned char *) frame_image->bits();
-
- // Make temp copy of pixels before we start changing them
- unsigned char *temp_image = new unsigned char[frame_image->width() * frame_image->height() * 4]();
- memcpy(temp_image, pixels, sizeof(char) * frame_image->width() * frame_image->height() * 4);
+ int pixel_count = frame_image->width() * frame_image->height();
// Get current keyframe values
- double time = frame_number;//abs(((frame_number + 255) % 510) - 255);
+ double time = frame_number;
double wavelength_value = wavelength.GetValue(frame_number);
double amplitude_value = amplitude.GetValue(frame_number);
double multiplier_value = multiplier.GetValue(frame_number);
@@ -84,43 +82,41 @@ std::shared_ptr Wave::GetFrame(std::shared_ptr frame, int64_t fram
double speed_y_value = speed_y.GetValue(frame_number);
// Loop through pixels
- for (int pixel = 0, byte_index=0; pixel < frame_image->width() * frame_image->height(); pixel++, byte_index+=4)
+ #pragma omp parallel for
+ for (int pixel = 0; pixel < pixel_count; ++pixel)
{
- // Calculate X and Y pixel coordinates
+ // Calculate pixel Y value
int Y = pixel / frame_image->width();
// Calculate wave pixel offsets
- float noiseVal = (100 + Y * 0.001) * multiplier_value; // Time and time multiplier (to make the wave move)
- float noiseAmp = noiseVal * amplitude_value; // Apply amplitude / height of the wave
- float waveformVal = sin((Y * wavelength_value) + (time * speed_y_value)); // Waveform algorithm on y-axis
- float waveVal = (waveformVal + shift_x_value) * noiseAmp; // Shifts pixels on the x-axis
+ float noiseVal = (100 + Y * 0.001) * multiplier_value; // Time and time multiplier (to make the wave move)
+ float noiseAmp = noiseVal * amplitude_value; // Apply amplitude / height of the wave
+ float waveformVal = sin((Y * wavelength_value) + (time * speed_y_value)); // Waveform algorithm on y-axis
+ float waveVal = (waveformVal + shift_x_value) * noiseAmp; // Shifts pixels on the x-axis
- int source_X = round(pixel + waveVal) * 4;
- if (source_X < 0)
- source_X = 0;
- if (source_X > frame_image->width() * frame_image->height() * 4 * sizeof(char))
- source_X = (frame_image->width() * frame_image->height() * 4 * sizeof(char)) - (sizeof(char) * 4);
+ long unsigned int source_px = round(pixel + waveVal);
+ if (source_px < 0)
+ source_px = 0;
+ if (source_px >= pixel_count)
+ source_px = pixel_count - 1;
// Calculate source array location, and target array location, and copy the 4 color values
- memcpy(&pixels[byte_index], &temp_image[source_X], sizeof(char) * 4);
+ memcpy(&pixels[pixel * 4], &original_pixels[source_px * 4], sizeof(char) * 4);
}
- // Delete arrays
- delete[] temp_image;
-
// return the modified frame
return frame;
}
// Generate JSON string of this object
-std::string Wave::Json() {
+std::string Wave::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
-// Generate Json::JsonValue for this object
-Json::Value Wave::JsonValue() {
+// Generate Json::Value for this object
+Json::Value Wave::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
@@ -136,24 +132,12 @@ Json::Value Wave::JsonValue() {
}
// Load JSON string into this object
-void Wave::SetJson(std::string value) {
+void Wave::SetJson(const std::string value) {
// Parse JSON string into JSON objects
- Json::Value root;
- Json::CharReaderBuilder rbuilder;
- Json::CharReader* reader(rbuilder.newCharReader());
-
- std::string errors;
- bool success = reader->parse( value.c_str(),
- value.c_str() + value.size(), &root, &errors );
- delete reader;
-
- if (!success)
- // Raise exception
- throw InvalidJSON("JSON could not be parsed (or is invalid)");
-
try
{
+ const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
@@ -164,8 +148,8 @@ void Wave::SetJson(std::string value) {
}
}
-// Load Json::JsonValue into this object
-void Wave::SetJsonValue(Json::Value root) {
+// Load Json::Value into this object
+void Wave::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
@@ -184,7 +168,7 @@ void Wave::SetJsonValue(Json::Value root) {
}
// Get all properties for a specific frame
-std::string Wave::PropertiesJSON(int64_t requested_frame) {
+std::string Wave::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index a104d766a..480dfb3d3 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -24,117 +24,116 @@
# along with OpenShot Library. If not, see .
################################################################################
-SET(TEST_MEDIA_PATH "${PROJECT_SOURCE_DIR}/src/examples/")
+# Test media path, used by unit tests for input data
+file(TO_NATIVE_PATH "${PROJECT_SOURCE_DIR}/src/examples/" TEST_MEDIA_PATH)
+add_definitions( -DTEST_MEDIA_PATH="${TEST_MEDIA_PATH}" )
################ WINDOWS ##################
# Set some compiler options for Windows
# required for libopenshot-audio headers
-IF (WIN32)
- STRING(REPLACE "/" "\\\\" TEST_MEDIA_PATH TEST_MEDIA_PATH)
+if(WIN32)
add_definitions( -DIGNORE_JUCE_HYPOT=1 )
- SET(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -include cmath")
-ENDIF(WIN32)
-
-add_definitions( -DTEST_MEDIA_PATH="${TEST_MEDIA_PATH}" )
+ set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -include cmath")
+endif()
################### UNITTEST++ #####################
# Find UnitTest++ libraries (used for unit testing)
-FIND_PACKAGE(UnitTest++ REQUIRED)
+find_package(UnitTest++)
+
+if (NOT UnitTest++_FOUND)
+ set(TESTS_ENABLED OFF PARENT_SCOPE)
+ return()
+endif()
# Include UnitTest++ headers (needed for compile)
-include_directories(${UNITTEST++_INCLUDE_DIR})
+include_directories(${UnitTest++_INCLUDE_DIRS})
+
+set_package_properties(UnitTest++ PROPERTIES
+ TYPE RECOMMENDED
+ PURPOSE "Unit testing framework")
################ IMAGE MAGICK ##################
# Set the Quantum Depth that ImageMagick was built with (default to 16 bits)
-IF (MAGICKCORE_QUANTUM_DEPTH)
+if(MAGICKCORE_QUANTUM_DEPTH)
add_definitions( -DMAGICKCORE_QUANTUM_DEPTH=${MAGICKCORE_QUANTUM_DEPTH} )
-ELSE (MAGICKCORE_QUANTUM_DEPTH)
+else()
add_definitions( -DMAGICKCORE_QUANTUM_DEPTH=16 )
-ENDIF (MAGICKCORE_QUANTUM_DEPTH)
-IF (MAGICKCORE_HDRI_ENABLE)
+endif()
+
+if(MAGICKCORE_HDRI_ENABLE)
add_definitions( -DMAGICKCORE_HDRI_ENABLE=${MAGICKCORE_HDRI_ENABLE} )
-ELSE (MAGICKCORE_HDRI_ENABLE)
+else()
add_definitions( -DMAGICKCORE_HDRI_ENABLE=0 )
-ENDIF (MAGICKCORE_HDRI_ENABLE)
-IF (OPENSHOT_IMAGEMAGICK_COMPATIBILITY)
+endif()
+
+if(OPENSHOT_IMAGEMAGICK_COMPATIBILITY)
add_definitions( -DOPENSHOT_IMAGEMAGICK_COMPATIBILITY=${OPENSHOT_IMAGEMAGICK_COMPATIBILITY} )
-ELSE (OPENSHOT_IMAGEMAGICK_COMPATIBILITY)
+else()
add_definitions( -DOPENSHOT_IMAGEMAGICK_COMPATIBILITY=0 )
-ENDIF (OPENSHOT_IMAGEMAGICK_COMPATIBILITY)
+endif()
# Find the ImageMagick++ library
-FIND_PACKAGE(ImageMagick COMPONENTS Magick++ MagickWand MagickCore)
-IF (ImageMagick_FOUND)
+find_package(ImageMagick COMPONENTS Magick++ MagickWand MagickCore)
+if(ImageMagick_FOUND)
# Include ImageMagick++ headers (needed for compile)
include_directories(${ImageMagick_INCLUDE_DIRS})
# define a global var (used in the C++)
add_definitions( -DUSE_IMAGEMAGICK=1 )
- SET(CMAKE_SWIG_FLAGS "-DUSE_IMAGEMAGICK=1")
-
-ENDIF (ImageMagick_FOUND)
+ set(CMAKE_SWIG_FLAGS "-DUSE_IMAGEMAGICK=1")
+endif()
################# LIBOPENSHOT-AUDIO ###################
# Find JUCE-based openshot Audio libraries
-FIND_PACKAGE(OpenShotAudio 0.1.8 REQUIRED)
+find_package(OpenShotAudio 0.2.0 REQUIRED)
# Include Juce headers (needed for compile)
include_directories(${LIBOPENSHOT_AUDIO_INCLUDE_DIRS})
################# BLACKMAGIC DECKLINK ###################
-IF (ENABLE_BLACKMAGIC)
+if(ENABLE_BLACKMAGIC)
# Find BlackMagic DeckLinkAPI libraries
- FIND_PACKAGE(BlackMagic)
+ find_package(BlackMagic)
- IF (BLACKMAGIC_FOUND)
+ if(BLACKMAGIC_FOUND)
# Include Blackmagic headers (needed for compile)
include_directories(${BLACKMAGIC_INCLUDE_DIR})
- ENDIF (BLACKMAGIC_FOUND)
-ENDIF (ENABLE_BLACKMAGIC)
-
-
-################### RESVG #####################
-# Find resvg library (used for rendering svg files)
-FIND_PACKAGE(RESVG)
-
-# Include resvg headers (optional SVG library)
-if (RESVG_FOUND)
- include_directories(${RESVG_INCLUDE_DIRS})
-endif(RESVG_FOUND)
+ endif()
+endif()
############### SET TEST SOURCE FILES #################
-SET ( OPENSHOT_TEST_FILES
- Cache_Tests.cpp
- Clip_Tests.cpp
- Color_Tests.cpp
- Coordinate_Tests.cpp
- ReaderBase_Tests.cpp
- ImageWriter_Tests.cpp
- FFmpegReader_Tests.cpp
- FFmpegWriter_Tests.cpp
- Fraction_Tests.cpp
- FrameMapper_Tests.cpp
- KeyFrame_Tests.cpp
- Point_Tests.cpp
- Settings_Tests.cpp
- Timeline_Tests.cpp )
+set(OPENSHOT_TEST_FILES
+ Cache_Tests.cpp
+ Clip_Tests.cpp
+ Color_Tests.cpp
+ Coordinate_Tests.cpp
+ ReaderBase_Tests.cpp
+ ImageWriter_Tests.cpp
+ FFmpegReader_Tests.cpp
+ FFmpegWriter_Tests.cpp
+ Fraction_Tests.cpp
+ Frame_Tests.cpp
+ FrameMapper_Tests.cpp
+ KeyFrame_Tests.cpp
+ Point_Tests.cpp
+ Settings_Tests.cpp
+ Timeline_Tests.cpp )
################ TESTER EXECUTABLE #################
# Create unit test executable (openshot-test)
message (STATUS "Tests enabled, test executable will be built as tests/openshot-test")
add_executable(openshot-test
- tests.cpp
- ${OPENSHOT_TEST_FILES} )
+ tests.cpp
+ ${OPENSHOT_TEST_FILES} )
# Link libraries to the new executable
-target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY})
+target_link_libraries(openshot-test openshot ${UnitTest++_LIBRARIES})
##### RUNNING TESTS (make os_test / make test) #####
# Hook up the 'make os_test' target to the 'openshot-test' executable
-ADD_CUSTOM_TARGET(os_test COMMAND openshot-test)
-list(APPEND OS_TEST_CMDS "'make os_test'")
+add_custom_target(os_test COMMAND openshot-test)
# Also hook up 'make test', if possible
# This requires CMake 3.11+, where the CMP0037 policy
@@ -146,8 +145,8 @@ endif()
if (CMAKE_VERSION VERSION_GREATER 3.11)
message(STATUS "Cmake 3.11+ detected, enabling 'test' target")
add_custom_target(test COMMAND openshot-test)
- list(APPEND OS_TEST_CMDS " or " "'make test'")
+ set(TEST_TARGET_NAME "test")
+else()
+ set(TEST_TARGET_NAME "os_test")
endif()
-
-string(CONCAT t ${OS_TEST_CMDS})
-message("\nTo run unit tests, use: ${t}")
+add_feature_info("Testrunner" ENABLE_TESTS "Run unit tests with 'make ${TEST_TARGET_NAME}'")
diff --git a/tests/Cache_Tests.cpp b/tests/Cache_Tests.cpp
index ea5b45ce4..ddf698f54 100644
--- a/tests/Cache_Tests.cpp
+++ b/tests/Cache_Tests.cpp
@@ -395,31 +395,31 @@ TEST(CacheDisk_JSON)
// Add some frames (out of order)
std::shared_ptr f3(new Frame(3, 1280, 720, "Blue", 500, 2));
c.Add(f3);
- CHECK_EQUAL(1, c.JsonValue()["ranges"].size());
+ CHECK_EQUAL(1, (int)c.JsonValue()["ranges"].size());
CHECK_EQUAL("1", c.JsonValue()["version"].asString());
// Add some frames (out of order)
std::shared_ptr f1(new Frame(1, 1280, 720, "Blue", 500, 2));
c.Add(f1);
- CHECK_EQUAL(2, c.JsonValue()["ranges"].size());
+ CHECK_EQUAL(2, (int)c.JsonValue()["ranges"].size());
CHECK_EQUAL("2", c.JsonValue()["version"].asString());
// Add some frames (out of order)
std::shared_ptr f2(new Frame(2, 1280, 720, "Blue", 500, 2));
c.Add(f2);
- CHECK_EQUAL(1, c.JsonValue()["ranges"].size());
+ CHECK_EQUAL(1, (int)c.JsonValue()["ranges"].size());
CHECK_EQUAL("3", c.JsonValue()["version"].asString());
// Add some frames (out of order)
std::shared_ptr f5(new Frame(5, 1280, 720, "Blue", 500, 2));
c.Add(f5);
- CHECK_EQUAL(2, c.JsonValue()["ranges"].size());
+ CHECK_EQUAL(2, (int)c.JsonValue()["ranges"].size());
CHECK_EQUAL("4", c.JsonValue()["version"].asString());
// Add some frames (out of order)
std::shared_ptr f4(new Frame(4, 1280, 720, "Blue", 500, 2));
c.Add(f4);
- CHECK_EQUAL(1, c.JsonValue()["ranges"].size());
+ CHECK_EQUAL(1, (int)c.JsonValue()["ranges"].size());
CHECK_EQUAL("5", c.JsonValue()["version"].asString());
// Delete cache directory
@@ -435,31 +435,31 @@ TEST(CacheMemory_JSON)
// Add some frames (out of order)
std::shared_ptr f3(new Frame(3, 1280, 720, "Blue", 500, 2));
c.Add(f3);
- CHECK_EQUAL(1, c.JsonValue()["ranges"].size());
+ CHECK_EQUAL(1, (int)c.JsonValue()["ranges"].size());
CHECK_EQUAL("1", c.JsonValue()["version"].asString());
// Add some frames (out of order)
std::shared_ptr f1(new Frame(1, 1280, 720, "Blue", 500, 2));
c.Add(f1);
- CHECK_EQUAL(2, c.JsonValue()["ranges"].size());
+ CHECK_EQUAL(2, (int)c.JsonValue()["ranges"].size());
CHECK_EQUAL("2", c.JsonValue()["version"].asString());
// Add some frames (out of order)
std::shared_ptr f2(new Frame(2, 1280, 720, "Blue", 500, 2));
c.Add(f2);
- CHECK_EQUAL(1, c.JsonValue()["ranges"].size());
+ CHECK_EQUAL(1, (int)c.JsonValue()["ranges"].size());
CHECK_EQUAL("3", c.JsonValue()["version"].asString());
// Add some frames (out of order)
std::shared_ptr f5(new Frame(5, 1280, 720, "Blue", 500, 2));
c.Add(f5);
- CHECK_EQUAL(2, c.JsonValue()["ranges"].size());
+ CHECK_EQUAL(2, (int)c.JsonValue()["ranges"].size());
CHECK_EQUAL("4", c.JsonValue()["version"].asString());
// Add some frames (out of order)
std::shared_ptr f4(new Frame(4, 1280, 720, "Blue", 500, 2));
c.Add(f4);
- CHECK_EQUAL(1, c.JsonValue()["ranges"].size());
+ CHECK_EQUAL(1, (int)c.JsonValue()["ranges"].size());
CHECK_EQUAL("5", c.JsonValue()["version"].asString());
}
diff --git a/tests/Clip_Tests.cpp b/tests/Clip_Tests.cpp
index 711fef03c..c66cc9a48 100644
--- a/tests/Clip_Tests.cpp
+++ b/tests/Clip_Tests.cpp
@@ -241,7 +241,7 @@ TEST(Clip_Effects)
CHECK_EQUAL(255, (int)pixels[pixel_index + 3]);
// Check the # of Effects
- CHECK_EQUAL(1, c10.Effects().size());
+ CHECK_EQUAL(1, (int)c10.Effects().size());
// Add a 2nd negate effect
@@ -262,5 +262,5 @@ TEST(Clip_Effects)
CHECK_EQUAL(255, (int)pixels[pixel_index + 3]);
// Check the # of Effects
- CHECK_EQUAL(2, c10.Effects().size());
+ CHECK_EQUAL(2, (int)c10.Effects().size());
}
diff --git a/tests/FFmpegWriter_Tests.cpp b/tests/FFmpegWriter_Tests.cpp
index 21940b1b3..cb75a118a 100644
--- a/tests/FFmpegWriter_Tests.cpp
+++ b/tests/FFmpegWriter_Tests.cpp
@@ -36,7 +36,8 @@
using namespace std;
using namespace openshot;
-TEST(FFmpegWriter_Test_Webm)
+SUITE(FFMpegWriter) {
+TEST(Webm)
{
// Reader
stringstream path;
@@ -82,3 +83,46 @@ TEST(FFmpegWriter_Test_Webm)
CHECK_CLOSE(23, (int)pixels[pixel_index + 2], 5);
CHECK_CLOSE(255, (int)pixels[pixel_index + 3], 5);
}
+
+TEST(Options_Overloads)
+{
+ // Reader
+ stringstream path;
+ path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4";
+ FFmpegReader r(path.str());
+ r.Open();
+
+ /* WRITER ---------------- */
+ FFmpegWriter w("output1.mp4");
+
+ // Set options
+ w.SetAudioOptions("aac", 48000, 192000);
+ w.SetVideoOptions("libx264", 1280, 720, Fraction(30,1), 5000000);
+
+ // Open writer
+ w.Open();
+
+ // Write some frames
+ w.WriteFrame(&r, 24, 50);
+
+ // Close writer & reader
+ w.Close();
+ r.Close();
+
+ FFmpegReader r1("output1.mp4");
+ r1.Open();
+
+ // Verify implied settings
+ CHECK_EQUAL(true, r1.info.has_audio);
+ CHECK_EQUAL(true, r1.info.has_video);
+
+ CHECK_EQUAL(2, r1.GetFrame(1)->GetAudioChannelsCount());
+ CHECK_EQUAL(LAYOUT_STEREO, r1.info.channel_layout);
+
+ CHECK_EQUAL(1, r1.info.pixel_ratio.num);
+ CHECK_EQUAL(1, r1.info.pixel_ratio.den);
+ CHECK_EQUAL(false, r1.info.interlaced_frame);
+ CHECK_EQUAL(true, r1.info.top_field_first);
+}
+
+} // SUITE()
diff --git a/tests/Frame_Tests.cpp b/tests/Frame_Tests.cpp
new file mode 100644
index 000000000..a92906a3d
--- /dev/null
+++ b/tests/Frame_Tests.cpp
@@ -0,0 +1,150 @@
+/**
+ * @file
+ * @brief Unit tests for openshot::Frame
+ * @author Jonathan Thomas
+ * @author FeRD (Frank Dana)
+ *
+ * @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"
+
+#include
+
+using namespace openshot;
+
+SUITE(Frame_Tests)
+{
+
+TEST(Default_Constructor)
+{
+ // Create a "blank" default Frame
+ std::shared_ptr f1(new Frame());
+
+ CHECK(f1 != nullptr); // Test aborts here if we didn't get a Frame
+
+ // Check basic default parameters
+ CHECK_EQUAL(1, f1->GetHeight());
+ CHECK_EQUAL(1, f1->GetWidth());
+ CHECK_EQUAL(44100, f1->SampleRate());
+ CHECK_EQUAL(2, f1->GetAudioChannelsCount());
+
+ // Should be false until we load or create contents
+ CHECK_EQUAL(false, f1->has_image_data);
+ CHECK_EQUAL(false, f1->has_audio_data);
+
+ // Calling GetImage() paints a blank frame, by default
+ std::shared_ptr i1 = f1->GetImage();
+
+ CHECK(i1 != nullptr);
+
+ CHECK_EQUAL(true,f1->has_image_data);
+ CHECK_EQUAL(false,f1->has_audio_data);
+}
+
+
+TEST(Data_Access)
+{
+ // Create a video clip
+ std::stringstream path;
+ path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4";
+ Clip c1(path.str());
+ c1.Open();
+
+ // Get first frame
+ std::shared_ptr f1 = c1.GetFrame(1);
+
+ CHECK(f1 != nullptr);
+
+ CHECK_EQUAL(1, f1->number);
+ CHECK_EQUAL(1280, f1->GetWidth());
+ CHECK_EQUAL(720, f1->GetHeight());
+}
+
+
+TEST(AddImage_QImage)
+{
+ // Create a "blank" default Frame
+ std::shared_ptr f1(new Frame());
+
+ // Load an image
+ std::stringstream path;
+ path << TEST_MEDIA_PATH << "front.png";
+ std::shared_ptr i1(new QImage(QString::fromStdString(path.str()))) ;
+
+ CHECK(f1 != nullptr); // Test aborts here if we didn't get a Frame
+ CHECK_EQUAL(false, i1->isNull());
+
+ f1->AddImage(i1);
+
+ // Check loaded image parameters
+ CHECK_EQUAL(i1->height(), f1->GetHeight());
+ CHECK_EQUAL(i1->width(), f1->GetWidth());
+ CHECK_EQUAL(true, f1->has_image_data);
+}
+
+
+TEST(Copy_Constructor)
+{
+ // Create a dummy Frame
+ openshot::Frame f1(1, 800, 600, "#000000");
+
+ // Load an image
+ std::stringstream path;
+ path << TEST_MEDIA_PATH << "front.png";
+ std::shared_ptr i1( new QImage(QString::fromStdString(path.str())) );
+
+ CHECK_EQUAL(false, i1->isNull());
+
+ // Add image to f1, then copy f1 to f2
+ f1.AddImage(i1);
+
+ Frame f2 = f1;
+
+ CHECK_EQUAL(f1.GetHeight(), f2.GetHeight());
+ CHECK_EQUAL(f1.GetWidth(), f2.GetWidth());
+
+ CHECK_EQUAL(f1.has_image_data, f2.has_image_data);
+ CHECK_EQUAL(f1.has_audio_data, f2.has_audio_data);
+
+ Fraction par1 = f1.GetPixelRatio();
+ Fraction par2 = f2.GetPixelRatio();
+
+ CHECK_EQUAL(par1.num, par2.num);
+ CHECK_EQUAL(par1.den, par2.den);
+
+
+ CHECK_EQUAL(f1.SampleRate(), f2.SampleRate());
+ CHECK_EQUAL(f1.GetAudioChannelsCount(), f2.GetAudioChannelsCount());
+ CHECK_EQUAL(f1.ChannelsLayout(), f2.ChannelsLayout());
+
+ CHECK_EQUAL(f1.GetBytes(), f2.GetBytes());
+ CHECK_EQUAL(f1.GetAudioSamplesCount(), f2.GetAudioSamplesCount());
+}
+
+} // SUITE(Frame_Tests)
diff --git a/tests/ReaderBase_Tests.cpp b/tests/ReaderBase_Tests.cpp
index 8ac283218..776529d3c 100644
--- a/tests/ReaderBase_Tests.cpp
+++ b/tests/ReaderBase_Tests.cpp
@@ -49,9 +49,9 @@ TEST(ReaderBase_Derived_Class)
std::shared_ptr GetFrame(int64_t number) { std::shared_ptr f(new Frame()); return f; }
void Close() { };
void Open() { };
- string Json() { return NULL; };
+ string Json() const { return ""; };
void SetJson(string value) { };
- Json::Value JsonValue() { return (int) NULL; };
+ Json::Value JsonValue() const { return Json::Value("{}"); };
void SetJsonValue(Json::Value root) { };
bool IsOpen() { return true; };
string Name() { return "TestReader"; };
@@ -60,6 +60,23 @@ TEST(ReaderBase_Derived_Class)
// Create an instance of the derived class
TestReader t1;
+ // Validate the new class
+ CHECK_EQUAL("TestReader", t1.Name());
+
+ t1.Close();
+ t1.Open();
+ CHECK_EQUAL(true, t1.IsOpen());
+
+ CHECK_EQUAL(true, t1.GetCache() == NULL);
+
+ t1.SetJson("{ }");
+ t1.SetJsonValue(Json::Value("{}"));
+ CHECK_EQUAL("", t1.Json());
+ auto json = t1.JsonValue();
+ CHECK_EQUAL(json, Json::Value("{}"));
+
+ auto f = t1.GetFrame(1);
+
// Check some of the default values of the FileInfo struct on the base class
CHECK_EQUAL(false, t1.info.has_audio);
CHECK_EQUAL(false, t1.info.has_audio);