diff --git a/.travis.yml b/.travis.yml index 2e7db59d..8c3c64d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,53 +1,88 @@ -dist: xenial -sudo: required +language: cpp + +# This section uses a rather esoteric (and tricky!) feature of YAML, +# &aliases and *anchors, to build package lists out of sublists without +# repeating their contents. Basically, '&name' creates an alias for the +# given data, which can then be referenced using the anchor '*name'. +addons: + apt: + packages: &p_common # Packages common to all Ubuntu builds + - cmake + - swig + - libopenshot-audio-dev + - libmagick++-dev + - libunittest++-dev + - libzmq3-dev + - qtbase5-dev + - qtmultimedia5-dev + - doxygen + - graphviz + packages: &ff_common # Common set of FFmpeg packages + - *p_common + - libfdk-aac-dev + - libavcodec-dev + - libavformat-dev + - libavdevice-dev + - libavutil-dev + - libavfilter-dev + - libswscale-dev + - libpostproc-dev + - libavresample-dev + - libswresample-dev matrix: include: - - language: cpp - name: "FFmpeg 2" - before_script: - - sudo add-apt-repository ppa:openshot.developers/libopenshot-daily -y - - sudo add-apt-repository ppa:beineri/opt-qt-5.10.0-xenial -y - - sudo apt-get update -qq - - sudo apt-get install gcc-4.8 cmake libavcodec-dev libavformat-dev libswscale-dev libavresample-dev libavutil-dev libopenshot-audio-dev libopenshot-dev libfdk-aac-dev libfdk-aac-dev libjsoncpp-dev libmagick++-dev libopenshot-audio-dev libunittest++-dev libzmq3-dev pkg-config python3-dev qtbase5-dev qtmultimedia5-dev swig -y - - sudo apt autoremove -y - script: - - mkdir -p build; cd build; - - cmake -D"CMAKE_BUILD_TYPE:STRING=Debug" ../ - - make VERBOSE=1 - - make os_test - - make install DESTDIR=dist/ - - - language: cpp - name: "FFmpeg 3" - before_script: - - sudo add-apt-repository ppa:openshot.developers/libopenshot-daily -y - - sudo add-apt-repository ppa:beineri/opt-qt-5.10.0-xenial -y - - sudo add-apt-repository ppa:jonathonf/ffmpeg-3 -y - - sudo apt-get update -qq - - sudo apt-get install gcc-4.8 cmake libavcodec-dev libavformat-dev libswscale-dev libavresample-dev libavutil-dev libopenshot-audio-dev libopenshot-dev libfdk-aac-dev libfdk-aac-dev libjsoncpp-dev libmagick++-dev libopenshot-audio-dev libunittest++-dev libzmq3-dev pkg-config python3-dev qtbase5-dev qtmultimedia5-dev swig -y - - sudo apt autoremove -y - script: - - mkdir -p build; cd build; - - cmake -D"CMAKE_BUILD_TYPE:STRING=Debug" ../ - - make VERBOSE=1 - - make os_test - - make install DESTDIR=dist/ - - - language: cpp - name: "FFmpeg 4" - before_script: - - sudo add-apt-repository ppa:openshot.developers/libopenshot-daily -y - - sudo add-apt-repository ppa:beineri/opt-qt-5.10.0-xenial -y - - sudo add-apt-repository ppa:jonathonf/ffmpeg -y - - sudo add-apt-repository ppa:jonathonf/ffmpeg-4 -y - - sudo add-apt-repository ppa:jonathonf/backports -y - - sudo apt-get update -qq - - sudo apt-get install gcc-4.8 cmake libavcodec58 libavformat58 libavcodec-dev libavformat-dev libswscale-dev libavresample-dev libavutil-dev libopenshot-audio-dev libopenshot-dev libfdk-aac-dev libfdk-aac-dev libjsoncpp-dev libmagick++-dev libopenshot-audio-dev libunittest++-dev libzmq3-dev pkg-config python3-dev qtbase5-dev qtmultimedia5-dev swig -y - - sudo apt autoremove -y - script: - - mkdir -p build; cd build; - - cmake -D"CMAKE_BUILD_TYPE:STRING=Debug" ../ - - make VERBOSE=1 - - make os_test - - make install DESTDIR=dist/ + - name: "FFmpeg 2 (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 (Ubuntu 18.04 Bionic)" + env: BUILD_VERSION=ffmpeg3 + os: linux + dist: bionic + addons: + apt: + sources: + - sourceline: 'ppa:openshot.developers/libopenshot-daily' + - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic' + packages: + - *ff_common + - qt5-default + + - name: "FFmpeg 4 (Ubuntu 18.04 Bionic)" + env: BUILD_VERSION=ffmpeg4 + os: linux + dist: bionic + addons: + apt: + sources: + - sourceline: 'ppa:openshot.developers/libopenshot-daily' + - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic' + - sourceline: 'ppa:jonathonf/ffmpeg-4' + packages: + - *ff_common + - qt5-default + - libavcodec58 + - libavformat58 + - libavdevice58 + - libavutil56 + - libavfilter7 + - libswscale5 + - libpostproc55 + - libavresample4 + - libswresample3 + +script: + - mkdir -p build; cd build; + - cmake -DCMAKE_BUILD_TYPE:STRING="Debug" ../ + - make VERBOSE=1 + - make os_test + - make install DESTDIR="$BUILD_VERSION" diff --git a/CMakeLists.txt b/CMakeLists.txt index 24d3e19d..0809c04d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,14 +92,18 @@ ENDIF(WIN32) set(QT_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include/Qt) FILE(GLOB QT_HEADER_FILES "${QT_HEADER_DIR}/*.h") -############## PROCESS SUB-DIRECTORIES ############## +############## PROCESS src/ DIRECTORIES ############## add_subdirectory(src) -add_subdirectory(tests) ################### 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)\")") @@ -108,3 +112,8 @@ 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() + +############# PROCESS tests/ DIRECTORY ############## +add_subdirectory(tests) + diff --git a/cmake/Modules/FindPythonLibs.cmake b/cmake/Modules/FindPythonLibs.cmake deleted file mode 100644 index e2ca1c79..00000000 --- a/cmake/Modules/FindPythonLibs.cmake +++ /dev/null @@ -1,294 +0,0 @@ -#.rst: -# FindPythonLibs -# -------------- -# -# Find python libraries -# -# This module finds if Python is installed and determines where the -# include files and libraries are. It also determines what the name of -# the library is. This code sets the following variables: -# -# :: -# -# PYTHONLIBS_FOUND - have the Python libs been found -# PYTHON_LIBRARIES - path to the python library -# PYTHON_INCLUDE_PATH - path to where Python.h is found (deprecated) -# PYTHON_INCLUDE_DIRS - path to where Python.h is found -# PYTHON_DEBUG_LIBRARIES - path to the debug library (deprecated) -# PYTHONLIBS_VERSION_STRING - version of the Python libs found (since CMake 2.8.8) -# -# -# -# The Python_ADDITIONAL_VERSIONS variable can be used to specify a list -# of version numbers that should be taken into account when searching -# for Python. You need to set this variable before calling -# find_package(PythonLibs). -# -# If you'd like to specify the installation of Python to use, you should -# modify the following cache variables: -# -# :: -# -# PYTHON_LIBRARY - path to the python library -# PYTHON_INCLUDE_DIR - path to where Python.h is found -# -# If also calling find_package(PythonInterp), call find_package(PythonInterp) -# first to get the currently active Python version by default with a consistent -# version of PYTHON_LIBRARIES. - -#============================================================================= -# Copyright 2001-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -include(CMakeFindFrameworks) -# Search for the python framework on Apple. -CMAKE_FIND_FRAMEWORKS(Python) - -set(_PYTHON1_VERSIONS 1.6 1.5) -set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0) -set(_PYTHON3_VERSIONS 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0) - -if(PythonLibs_FIND_VERSION) - if(PythonLibs_FIND_VERSION_COUNT GREATER 1) - set(_PYTHON_FIND_MAJ_MIN "${PythonLibs_FIND_VERSION_MAJOR}.${PythonLibs_FIND_VERSION_MINOR}") - unset(_PYTHON_FIND_OTHER_VERSIONS) - if(PythonLibs_FIND_VERSION_EXACT) - if(_PYTHON_FIND_MAJ_MIN STREQUAL PythonLibs_FIND_VERSION) - set(_PYTHON_FIND_OTHER_VERSIONS "${PythonLibs_FIND_VERSION}") - else() - set(_PYTHON_FIND_OTHER_VERSIONS "${PythonLibs_FIND_VERSION}" "${_PYTHON_FIND_MAJ_MIN}") - endif() - else() - foreach(_PYTHON_V ${_PYTHON${PythonLibs_FIND_VERSION_MAJOR}_VERSIONS}) - if(NOT _PYTHON_V VERSION_LESS _PYTHON_FIND_MAJ_MIN) - list(APPEND _PYTHON_FIND_OTHER_VERSIONS ${_PYTHON_V}) - endif() - endforeach() - endif() - unset(_PYTHON_FIND_MAJ_MIN) - else() - set(_PYTHON_FIND_OTHER_VERSIONS ${_PYTHON${PythonLibs_FIND_VERSION_MAJOR}_VERSIONS}) - endif() -else() - set(_PYTHON_FIND_OTHER_VERSIONS ${_PYTHON3_VERSIONS} ${_PYTHON2_VERSIONS} ${_PYTHON1_VERSIONS}) -endif() - -# Set up the versions we know about, in the order we will search. Always add -# the user supplied additional versions to the front. -# If FindPythonInterp has already found the major and minor version, -# insert that version between the user supplied versions and the stock -# version list. -set(_Python_VERSIONS ${Python_ADDITIONAL_VERSIONS}) -if(DEFINED PYTHON_VERSION_MAJOR AND DEFINED PYTHON_VERSION_MINOR) - list(APPEND _Python_VERSIONS ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}) -endif() -list(APPEND _Python_VERSIONS ${_PYTHON_FIND_OTHER_VERSIONS}) - -unset(_PYTHON_FIND_OTHER_VERSIONS) -unset(_PYTHON1_VERSIONS) -unset(_PYTHON2_VERSIONS) -unset(_PYTHON3_VERSIONS) - -foreach(_CURRENT_VERSION ${_Python_VERSIONS}) - string(REPLACE "." "" _CURRENT_VERSION_NO_DOTS ${_CURRENT_VERSION}) - if(WIN32) - find_library(PYTHON_DEBUG_LIBRARY - NAMES python${_CURRENT_VERSION_NO_DOTS}_d python - PATHS - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs/Debug - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs/Debug - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs - ) - endif() - - find_library(PYTHON_LIBRARY - NAMES - python${_CURRENT_VERSION_NO_DOTS} - python${_CURRENT_VERSION}mu - python${_CURRENT_VERSION}m - python${_CURRENT_VERSION}u - python${_CURRENT_VERSION} - PATHS - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs - # Avoid finding the .dll in the PATH. We want the .lib. - NO_SYSTEM_ENVIRONMENT_PATH - ) - # Look for the static library in the Python config directory - find_library(PYTHON_LIBRARY - NAMES python${_CURRENT_VERSION_NO_DOTS} python${_CURRENT_VERSION} - # Avoid finding the .dll in the PATH. We want the .lib. - NO_SYSTEM_ENVIRONMENT_PATH - # This is where the static library is usually located - PATH_SUFFIXES python${_CURRENT_VERSION}/config - ) - - # For backward compatibility, honour value of PYTHON_INCLUDE_PATH, if - # PYTHON_INCLUDE_DIR is not set. - if(DEFINED PYTHON_INCLUDE_PATH AND NOT DEFINED PYTHON_INCLUDE_DIR) - set(PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_PATH}" CACHE PATH - "Path to where Python.h is found" FORCE) - endif() - - set(PYTHON_FRAMEWORK_INCLUDES) - if(Python_FRAMEWORKS AND NOT PYTHON_INCLUDE_DIR) - foreach(dir ${Python_FRAMEWORKS}) - set(PYTHON_FRAMEWORK_INCLUDES ${PYTHON_FRAMEWORK_INCLUDES} - ${dir}/Versions/${_CURRENT_VERSION}/include/python${_CURRENT_VERSION}) - endforeach() - endif() - - find_path(PYTHON_INCLUDE_DIR - NAMES Python.h - PATHS - ${PYTHON_FRAMEWORK_INCLUDES} - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/include - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/include - PATH_SUFFIXES - python${_CURRENT_VERSION}mu - python${_CURRENT_VERSION}m - python${_CURRENT_VERSION}u - python${_CURRENT_VERSION} - ) - - # For backward compatibility, set PYTHON_INCLUDE_PATH. - set(PYTHON_INCLUDE_PATH "${PYTHON_INCLUDE_DIR}") - - if(PYTHON_INCLUDE_DIR AND EXISTS "${PYTHON_INCLUDE_DIR}/patchlevel.h") - file(STRINGS "${PYTHON_INCLUDE_DIR}/patchlevel.h" python_version_str - REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"") - string(REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"]+)\".*" "\\1" - PYTHONLIBS_VERSION_STRING "${python_version_str}") - unset(python_version_str) - endif() - - if(PYTHON_LIBRARY AND PYTHON_INCLUDE_DIR) - break() - endif() -endforeach() - -mark_as_advanced( - PYTHON_DEBUG_LIBRARY - PYTHON_LIBRARY - PYTHON_INCLUDE_DIR -) - -# We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the -# cache entries because they are meant to specify the location of a single -# library. We now set the variables listed by the documentation for this -# module. -set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") -set(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}") - -# These variables have been historically named in this module different from -# what SELECT_LIBRARY_CONFIGURATIONS() expects. -set(PYTHON_LIBRARY_DEBUG "${PYTHON_DEBUG_LIBRARY}") -set(PYTHON_LIBRARY_RELEASE "${PYTHON_LIBRARY}") -include(SelectLibraryConfigurations) -SELECT_LIBRARY_CONFIGURATIONS(PYTHON) -# SELECT_LIBRARY_CONFIGURATIONS() sets ${PREFIX}_FOUND if it has a library. -# Unset this, this prefix doesn't match the module prefix, they are different -# for historical reasons. -unset(PYTHON_FOUND) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(PythonLibs - REQUIRED_VARS PYTHON_LIBRARIES PYTHON_INCLUDE_DIRS - VERSION_VAR PYTHONLIBS_VERSION_STRING) - -# PYTHON_ADD_MODULE( src1 src2 ... srcN) is used to build modules for python. -# PYTHON_WRITE_MODULES_HEADER() writes a header file you can include -# in your sources to initialize the static python modules -function(PYTHON_ADD_MODULE _NAME ) - get_property(_TARGET_SUPPORTS_SHARED_LIBS - GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) - option(PYTHON_ENABLE_MODULE_${_NAME} "Add module ${_NAME}" TRUE) - option(PYTHON_MODULE_${_NAME}_BUILD_SHARED - "Add module ${_NAME} shared" ${_TARGET_SUPPORTS_SHARED_LIBS}) - - # Mark these options as advanced - mark_as_advanced(PYTHON_ENABLE_MODULE_${_NAME} - PYTHON_MODULE_${_NAME}_BUILD_SHARED) - - if(PYTHON_ENABLE_MODULE_${_NAME}) - if(PYTHON_MODULE_${_NAME}_BUILD_SHARED) - set(PY_MODULE_TYPE MODULE) - else() - set(PY_MODULE_TYPE STATIC) - set_property(GLOBAL APPEND PROPERTY PY_STATIC_MODULES_LIST ${_NAME}) - endif() - - set_property(GLOBAL APPEND PROPERTY PY_MODULES_LIST ${_NAME}) - add_library(${_NAME} ${PY_MODULE_TYPE} ${ARGN}) -# target_link_libraries(${_NAME} ${PYTHON_LIBRARIES}) - - if(PYTHON_MODULE_${_NAME}_BUILD_SHARED) - set_target_properties(${_NAME} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}") - if(WIN32 AND NOT CYGWIN) - set_target_properties(${_NAME} PROPERTIES SUFFIX ".pyd") - endif() - endif() - - endif() -endfunction() - -function(PYTHON_WRITE_MODULES_HEADER _filename) - - get_property(PY_STATIC_MODULES_LIST GLOBAL PROPERTY PY_STATIC_MODULES_LIST) - - get_filename_component(_name "${_filename}" NAME) - string(REPLACE "." "_" _name "${_name}") - string(TOUPPER ${_name} _nameUpper) - set(_filename ${CMAKE_CURRENT_BINARY_DIR}/${_filename}) - - set(_filenameTmp "${_filename}.in") - file(WRITE ${_filenameTmp} "/*Created by cmake, do not edit, changes will be lost*/\n") - file(APPEND ${_filenameTmp} -"#ifndef ${_nameUpper} -#define ${_nameUpper} - -#include - -#ifdef __cplusplus -extern \"C\" { -#endif /* __cplusplus */ - -") - - foreach(_currentModule ${PY_STATIC_MODULES_LIST}) - file(APPEND ${_filenameTmp} "extern void init${PYTHON_MODULE_PREFIX}${_currentModule}(void);\n\n") - endforeach() - - file(APPEND ${_filenameTmp} -"#ifdef __cplusplus -} -#endif /* __cplusplus */ - -") - - - foreach(_currentModule ${PY_STATIC_MODULES_LIST}) - file(APPEND ${_filenameTmp} "int ${_name}_${_currentModule}(void) \n{\n static char name[]=\"${PYTHON_MODULE_PREFIX}${_currentModule}\"; return PyImport_AppendInittab(name, init${PYTHON_MODULE_PREFIX}${_currentModule});\n}\n\n") - endforeach() - - file(APPEND ${_filenameTmp} "void ${_name}_LoadAllPythonModules(void)\n{\n") - foreach(_currentModule ${PY_STATIC_MODULES_LIST}) - file(APPEND ${_filenameTmp} " ${_name}_${_currentModule}();\n") - endforeach() - file(APPEND ${_filenameTmp} "}\n\n") - file(APPEND ${_filenameTmp} "#ifndef EXCLUDE_LOAD_ALL_FUNCTION\nvoid CMakeLoadAllPythonModules(void)\n{\n ${_name}_LoadAllPythonModules();\n}\n#endif\n\n#endif\n") - -# with configure_file() cmake complains that you may not use a file created using file(WRITE) as input file for configure_file() - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_filenameTmp}" "${_filename}" OUTPUT_QUIET ERROR_QUIET) - -endfunction() diff --git a/include/CacheBase.h b/include/CacheBase.h index 31cfad51..65ce1377 100644 --- a/include/CacheBase.h +++ b/include/CacheBase.h @@ -32,6 +32,7 @@ #define OPENSHOT_CACHE_BASE_H #include +#include #include "Frame.h" #include "Exceptions.h" #include "Json.h" diff --git a/include/ChunkReader.h b/include/ChunkReader.h index 35e3af4e..9d99fcd4 100644 --- a/include/ChunkReader.h +++ b/include/ChunkReader.h @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include "Json.h" #include "CacheMemory.h" diff --git a/include/Exceptions.h b/include/Exceptions.h index c5228f13..28942050 100644 --- a/include/Exceptions.h +++ b/include/Exceptions.h @@ -61,6 +61,14 @@ namespace openshot { int64_t frame_number; int64_t chunk_number; int64_t chunk_frame; + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param frame_number The frame number being processed + * @param chunk_number The chunk requested + * @param chunk_frame The chunk frame + */ ChunkNotFound(std::string message, int64_t frame_number, int64_t chunk_number, int64_t chunk_frame) : BaseException(message), frame_number(frame_number), chunk_number(chunk_number), chunk_frame(chunk_frame) { } virtual ~ChunkNotFound() noexcept {} @@ -71,6 +79,11 @@ namespace openshot { class DecklinkError : public BaseException { public: + /** + * @brief Constructor + * + * @param message A message to accompany the exception + */ DecklinkError(std::string message) : BaseException(message) { } virtual ~DecklinkError() noexcept {} @@ -81,6 +94,12 @@ namespace openshot { { public: int64_t frame_number; + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param frame_number The frame number being processed + */ ErrorDecodingAudio(std::string message, int64_t frame_number) : BaseException(message), frame_number(frame_number) { } virtual ~ErrorDecodingAudio() noexcept {} @@ -91,6 +110,12 @@ namespace openshot { { public: int64_t frame_number; + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param frame_number The frame number being processed + */ ErrorEncodingAudio(std::string message, int64_t frame_number) : BaseException(message), frame_number(frame_number) { } virtual ~ErrorEncodingAudio() noexcept {} @@ -101,6 +126,12 @@ namespace openshot { { public: int64_t frame_number; + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param frame_number The frame number being processed + */ ErrorEncodingVideo(std::string message, int64_t frame_number) : BaseException(message), frame_number(frame_number) { } virtual ~ErrorEncodingVideo() noexcept {} @@ -111,7 +142,13 @@ namespace openshot { { public: std::string file_path; - InvalidChannels(std::string message, std::string file_path) + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param file_path (optional) The input file being processed + */ + InvalidChannels(std::string message, std::string file_path="") : BaseException(message), file_path(file_path) { } virtual ~InvalidChannels() noexcept {} }; @@ -121,7 +158,13 @@ namespace openshot { { public: std::string file_path; - InvalidCodec(std::string message, std::string file_path) + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param file_path (optional) The input file being processed + */ + InvalidCodec(std::string message, std::string file_path="") : BaseException(message), file_path(file_path) { } virtual ~InvalidCodec() noexcept {} }; @@ -131,6 +174,12 @@ namespace openshot { { public: std::string file_path; + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param file_path The input file being processed + */ InvalidFile(std::string message, std::string file_path) : BaseException(message), file_path(file_path) { } virtual ~InvalidFile() noexcept {} @@ -141,7 +190,13 @@ namespace openshot { { public: std::string file_path; - InvalidFormat(std::string message, std::string file_path) + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param file_path (optional) The input file being processed + */ + InvalidFormat(std::string message, std::string file_path="") : BaseException(message), file_path(file_path) { } virtual ~InvalidFormat() noexcept {} }; @@ -151,7 +206,13 @@ namespace openshot { { public: std::string file_path; - InvalidJSON(std::string message, std::string file_path) + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param file_path (optional) The input file being processed + */ + InvalidJSON(std::string message, std::string file_path="") : BaseException(message), file_path(file_path) { } virtual ~InvalidJSON() noexcept {} }; @@ -161,7 +222,13 @@ namespace openshot { { public: std::string file_path; - InvalidOptions(std::string message, std::string file_path) + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param file_path (optional) The input file being processed + */ + InvalidOptions(std::string message, std::string file_path="") : BaseException(message), file_path(file_path) { } virtual ~InvalidOptions() noexcept {} }; @@ -171,7 +238,13 @@ namespace openshot { { public: std::string file_path; - InvalidSampleRate(std::string message, std::string file_path) + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param file_path (optional) The input file being processed + */ + InvalidSampleRate(std::string message, std::string file_path="") : BaseException(message), file_path(file_path) { } virtual ~InvalidSampleRate() noexcept {} }; @@ -181,6 +254,12 @@ namespace openshot { { public: std::string json; + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param json The json data being processed + */ InvalidJSONKey(std::string message, std::string json) : BaseException(message), json(json) { } virtual ~InvalidJSONKey() noexcept {} @@ -191,7 +270,13 @@ namespace openshot { { public: std::string file_path; - NoStreamsFound(std::string message, std::string file_path) + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param file_path (optional) The input file being processed + */ + NoStreamsFound(std::string message, std::string file_path="") : BaseException(message), file_path(file_path) { } virtual ~NoStreamsFound() noexcept {} }; @@ -202,6 +287,13 @@ namespace openshot { public: int64_t FrameRequested; int64_t MaxFrames; + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param frame_requested The out-of-bounds frame number requested + * @param max_frames The maximum available frame number + */ OutOfBoundsFrame(std::string message, int64_t frame_requested, int64_t max_frames) : BaseException(message), FrameRequested(frame_requested), MaxFrames(max_frames) { } virtual ~OutOfBoundsFrame() noexcept {} @@ -213,6 +305,13 @@ namespace openshot { public: int PointRequested; int MaxPoints; + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param point_requested The out-of-bounds point requested + * @param max_points The maximum available point value + */ OutOfBoundsPoint(std::string message, int point_requested, int max_points) : BaseException(message), PointRequested(point_requested), MaxPoints(max_points) { } virtual ~OutOfBoundsPoint() noexcept {} @@ -223,7 +322,13 @@ namespace openshot { { public: std::string file_path; - OutOfMemory(std::string message, std::string file_path) + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param file_path (optional) The input file being processed + */ + OutOfMemory(std::string message, std::string file_path="") : BaseException(message), file_path(file_path) { } virtual ~OutOfMemory() noexcept {} }; @@ -233,7 +338,13 @@ namespace openshot { { public: std::string file_path; - ReaderClosed(std::string message, std::string file_path) + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param file_path (optional) The input file being processed + */ + ReaderClosed(std::string message, std::string file_path="") : BaseException(message), file_path(file_path) { } virtual ~ReaderClosed() noexcept {} }; @@ -243,7 +354,13 @@ namespace openshot { { public: std::string file_path; - ResampleError(std::string message, std::string file_path) + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param file_path (optional) The input file being processed + */ + ResampleError(std::string message, std::string file_path="") : BaseException(message), file_path(file_path) { } virtual ~ResampleError() noexcept {} }; @@ -253,7 +370,13 @@ namespace openshot { { public: std::string file_path; - TooManySeeks(std::string message, std::string file_path) + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param file_path (optional) The input file being processed + */ + TooManySeeks(std::string message, std::string file_path="") : BaseException(message), file_path(file_path) { } virtual ~TooManySeeks() noexcept {} }; @@ -263,7 +386,13 @@ namespace openshot { { public: std::string file_path; - WriterClosed(std::string message, std::string file_path) + /** + * @brief Constructor + * + * @param message A message to accompany the exception + * @param file_path (optional) The output file being written + */ + WriterClosed(std::string message, std::string file_path="") : BaseException(message), file_path(file_path) { } virtual ~WriterClosed() noexcept {} }; diff --git a/include/OpenShotVersion.h.in b/include/OpenShotVersion.h.in index e6b907ff..e15662b2 100644 --- a/include/OpenShotVersion.h.in +++ b/include/OpenShotVersion.h.in @@ -48,30 +48,23 @@ namespace openshot { /// This struct holds version number information. Use the GetVersion() method to access the current version of libopenshot. struct OpenShotVersion { - int major; /// Major version number - int minor; /// Minor version number - int build; /// Build number - int so; /// Shared Object Number (incremented when API or ABI changes) + static const int Major = OPENSHOT_VERSION_MAJOR; /// Major version number + static const int Minor = OPENSHOT_VERSION_MINOR; /// Minor version number + static const int Build = OPENSHOT_VERSION_BUILD; /// Build number + static const int So = OPENSHOT_VERSION_SO; /// Shared Object Number (incremented when API or ABI changes) /// Get a string version of the version (i.e. "Major.Minor.Build") - std::string ToString() { + inline static const std::string ToString() { std::stringstream version_string; - version_string << major << "." << minor << "." << build; + version_string << Major << "." << Minor << "." << Build; return version_string.str(); } }; + static const openshot::OpenShotVersion Version; + /// Get the current version number of libopenshot (major, minor, and build number) - static OpenShotVersion GetVersion() { - OpenShotVersion version; - - // Set version info - version.major = OPENSHOT_VERSION_MAJOR; - version.minor = OPENSHOT_VERSION_MINOR; - version.build = OPENSHOT_VERSION_BUILD; - version.so = OPENSHOT_VERSION_SO; - - return version; - } + openshot::OpenShotVersion GetVersion(); } -#endif + +#endif // OPENSHOT_VERSION_H \ No newline at end of file diff --git a/include/QtImageReader.h b/include/QtImageReader.h index 49a15fbd..3153e7a3 100644 --- a/include/QtImageReader.h +++ b/include/QtImageReader.h @@ -65,7 +65,7 @@ namespace openshot class QtImageReader : public ReaderBase { private: - std::string path; + QString path; std::shared_ptr image; ///> Original image (full quality) std::shared_ptr cached_image; ///> Scaled for performance bool is_open; ///> Is Reader opened diff --git a/include/ReaderBase.h b/include/ReaderBase.h index 7ef60923..4e1cff25 100644 --- a/include/ReaderBase.h +++ b/include/ReaderBase.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include "CacheMemory.h" #include "ChannelLayouts.h" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6980dbae..398d6154 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,8 +6,8 @@ # # 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 +# 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 @@ -27,6 +27,12 @@ # Pick up our include directories from the parent context include_directories(${OPENSHOT_INCLUDE_DIRS}) +####### Display summary of options/dependencies ###### +include(FeatureSummary) +#set_property(GLOBAL APPEND PROPERTY FeatureSummary_PKG_TYPES BUILD) +#find_package(FOO) +#set_package_properties(FOO PROPERTIES TYPE BUILD) + ################ OPTIONS ################## # Optional build settings for libopenshot OPTION(USE_SYSTEM_JSONCPP "Use system installed JsonCpp" OFF) @@ -82,33 +88,15 @@ ENDIF (ImageMagick_FOUND) # Find FFmpeg libraries (used for video encoding / decoding) FIND_PACKAGE(FFmpeg REQUIRED) -IF (AVCODEC_FOUND) - include_directories(${AVCODEC_INCLUDE_DIRS}) -ENDIF (AVCODEC_FOUND) -IF (AVDEVICE_FOUND) - include_directories(${AVDEVICE_INCLUDE_DIRS}) -ENDIF (AVDEVICE_FOUND) -IF (AVFORMAT_FOUND) - include_directories(${AVFORMAT_INCLUDE_DIRS}) -ENDIF (AVFORMAT_FOUND) -IF (AVFILTER_FOUND) - include_directories(${AVFILTER_INCLUDE_DIRS}) -ENDIF (AVFILTER_FOUND) -IF (AVUTIL_FOUND) - include_directories(${AVUTIL_INCLUDE_DIRS}) -ENDIF (AVUTIL_FOUND) -IF (POSTPROC_FOUND) - include_directories(${POSTPROC_INCLUDE_DIRS}) -ENDIF (POSTPROC_FOUND) -IF (SWSCALE_FOUND) - include_directories(${SWSCALE_INCLUDE_DIRS}) -ENDIF (SWSCALE_FOUND) -IF (SWRESAMPLE_FOUND) - include_directories(${SWRESAMPLE_INCLUDE_DIRS}) -ENDIF (SWRESAMPLE_FOUND) -IF (AVRESAMPLE_FOUND) - include_directories(${AVRESAMPLE_INCLUDE_DIRS}) -ENDIF (AVRESAMPLE_FOUND) +foreach(ffmpeg_comp AVCODEC AVDEVICE AVFORMAT AVFILTER AVUTIL POSTPROC SWSCALE SWRESAMPLE AVRESAMPLE) + if(${ffmpeg_comp}_FOUND) + list(APPEND FF_INCLUDES ${${ffmpeg_comp}_INCLUDE_DIRS}) + add_definitions(${${ffmpeg_comp}_DEFINITIONS}) + list(APPEND FF_LIBRARIES ${${ffmpeg_comp}_LIBRARIES}) + endif() +endforeach() +list(REMOVE_DUPLICATES FF_INCLUDES) +include_directories(${FF_INCLUDES}) ################# LIBOPENSHOT-AUDIO ################### # Find JUCE-based openshot Audio libraries @@ -119,38 +107,17 @@ include_directories(${LIBOPENSHOT_AUDIO_INCLUDE_DIRS}) ################# QT5 ################### # Find QT5 libraries -find_package(Qt5Widgets REQUIRED) -find_package(Qt5Core REQUIRED) -find_package(Qt5Gui REQUIRED) -find_package(Qt5Multimedia REQUIRED) -find_package(Qt5MultimediaWidgets REQUIRED) - -# Include Qt headers (needed for compile) -include_directories(${Qt5Widgets_INCLUDE_DIRS}) -include_directories(${Qt5Core_INCLUDE_DIRS}) -include_directories(${Qt5Gui_INCLUDE_DIRS}) -include_directories(${Qt5Multimedia_INCLUDE_DIRS}) -include_directories(${Qt5MultimediaWidgets_INCLUDE_DIRS}) - -add_definitions(${Qt5Widgets_DEFINITIONS}) -add_definitions(${Qt5Core_DEFINITIONS}) -add_definitions(${Qt5Gui_DEFINITIONS}) -add_definitions(${Qt5Multimedia_DEFINITIONS}) -add_definitions(${Qt5MultimediaWidgets_DEFINITIONS}) - -SET(QT_LIBRARIES ${Qt5Widgets_LIBRARIES} - ${Qt5Core_LIBRARIES} - ${Qt5Gui_LIBRARIES} - ${Qt5Multimedia_LIBRARIES} - ${Qt5MultimediaWidgets_LIBRARIES}) - -# Set compiler flags for Qt -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS} ") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS} ") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Gui_EXECUTABLE_COMPILE_FLAGS} ") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Multimedia_EXECUTABLE_COMPILE_FLAGS} ") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5MultimediaWidgets_EXECUTABLE_COMPILE_FLAGS} ") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -ggdb ") +foreach(qt_lib Qt5Widgets Qt5Core Qt5Gui Qt5Multimedia Qt5MultimediaWidgets) + find_package(${qt_lib} REQUIRED) + # Header files + include_directories(${${qt_lib}_INCLUDE_DIRS}) + # Compiler definitions + add_definitions(${${qt_lib}_DEFINITIONS}) + # Other CFLAGS + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${${qt_lib}_EXECUTABLE_COMPILE_FLAGS}") + # For use when linking + list(APPEND QT_LIBRARIES ${${qt_lib}_LIBRARIES}) +endforeach() # Manually moc Qt files qt5_wrap_cpp(MOC_FILES ${QT_HEADER_FILES}) @@ -161,7 +128,7 @@ IF (ENABLE_BLACKMAGIC) FIND_PACKAGE(BlackMagic) IF (BLACKMAGIC_FOUND) - # Include headers (needed for compile) + # Include Blackmagic headers (needed for compile) include_directories(${BLACKMAGIC_INCLUDE_DIR}) # define a global var (used in the C++) @@ -171,20 +138,19 @@ IF (ENABLE_BLACKMAGIC) ENDIF (BLACKMAGIC_FOUND) ENDIF (ENABLE_BLACKMAGIC) -################### OPENMP ##################### -# Check for OpenMP (used for multi-core processing) -FIND_PACKAGE(OpenMP) - -if (OPENMP_FOUND) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS} ") -endif(OPENMP_FOUND) - ################### ZEROMQ ##################### # Find ZeroMQ library (used for socket communication & logging) -FIND_PACKAGE(ZMQ REQUIRED) + +# Some platforms package the header-only cppzmq C++ bindings separately, +# others (Ubuntu) bundle them in with libzmq itself +find_package(cppzmq QUIET) +find_package(ZMQ REQUIRED) # Include ZeroMQ headers (needed for compile) include_directories(${ZMQ_INCLUDE_DIRS}) +if (cppzmq_FOUND) + include_directories(${cppzmq_INCLUDE_DIRS}) +endif() ################### RESVG ##################### # Find resvg library (used for rendering svg files) @@ -249,6 +215,7 @@ SET ( OPENSHOT_SOURCE_FILES Frame.cpp FrameMapper.cpp KeyFrame.cpp + OpenShotVersion.cpp ZmqLogger.cpp PlayerBase.cpp Point.cpp @@ -306,72 +273,70 @@ set_target_properties(openshot INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" ) +################### OPENMP ##################### +# Check for OpenMP (used for multi-core processing) + +# OpenMP is required by FFmpegReader/Writer +find_package(OpenMP REQUIRED) + +if(NOT TARGET OpenMP::OpenMP_CXX) + # Older CMake versions (< 3.9) don't create find targets. + add_library(OpenMP_TARGET INTERFACE) + add_library(OpenMP::OpenMP_CXX ALIAS OpenMP_TARGET) + target_compile_options(OpenMP_TARGET INTERFACE ${OpenMP_CXX_FLAGS}) + find_package(Threads REQUIRED) + target_link_libraries(OpenMP_TARGET INTERFACE Threads::Threads) + target_link_libraries(OpenMP_TARGET INTERFACE ${OpenMP_CXX_FLAGS}) +endif() + +target_link_libraries(openshot PUBLIC OpenMP::OpenMP_CXX) + ############### LINK LIBRARY ################# SET ( REQUIRED_LIBRARIES ${LIBOPENSHOT_AUDIO_LIBRARIES} + ${FF_LIBRARIES} ${QT_LIBRARIES} ${PROFILER} ${JSONCPP_LIBRARY} ${ZMQ_LIBRARIES} ) -IF (AVCODEC_FOUND) - SET ( REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} ${AVCODEC_LIBRARIES} ) -ENDIF (AVCODEC_FOUND) -IF (AVDEVICE_FOUND) - SET ( REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} ${AVDEVICE_LIBRARIES} ) -ENDIF (AVDEVICE_FOUND) -IF (AVFORMAT_FOUND) - SET ( REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} ${AVFORMAT_LIBRARIES} ) -ENDIF (AVFORMAT_FOUND) -IF (AVFILTER_FOUND) - SET ( REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} ${AVFILTER_LIBRARIES} ) -ENDIF (AVFILTER_FOUND) -IF (AVUTIL_FOUND) - SET ( REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} ${AVUTIL_LIBRARIES} ) -ENDIF (AVUTIL_FOUND) -IF (POSTPROC_FOUND) - SET ( REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} ${POSTPROC_LIBRARIES} ) -ENDIF (POSTPROC_FOUND) -IF (SWSCALE_FOUND) - SET ( REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} ${SWSCALE_LIBRARIES} ) -ENDIF (SWSCALE_FOUND) -IF (SWRESAMPLE_FOUND) - SET ( REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} ${SWRESAMPLE_LIBRARIES} ) -ENDIF (SWRESAMPLE_FOUND) -IF (AVRESAMPLE_FOUND) - SET ( REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} ${AVRESAMPLE_LIBRARIES} ) -ENDIF (AVRESAMPLE_FOUND) - IF (RESVG_FOUND) - SET ( REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} ${RESVG_LIBRARIES} ) + list(APPEND REQUIRED_LIBRARIES ${RESVG_LIBRARIES}) ENDIF(RESVG_FOUND) -IF (OPENMP_FOUND) - SET ( REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} ${OpenMP_CXX_FLAGS} ) -ENDIF (OPENMP_FOUND) IF (ImageMagick_FOUND) - SET ( REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} ${ImageMagick_LIBRARIES} ) + list(APPEND REQUIRED_LIBRARIES ${ImageMagick_LIBRARIES}) ENDIF (ImageMagick_FOUND) IF (BLACKMAGIC_FOUND) - SET ( REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} ${BLACKMAGIC_LIBRARY_DIR} ) + list(APPEND REQUIRED_LIBRARIES ${BLACKMAGIC_LIBRARY_DIR}) ENDIF (BLACKMAGIC_FOUND) IF (WIN32) # Required for exception handling on Windows - SET ( REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} "imagehlp" "dbghelp" ) + list(APPEND REQUIRED_LIBRARIES "imagehlp" "dbghelp" ) ENDIF(WIN32) # Link all referenced libraries -target_link_libraries(openshot ${REQUIRED_LIBRARIES}) +target_link_libraries(openshot PUBLIC ${REQUIRED_LIBRARIES}) +# Pick up parameters from OpenMP target and propagate +target_link_libraries(openshot PUBLIC OpenMP::OpenMP_CXX) ############### CLI EXECUTABLE ################ # Create test executable add_executable(openshot-example examples/Example.cpp) +# Define path to test input files +SET(TEST_MEDIA_PATH "${PROJECT_SOURCE_DIR}/src/examples/") +IF (WIN32) + STRING(REPLACE "/" "\\\\" TEST_MEDIA_PATH TEST_MEDIA_PATH) +ENDIF(WIN32) +target_compile_definitions(openshot-example PRIVATE + -DTEST_MEDIA_PATH="${TEST_MEDIA_PATH}" ) + # Link test executable to the new library target_link_libraries(openshot-example openshot) @@ -395,12 +360,18 @@ ENDIF (BLACKMAGIC_FOUND) ############### INCLUDE SWIG BINDINGS ################ add_subdirectory(bindings) +########### PRINT FEATURE SUMMARY ############## +feature_summary(WHAT ALL + INCLUDE_QUIET_PACKAGES + DESCRIPTION "Build configuration:" + VAR featuresText) +message("\n${featuresText}") ############### INSTALL HEADERS & LIBRARY ################ set(LIB_INSTALL_DIR lib${LIB_SUFFIX}) # determine correct lib folder # Install primary library -INSTALL( TARGETS openshot +INSTALL(TARGETS openshot ARCHIVE DESTINATION ${LIB_INSTALL_DIR} LIBRARY DESTINATION ${LIB_INSTALL_DIR} RUNTIME DESTINATION ${LIB_INSTALL_DIR} diff --git a/src/CacheBase.cpp b/src/CacheBase.cpp index b5627e8b..8a7d541a 100644 --- a/src/CacheBase.cpp +++ b/src/CacheBase.cpp @@ -71,5 +71,5 @@ void CacheBase::SetJsonValue(Json::Value root) { // Set data from Json (if key is found) if (!root["max_bytes"].isNull()) - max_bytes = atoll(root["max_bytes"].asString().c_str()); + max_bytes = std::stoll(root["max_bytes"].asString()); } diff --git a/src/CacheDisk.cpp b/src/CacheDisk.cpp index 41b40aef..5dc677e5 100644 --- a/src/CacheDisk.cpp +++ b/src/CacheDisk.cpp @@ -519,7 +519,7 @@ void CacheDisk::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -529,7 +529,7 @@ void CacheDisk::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/CacheMemory.cpp b/src/CacheMemory.cpp index 2673f68b..ff8963fd 100644 --- a/src/CacheMemory.cpp +++ b/src/CacheMemory.cpp @@ -372,7 +372,7 @@ void CacheMemory::SetJson(std::string value) { delete reader; if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -382,7 +382,7 @@ void CacheMemory::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/ChunkReader.cpp b/src/ChunkReader.cpp index 983f8d58..7321cb26 100644 --- a/src/ChunkReader.cpp +++ b/src/ChunkReader.cpp @@ -94,7 +94,7 @@ void ChunkReader::load_json() info.has_video = root["has_video"].asBool(); info.has_audio = root["has_audio"].asBool(); info.duration = root["duration"].asDouble(); - info.file_size = atoll(root["file_size"].asString().c_str()); + info.file_size = std::stoll(root["file_size"].asString()); info.height = root["height"].asInt(); info.width = root["width"].asInt(); info.pixel_format = root["pixel_format"].asInt(); @@ -106,7 +106,7 @@ void ChunkReader::load_json() info.display_ratio.num = root["display_ratio"]["num"].asInt(); info.display_ratio.den = root["display_ratio"]["den"].asInt(); info.vcodec = root["vcodec"].asString(); - info.video_length = atoll(root["video_length"].asString().c_str()); + info.video_length = std::stoll(root["video_length"].asString()); info.video_stream_index = root["video_stream_index"].asInt(); info.video_timebase.num = root["video_timebase"]["num"].asInt(); info.video_timebase.den = root["video_timebase"]["den"].asInt(); @@ -292,7 +292,7 @@ void ChunkReader::SetJson(std::string value) { delete reader; if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -302,7 +302,7 @@ void ChunkReader::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } @@ -316,7 +316,7 @@ void ChunkReader::SetJsonValue(Json::Value root) { if (!root["path"].isNull()) path = root["path"].asString(); if (!root["chunk_size"].isNull()) - chunk_size = atoll(root["chunk_size"].asString().c_str()); + chunk_size = std::stoll(root["chunk_size"].asString()); if (!root["chunk_version"].isNull()) version = (ChunkVersion) root["chunk_version"].asInt(); diff --git a/src/Clip.cpp b/src/Clip.cpp index 4d7138e7..30b28885 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -235,7 +235,7 @@ ReaderBase* Clip::Reader() return reader; else // Throw error if reader not initialized - throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.", ""); + throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method."); } // Open the internal reader @@ -252,7 +252,7 @@ void Clip::Open() } else // Throw error if reader not initialized - throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.", ""); + throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method."); } // Close the internal reader @@ -266,7 +266,7 @@ void Clip::Close() } else // Throw error if reader not initialized - throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.", ""); + throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method."); } // Get end position of clip (trim end of video), which can be affected by the time curve. @@ -282,7 +282,7 @@ float Clip::End() fps = reader->info.fps.ToFloat(); else // Throw error if reader not initialized - throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.", ""); + throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method."); return float(time.GetLength()) / fps; } @@ -350,7 +350,7 @@ std::shared_ptr Clip::GetFrame(int64_t requested_frame) } else // Throw error if reader not initialized - throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.", ""); + throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method."); } // Get file extension @@ -394,7 +394,7 @@ void Clip::get_time_mapped_frame(std::shared_ptr frame, int64_t frame_num // Check for valid reader if (!reader) // Throw error if reader not initialized - throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.", ""); + throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method."); // Check for a valid time map curve if (time.Values.size() > 1) @@ -812,7 +812,7 @@ void Clip::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -822,7 +822,7 @@ void Clip::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/Color.cpp b/src/Color.cpp index 9266800d..927fc162 100644 --- a/src/Color.cpp +++ b/src/Color.cpp @@ -120,7 +120,7 @@ void Color::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -130,7 +130,7 @@ void Color::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/Coordinate.cpp b/src/Coordinate.cpp index 0a8349b7..a0bdabcc 100644 --- a/src/Coordinate.cpp +++ b/src/Coordinate.cpp @@ -83,7 +83,7 @@ void Coordinate::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -93,7 +93,7 @@ void Coordinate::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/DecklinkReader.cpp b/src/DecklinkReader.cpp index 6d727da1..35ed1857 100644 --- a/src/DecklinkReader.cpp +++ b/src/DecklinkReader.cpp @@ -278,7 +278,7 @@ void DecklinkReader::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -288,7 +288,7 @@ void DecklinkReader::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/DecklinkWriter.cpp b/src/DecklinkWriter.cpp index 7dcede04..4ebbd1f0 100644 --- a/src/DecklinkWriter.cpp +++ b/src/DecklinkWriter.cpp @@ -234,7 +234,7 @@ void DecklinkWriter::WriteFrame(std::shared_ptr frame) { // Check for open reader (or throw exception) if (!is_open) - throw WriterClosed("The DecklinkWriter is closed. Call Open() before calling this method.", ""); + throw WriterClosed("The DecklinkWriter is closed. Call Open() before calling this method."); delegate->WriteFrame(frame); } diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp index 8b2abedf..997a020a 100644 --- a/src/DummyReader.cpp +++ b/src/DummyReader.cpp @@ -156,7 +156,7 @@ void DummyReader::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -166,7 +166,7 @@ void DummyReader::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/EffectBase.cpp b/src/EffectBase.cpp index b04c1697..30e83765 100644 --- a/src/EffectBase.cpp +++ b/src/EffectBase.cpp @@ -112,7 +112,7 @@ void EffectBase::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -122,7 +122,7 @@ void EffectBase::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 7904409d..8f77cda4 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -309,7 +309,7 @@ void FFmpegReader::Open() { char *adapter_ptr = NULL; int adapter_num; adapter_num = openshot::Settings::Instance()->HW_DE_DEVICE_SET; - fprintf(stderr, "\n\nDecodiing Device Nr: %d\n", adapter_num); + fprintf(stderr, "Hardware decoding device number: %d\n", adapter_num); // Set hardware pix format (callback) pCodecCtx->get_format = get_hw_dec_format; @@ -729,6 +729,33 @@ void FFmpegReader::UpdateVideoInfo() { info.display_ratio.num = size.num; info.display_ratio.den = size.den; + // Get scan type and order from codec context/params + if (!check_interlace) { + check_interlace = true; + AVFieldOrder field_order = AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->field_order; + switch(field_order) { + case AV_FIELD_PROGRESSIVE: + info.interlaced_frame = false; + break; + case AV_FIELD_TT: + case AV_FIELD_TB: + info.interlaced_frame = true; + info.top_field_first = true; + break; + case AV_FIELD_BT: + case AV_FIELD_BB: + info.interlaced_frame = true; + info.top_field_first = false; + break; + case AV_FIELD_UNKNOWN: + // Check again later? + check_interlace = false; + break; + } + // check_interlace will prevent these checks being repeated, + // unless it was cleared because we got an AV_FIELD_UNKNOWN response. + } + // Set the video timebase info.video_timebase.num = pStream->time_base.num; info.video_timebase.den = pStream->time_base.den; @@ -1078,14 +1105,14 @@ bool FFmpegReader::GetAVFrame() { ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Packet not sent)"); } else { - AVFrame *next_frame2; - if (hw_de_on && hw_de_supported) { - next_frame2 = AV_ALLOCATE_FRAME(); - } - else - { - next_frame2 = next_frame; - } + AVFrame *next_frame2; + if (hw_de_on && hw_de_supported) { + next_frame2 = AV_ALLOCATE_FRAME(); + } + else + { + next_frame2 = next_frame; + } pFrame = AV_ALLOCATE_FRAME(); while (ret >= 0) { ret = avcodec_receive_frame(pCodecCtx, next_frame2); @@ -1119,11 +1146,6 @@ bool FFmpegReader::GetAVFrame() { av_image_alloc(pFrame->data, pFrame->linesize, info.width, info.height, (AVPixelFormat)(pStream->codecpar->format), 1); av_image_copy(pFrame->data, pFrame->linesize, (const uint8_t**)next_frame->data, next_frame->linesize, (AVPixelFormat)(pStream->codecpar->format), info.width, info.height); - if (!check_interlace) { - check_interlace = true; - info.interlaced_frame = next_frame->interlaced_frame; - info.top_field_first = next_frame->top_field_first; - } } } if (hw_de_on && hw_de_supported) { @@ -1143,13 +1165,6 @@ bool FFmpegReader::GetAVFrame() { avpicture_alloc((AVPicture *) pFrame, pCodecCtx->pix_fmt, info.width, info.height); av_picture_copy((AVPicture *) pFrame, (AVPicture *) next_frame, pCodecCtx->pix_fmt, info.width, info.height); - - // Detect interlaced frame (only once) - if (!check_interlace) { - check_interlace = true; - info.interlaced_frame = next_frame->interlaced_frame; - info.top_field_first = next_frame->top_field_first; - } } #endif } @@ -2002,7 +2017,15 @@ AudioLocation FFmpegReader::GetAudioPTSLocation(int64_t pts) { std::shared_ptr FFmpegReader::CreateFrame(int64_t requested_frame) { // Check working cache std::shared_ptr output = working_cache.GetFrame(requested_frame); + if (!output) { + // Lock + const GenericScopedLock lock(processingCriticalSection); + + // (re-)Check working cache + output = working_cache.GetFrame(requested_frame); + if(output) return output; + // Create a new frame on the working cache output = std::make_shared(requested_frame, info.width, info.height, "#000000", Frame::GetSamplesPerFrame(requested_frame, info.fps, info.sample_rate, info.channels), info.channels); output->SetPixelRatio(info.pixel_ratio.num, info.pixel_ratio.den); // update pixel ratio @@ -2015,8 +2038,7 @@ std::shared_ptr FFmpegReader::CreateFrame(int64_t requested_frame) { if (requested_frame > largest_frame_processed) largest_frame_processed = requested_frame; } - - // Return new frame + // Return frame return output; } @@ -2042,18 +2064,11 @@ bool FFmpegReader::CheckMissingFrame(int64_t requested_frame) { // Lock const GenericScopedLock lock(processingCriticalSection); - // Init # of times this frame has been checked so far - int checked_count = 0; - // Increment check count for this frame (or init to 1) - if (checked_frames.count(requested_frame) == 0) - checked_frames[requested_frame] = 1; - else - checked_frames[requested_frame]++; - checked_count = checked_frames[requested_frame]; + ++checked_frames[requested_frame]; // Debug output - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckMissingFrame", "requested_frame", requested_frame, "has_missing_frames", has_missing_frames, "missing_video_frames.size()", missing_video_frames.size(), "checked_count", checked_count); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckMissingFrame", "requested_frame", requested_frame, "has_missing_frames", has_missing_frames, "missing_video_frames.size()", missing_video_frames.size(), "checked_count", checked_frames[requested_frame]); // Missing frames (sometimes frame #'s are skipped due to invalid or missing timestamps) std::map::iterator itr; @@ -2066,7 +2081,7 @@ bool FFmpegReader::CheckMissingFrame(int64_t requested_frame) { // If MP3 with single video frame, handle this special case by copying the previously // decoded image to the new frame. Otherwise, it will spend a huge amount of // CPU time looking for missing images for all the audio-only frames. - if (checked_count > 8 && !missing_video_frames.count(requested_frame) && + 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)) { missing_video_frames.insert(std::pair(requested_frame, last_video_frame->number)); @@ -2080,10 +2095,7 @@ bool FFmpegReader::CheckMissingFrame(int64_t requested_frame) { int64_t missing_source_frame = missing_video_frames.find(requested_frame)->second; // Increment missing source frame check count (or init to 1) - if (checked_frames.count(missing_source_frame) == 0) - checked_frames[missing_source_frame] = 1; - else - checked_frames[missing_source_frame]++; + ++checked_frames[missing_source_frame]; // Get the previous frame of this missing frame (if it's available in missing cache) std::shared_ptr parent_frame = missing_frames.GetFrame(missing_source_frame); @@ -2445,7 +2457,7 @@ void FFmpegReader::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { // Set all values that match @@ -2453,7 +2465,7 @@ void FFmpegReader::SetJson(std::string value) { } catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index dfeca88a..84915a56 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -172,7 +172,7 @@ void FFmpegWriter::SetVideoOptions(bool has_video, std::string codec, Fraction f AVCodec *new_codec; // Check if the codec selected is a hardware accelerated codec #if IS_FFMPEG_3_2 - #if defined(__linux__) + #if defined(__linux__) if ( (strcmp(codec.c_str(),"h264_vaapi") == 0)) { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; @@ -194,7 +194,7 @@ void FFmpegWriter::SetVideoOptions(bool has_video, std::string codec, Fraction f hw_en_supported = 0; } } -#elif defined(_WIN32) + #elif defined(_WIN32) if ( (strcmp(codec.c_str(),"h264_dxva2") == 0)) { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; @@ -216,7 +216,7 @@ void FFmpegWriter::SetVideoOptions(bool has_video, std::string codec, Fraction f hw_en_supported = 0; } } -#elif defined(__APPLE__) + #elif defined(__APPLE__) if ( (strcmp(codec.c_str(),"h264_videotoolbox") == 0)) { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; @@ -229,9 +229,9 @@ void FFmpegWriter::SetVideoOptions(bool has_video, std::string codec, Fraction f hw_en_on = 0; hw_en_supported = 0; } -#else // is FFmpeg 3 but not linux + #else // is FFmpeg 3 but not linux new_codec = avcodec_find_encoder_by_name(codec.c_str()); -#endif //__linux__ + #endif //__linux__ #else // not ffmpeg 3 new_codec = avcodec_find_encoder_by_name(codec.c_str()); #endif //IS_FFMPEG_3_2 diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index df8d37b1..fe12a780 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -75,7 +75,7 @@ ReaderBase* FrameMapper::Reader() return reader; else // Throw error if reader not initialized - throw ReaderClosed("No Reader has been initialized for FrameMapper. Call Reader(*reader) before calling this method.", ""); + throw ReaderClosed("No Reader has been initialized for FrameMapper. Call Reader(*reader) before calling this method."); } void FrameMapper::AddField(int64_t frame) @@ -707,7 +707,7 @@ void FrameMapper::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -717,7 +717,7 @@ void FrameMapper::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/ImageReader.cpp b/src/ImageReader.cpp index 42dd58d6..1aa20ab4 100644 --- a/src/ImageReader.cpp +++ b/src/ImageReader.cpp @@ -169,7 +169,7 @@ void ImageReader::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -179,7 +179,7 @@ void ImageReader::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/KeyFrame.cpp b/src/KeyFrame.cpp index 895104d7..84ebb585 100644 --- a/src/KeyFrame.cpp +++ b/src/KeyFrame.cpp @@ -379,7 +379,7 @@ void Keyframe::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -389,7 +389,7 @@ void Keyframe::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/OpenShotVersion.cpp b/src/OpenShotVersion.cpp new file mode 100644 index 00000000..1bc73c3a --- /dev/null +++ b/src/OpenShotVersion.cpp @@ -0,0 +1,38 @@ +/** + * @file + * @brief Source file for GetVersion function + * @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 "OpenShotVersion.h" + +namespace openshot { + OpenShotVersion GetVersion() { + return openshot::Version; + } +} \ No newline at end of file diff --git a/src/Point.cpp b/src/Point.cpp index 0ff340d3..5f410e60 100644 --- a/src/Point.cpp +++ b/src/Point.cpp @@ -146,7 +146,7 @@ void Point::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -156,7 +156,7 @@ void Point::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/Profiles.cpp b/src/Profiles.cpp index 1c1f493b..e7c54771 100644 --- a/src/Profiles.cpp +++ b/src/Profiles.cpp @@ -177,7 +177,7 @@ void Profile::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -187,7 +187,7 @@ void Profile::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/Qt/VideoCacheThread.cpp b/src/Qt/VideoCacheThread.cpp index fbe784f7..46b6f030 100644 --- a/src/Qt/VideoCacheThread.cpp +++ b/src/Qt/VideoCacheThread.cpp @@ -93,7 +93,7 @@ namespace openshot try { if (reader) { - ZmqLogger::Instance()->AppendDebugMethod("VideoCacheThread::run (cache frame)", "position", position, "current_display_frame", current_display_frame, "max_frames", max_frames, "needed_frames", (position - current_display_frame), "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("VideoCacheThread::run (cache frame)", "position", position, "current_display_frame", current_display_frame, "max_frames", max_frames, "needed_frames", (position - current_display_frame)); // Force the frame to be generated reader->GetFrame(position); diff --git a/src/Qt/VideoPlaybackThread.cpp b/src/Qt/VideoPlaybackThread.cpp index 730a1d37..f1cff756 100644 --- a/src/Qt/VideoPlaybackThread.cpp +++ b/src/Qt/VideoPlaybackThread.cpp @@ -64,7 +64,7 @@ namespace openshot if (need_render && frame) { // Debug - ZmqLogger::Instance()->AppendDebugMethod("VideoPlaybackThread::run (before render)", "frame->number", frame->number, "need_render", need_render, "", -1, "", -1, "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("VideoPlaybackThread::run (before render)", "frame->number", frame->number, "need_render", need_render); // Render the frame to the screen renderer->paint(frame); diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp index 929a417d..55306446 100644 --- a/src/QtImageReader.cpp +++ b/src/QtImageReader.cpp @@ -44,14 +44,14 @@ using namespace openshot; -QtImageReader::QtImageReader(std::string path) : path(path), is_open(false) +QtImageReader::QtImageReader(std::string path) : path{QString::fromStdString(path)}, is_open(false) { // Open and Close the reader, to populate its attributes (such as height, width, etc...) Open(); Close(); } -QtImageReader::QtImageReader(std::string path, bool inspect_reader) : path(path), is_open(false) +QtImageReader::QtImageReader(std::string path, bool inspect_reader) : path{QString::fromStdString(path)}, is_open(false) { // Open and Close the reader, to populate its attributes (such as height, width, etc...) if (inspect_reader) { @@ -77,12 +77,12 @@ void QtImageReader::Open() // 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.find(".svg") != std::string::npos || path.find(".svgz") != std::string::npos) { + if (path.toLower().endsWith(".svg") || path.toLower().endsWith(".svgz")) { - ResvgRenderer renderer(QString::fromStdString(path)); + ResvgRenderer renderer(path); if (!renderer.isValid()) { // Attempt to open file (old method using Qt5 limited SVG parsing) - success = image->load(QString::fromStdString(path)); + success = image->load(path); if (success) { image = std::shared_ptr(new QImage(image->convertToFormat(QImage::Format_RGBA8888))); } @@ -98,20 +98,20 @@ void QtImageReader::Open() } else { // Attempt to open file (old method) - success = image->load(QString::fromStdString(path)); + 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(QString::fromStdString(path)); + success = image->load(path); if (success) image = std::shared_ptr(new QImage(image->convertToFormat(QImage::Format_RGBA8888))); #endif if (!success) // raise exception - throw InvalidFile("File could not be opened.", path); + throw InvalidFile("File could not be opened.", path.toStdString()); // Update image properties info.has_audio = false; @@ -171,7 +171,7 @@ std::shared_ptr QtImageReader::GetFrame(int64_t requested_frame) { // Check for open reader (or throw exception) if (!is_open) - throw ReaderClosed("The Image is closed. Call Open() before calling this method.", path); + throw ReaderClosed("The Image is closed. Call Open() before calling this method.", path.toStdString()); // Create a scoped lock, allowing only a single thread to run the following code at one time const GenericScopedLock lock(getFrameCriticalSection); @@ -228,8 +228,8 @@ std::shared_ptr QtImageReader::GetFrame(int64_t requested_frame) // 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.find(".svg") != std::string::npos || path.find(".svgz") != std::string::npos) { - ResvgRenderer renderer(QString::fromStdString(path)); + 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 QSize svg_size(renderer.defaultSize().width(), renderer.defaultSize().height()); @@ -289,7 +289,7 @@ Json::Value QtImageReader::JsonValue() { // Create root json object Json::Value root = ReaderBase::JsonValue(); // get parent properties root["type"] = "QtImageReader"; - root["path"] = path; + root["path"] = path.toStdString(); // return JsonValue return root; @@ -310,7 +310,7 @@ void QtImageReader::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -320,7 +320,7 @@ void QtImageReader::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } @@ -332,7 +332,7 @@ void QtImageReader::SetJsonValue(Json::Value root) { // Set data from Json (if key is found) if (!root["path"].isNull()) - path = root["path"].asString(); + path = QString::fromStdString(root["path"].asString()); // Re-Open path, and re-init everything (if needed) if (is_open) diff --git a/src/ReaderBase.cpp b/src/ReaderBase.cpp index 1966614c..ccd271f4 100644 --- a/src/ReaderBase.cpp +++ b/src/ReaderBase.cpp @@ -181,7 +181,7 @@ void ReaderBase::SetJsonValue(Json::Value root) { if (!root["duration"].isNull()) info.duration = root["duration"].asDouble(); if (!root["file_size"].isNull()) - info.file_size = atoll(root["file_size"].asString().c_str()); + info.file_size = std::stoll(root["file_size"].asString()); if (!root["height"].isNull()) info.height = root["height"].asInt(); if (!root["width"].isNull()) @@ -211,7 +211,7 @@ void ReaderBase::SetJsonValue(Json::Value root) { if (!root["vcodec"].isNull()) info.vcodec = root["vcodec"].asString(); if (!root["video_length"].isNull()) - info.video_length = atoll(root["video_length"].asString().c_str()); + info.video_length = std::stoll(root["video_length"].asString()); if (!root["video_stream_index"].isNull()) info.video_stream_index = root["video_stream_index"].asInt(); if (!root["video_timebase"].isNull() && root["video_timebase"].isObject()) { diff --git a/src/TextReader.cpp b/src/TextReader.cpp index 6037ae3d..504cfc92 100644 --- a/src/TextReader.cpp +++ b/src/TextReader.cpp @@ -230,7 +230,7 @@ void TextReader::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -240,7 +240,7 @@ void TextReader::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 7b656b36..51868157 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -746,7 +746,7 @@ std::shared_ptr Timeline::GetFrame(int64_t requested_frame) // Check for open reader (or throw exception) if (!is_open) - throw ReaderClosed("The Timeline is closed. Call Open() before calling this method.", ""); + throw ReaderClosed("The Timeline is closed. Call Open() before calling this method."); // Check cache again (due to locking) #pragma omp critical (T_GetFrame) @@ -1040,7 +1040,7 @@ void Timeline::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -1050,7 +1050,7 @@ void Timeline::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } @@ -1139,7 +1139,7 @@ void Timeline::ApplyJsonDiff(std::string value) { if (!success || !root.isArray()) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid).", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)."); try { @@ -1167,7 +1167,7 @@ void Timeline::ApplyJsonDiff(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/WriterBase.cpp b/src/WriterBase.cpp index 56723352..72b86b61 100644 --- a/src/WriterBase.cpp +++ b/src/WriterBase.cpp @@ -209,7 +209,7 @@ void WriterBase::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -219,7 +219,7 @@ void WriterBase::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 9afabd41..5c143e0b 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -48,7 +48,6 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) ### Enable C++ support in SWIG set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) - SET(CMAKE_SWIG_FLAGS "") ### Suppress a ton of warnings in the generated SWIG C++ code set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ diff --git a/src/bindings/python/openshot.i b/src/bindings/python/openshot.i index 84d6e5eb..5bf592ee 100644 --- a/src/bindings/python/openshot.i +++ b/src/bindings/python/openshot.i @@ -30,6 +30,9 @@ /* Suppress warnings about ignored operator= */ %warnfilter(362); +/* Don't generate multiple wrappers for functions with default args */ +%feature("compactdefaultargs", "1"); + /* Enable inline documentation */ %feature("autodoc", "1"); @@ -119,6 +122,13 @@ } } +%extend openshot::OpenShotVersion { + // Give the struct a string representation + const std::string __str__() { + return std::string(OPENSHOT_VERSION_FULL); + } +} + %include "OpenShotVersion.h" %include "../../../include/ReaderBase.h" %include "../../../include/WriterBase.h" diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt index 4b962e73..c7eb1d78 100644 --- a/src/bindings/ruby/CMakeLists.txt +++ b/src/bindings/ruby/CMakeLists.txt @@ -50,7 +50,6 @@ IF (RUBY_FOUND) set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) - SET(CMAKE_SWIG_FLAGS "") ### Suppress a ton of warnings in the generated SWIG C++ code set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ -Wno-unused-parameter -Wno-catch-value -Wno-sign-compare -Wno-ignored-qualifiers") diff --git a/src/bindings/ruby/openshot.i b/src/bindings/ruby/openshot.i index 1b9b4969..cdb3f9ff 100644 --- a/src/bindings/ruby/openshot.i +++ b/src/bindings/ruby/openshot.i @@ -30,6 +30,9 @@ /* Suppress warnings about ignored operator= */ %warnfilter(362); +/* Don't generate multiple wrappers for functions with default args */ +%feature("compactdefaultargs", "1"); + /* Enable inline documentation */ %feature("autodoc", "1"); diff --git a/src/effects/Bars.cpp b/src/effects/Bars.cpp index 544160c9..fcb684e3 100644 --- a/src/effects/Bars.cpp +++ b/src/effects/Bars.cpp @@ -151,7 +151,7 @@ void Bars::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -161,7 +161,7 @@ void Bars::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/effects/Blur.cpp b/src/effects/Blur.cpp index 8bfdad11..e0315fda 100644 --- a/src/effects/Blur.cpp +++ b/src/effects/Blur.cpp @@ -288,7 +288,7 @@ void Blur::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -298,7 +298,7 @@ void Blur::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/effects/Brightness.cpp b/src/effects/Brightness.cpp index b25727b7..b8113b87 100644 --- a/src/effects/Brightness.cpp +++ b/src/effects/Brightness.cpp @@ -142,7 +142,7 @@ void Brightness::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -152,7 +152,7 @@ void Brightness::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/effects/ChromaKey.cpp b/src/effects/ChromaKey.cpp index d06ce739..30c4dfce 100644 --- a/src/effects/ChromaKey.cpp +++ b/src/effects/ChromaKey.cpp @@ -135,7 +135,7 @@ void ChromaKey::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -145,7 +145,7 @@ void ChromaKey::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/effects/ColorShift.cpp b/src/effects/ColorShift.cpp index 94d53d22..ea8ae136 100644 --- a/src/effects/ColorShift.cpp +++ b/src/effects/ColorShift.cpp @@ -234,7 +234,7 @@ void ColorShift::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -244,7 +244,7 @@ void ColorShift::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/effects/Crop.cpp b/src/effects/Crop.cpp index aa35f05f..8a4afa5e 100644 --- a/src/effects/Crop.cpp +++ b/src/effects/Crop.cpp @@ -150,7 +150,7 @@ void Crop::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -160,7 +160,7 @@ void Crop::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/effects/Deinterlace.cpp b/src/effects/Deinterlace.cpp index b7a88e0b..a78af931 100644 --- a/src/effects/Deinterlace.cpp +++ b/src/effects/Deinterlace.cpp @@ -129,7 +129,7 @@ void Deinterlace::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -139,7 +139,7 @@ void Deinterlace::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/effects/Hue.cpp b/src/effects/Hue.cpp index 7a581616..4083d035 100644 --- a/src/effects/Hue.cpp +++ b/src/effects/Hue.cpp @@ -136,7 +136,7 @@ void Hue::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -146,7 +146,7 @@ void Hue::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/effects/Mask.cpp b/src/effects/Mask.cpp index 3749e14f..b804c214 100644 --- a/src/effects/Mask.cpp +++ b/src/effects/Mask.cpp @@ -189,7 +189,7 @@ void Mask::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -199,7 +199,7 @@ void Mask::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/effects/Negate.cpp b/src/effects/Negate.cpp index 690cd19e..cce59498 100644 --- a/src/effects/Negate.cpp +++ b/src/effects/Negate.cpp @@ -90,7 +90,7 @@ void Negate::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -100,7 +100,7 @@ void Negate::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/effects/Pixelate.cpp b/src/effects/Pixelate.cpp index f61e4686..a57a186f 100644 --- a/src/effects/Pixelate.cpp +++ b/src/effects/Pixelate.cpp @@ -147,7 +147,7 @@ void Pixelate::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -157,7 +157,7 @@ void Pixelate::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/effects/Saturation.cpp b/src/effects/Saturation.cpp index 9c941b76..06bcb02c 100644 --- a/src/effects/Saturation.cpp +++ b/src/effects/Saturation.cpp @@ -147,7 +147,7 @@ void Saturation::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -157,7 +157,7 @@ void Saturation::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/effects/Shift.cpp b/src/effects/Shift.cpp index a204157a..d0908fd8 100644 --- a/src/effects/Shift.cpp +++ b/src/effects/Shift.cpp @@ -167,7 +167,7 @@ void Shift::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -177,7 +177,7 @@ void Shift::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/effects/Wave.cpp b/src/effects/Wave.cpp index d6aa61b5..2139e4ac 100644 --- a/src/effects/Wave.cpp +++ b/src/effects/Wave.cpp @@ -150,7 +150,7 @@ void Wave::SetJson(std::string value) { if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -160,7 +160,7 @@ void Wave::SetJson(std::string value) { catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } } diff --git a/src/examples/Example.cpp b/src/examples/Example.cpp index ebda6b3f..c9e61628 100644 --- a/src/examples/Example.cpp +++ b/src/examples/Example.cpp @@ -39,16 +39,19 @@ using namespace openshot; int main(int argc, char* argv[]) { - Settings *s = Settings::Instance(); - s->HARDWARE_DECODER = 2; // 1 VA-API, 2 NVDEC - s->HW_DE_DEVICE_SET = 0; + Settings *s = Settings::Instance(); + s->HARDWARE_DECODER = 2; // 1 VA-API, 2 NVDEC, 6 VDPAU + s->HW_DE_DEVICE_SET = 0; - FFmpegReader r9("/home/jonathan/Videos/sintel_trailer-720p.mp4"); + std::string input_filepath = TEST_MEDIA_PATH; + input_filepath += "sintel_trailer-720p.mp4"; + + FFmpegReader r9(input_filepath); r9.Open(); r9.DisplayInfo(); /* WRITER ---------------- */ - FFmpegWriter w9("/home/jonathan/metadata.mp4"); + FFmpegWriter w9("metadata.mp4"); // Set options w9.SetAudioOptions(true, "libmp3lame", r9.info.sample_rate, r9.info.channels, r9.info.channel_layout, 128000); diff --git a/src/examples/Example.py b/src/examples/Example.py new file mode 100755 index 00000000..a5d483f6 --- /dev/null +++ b/src/examples/Example.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 + +""" + @file + @brief Python source file for openshot.py example + @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 . + + +# This can be run against an uninstalled build of libopenshot, just set the +# environment variable PYTHONPATH to the location of the Python bindings. +# +# For example: +# $ PYTHONPATH=../../build/src/bindings/python python3 Example.py +# +import openshot + + +# Create an FFmpegReader +r = openshot.FFmpegReader("sintel_trailer-720p.mp4") + +r.Open() # Open the reader +r.DisplayInfo() # Display metadata + +# Set up Writer +w = openshot.FFmpegWriter("pythonExample.mp4") + +w.SetAudioOptions(True, "libmp3lame", r.info.sample_rate, r.info.channels, r.info.channel_layout, 128000) +w.SetVideoOptions(True, "libx264", openshot.Fraction(30000, 1000), 1280, 720, + openshot.Fraction(1, 1), False, False, 3000000) + +w.info.metadata["title"] = "testtest" +w.info.metadata["artist"] = "aaa" +w.info.metadata["album"] = "bbb" +w.info.metadata["year"] = "2015" +w.info.metadata["description"] = "ddd" +w.info.metadata["comment"] = "eee" +w.info.metadata["comment"] = "comment" +w.info.metadata["copyright"] = "copyright OpenShot!" + +# Open the Writer +w.Open() + +# Grab 30 frames from Reader and encode to Writer +for frame in range(100): + f = r.GetFrame(frame) + w.WriteFrame(f) + +# Close out Reader & Writer +w.Close() +r.Close() + +print("Completed successfully!") diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5e18fcf3..0bfd56d8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -81,34 +81,15 @@ ENDIF (ImageMagick_FOUND) # Find FFmpeg libraries (used for video encoding / decoding) FIND_PACKAGE(FFmpeg REQUIRED) -# Include FFmpeg headers (needed for compile) -IF (AVCODEC_FOUND) - include_directories(${AVCODEC_INCLUDE_DIRS}) -ENDIF (AVCODEC_FOUND) -IF (AVDEVICE_FOUND) - include_directories(${AVDEVICE_INCLUDE_DIRS}) -ENDIF (AVDEVICE_FOUND) -IF (AVFORMAT_FOUND) - include_directories(${AVFORMAT_INCLUDE_DIRS}) -ENDIF (AVFORMAT_FOUND) -IF (AVFILTER_FOUND) - include_directories(${AVFILTER_INCLUDE_DIRS}) -ENDIF (AVFILTER_FOUND) -IF (AVUTIL_FOUND) - include_directories(${AVUTIL_INCLUDE_DIRS}) -ENDIF (AVUTIL_FOUND) -IF (POSTPROC_FOUND) - include_directories(${POSTPROC_INCLUDE_DIRS}) -ENDIF (POSTPROC_FOUND) -IF (SWSCALE_FOUND) - include_directories(${SWSCALE_INCLUDE_DIRS}) -ENDIF (SWSCALE_FOUND) -IF (SWRESAMPLE_FOUND) - include_directories(${SWRESAMPLE_INCLUDE_DIRS}) -ENDIF (SWRESAMPLE_FOUND) -IF (AVRESAMPLE_FOUND) - include_directories(${AVRESAMPLE_INCLUDE_DIRS}) -ENDIF (AVRESAMPLE_FOUND) +foreach(ffmpeg_comp AVCODEC AVDEVICE AVFORMAT AVFILTER AVUTIL POSTPROC SWSCALE SWRESAMPLE AVRESAMPLE) + if(${ffmpeg_comp}_FOUND) + # Include FFmpeg headers (needed for compile) + list(APPEND FF_INCLUDES ${${ffmpeg_comp}_INCLUDE_DIRS}) + add_definitions(${${ffmpeg_comp}_DEFINITIONS}) + endif() +endforeach() +list(REMOVE_DUPLICATES FF_INCLUDES) +include_directories(${FF_INCLUDES}) ################# LIBOPENSHOT-AUDIO ################### # Find JUCE-based openshot Audio libraries @@ -119,38 +100,17 @@ include_directories(${LIBOPENSHOT_AUDIO_INCLUDE_DIRS}) ################# QT5 ################### # Find QT5 libraries -find_package(Qt5Widgets REQUIRED) -find_package(Qt5Core REQUIRED) -find_package(Qt5Gui REQUIRED) -find_package(Qt5Multimedia REQUIRED) -find_package(Qt5MultimediaWidgets REQUIRED) - -# Include Qt headers (needed for compile) -include_directories(${Qt5Widgets_INCLUDE_DIRS}) -include_directories(${Qt5Core_INCLUDE_DIRS}) -include_directories(${Qt5Gui_INCLUDE_DIRS}) -include_directories(${Qt5Multimedia_INCLUDE_DIRS}) -include_directories(${Qt5MultimediaWidgets_INCLUDE_DIRS}) - -add_definitions(${Qt5Widgets_DEFINITIONS}) -add_definitions(${Qt5Core_DEFINITIONS}) -add_definitions(${Qt5Gui_DEFINITIONS}) -add_definitions(${Qt5Multimedia_DEFINITIONS}) -add_definitions(${Qt5MultimediaWidgets_DEFINITIONS}) - -SET(QT_LIBRARIES ${Qt5Widgets_LIBRARIES} - ${Qt5Core_LIBRARIES} - ${Qt5Gui_LIBRARIES} - ${Qt5Multimedia_LIBRARIES} - ${Qt5MultimediaWidgets_LIBRARIES}) - -# Set compiler flags for Qt -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS} ") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS} ") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Gui_EXECUTABLE_COMPILE_FLAGS} ") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Multimedia_EXECUTABLE_COMPILE_FLAGS} ") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5MultimediaWidgets_EXECUTABLE_COMPILE_FLAGS} ") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -ggdb ") +foreach(qt_lib Qt5Widgets Qt5Core Qt5Gui Qt5Multimedia Qt5MultimediaWidgets) + find_package(${qt_lib} REQUIRED) + # Header files + list(APPEND QT_INCLUDES ${${qt_lib}_INCLUDE_DIRS}) + # Compiler definitions + add_definitions(${${qt_lib}_DEFINITIONS}) + # Other CFLAGS + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${${qt_lib}_EXECUTABLE_COMPILE_FLAGS}") +endforeach() +list(REMOVE_DUPLICATES QT_INCLUDES) +include_directories(${QT_INCLUDES}) # Manually moc Qt files qt5_wrap_cpp(MOC_FILES ${QT_HEADER_FILES}) @@ -167,20 +127,20 @@ IF (ENABLE_BLACKMAGIC) ENDIF (BLACKMAGIC_FOUND) ENDIF (ENABLE_BLACKMAGIC) -################### OPENMP ##################### -# Check for OpenMP (used for multi-core processing) -FIND_PACKAGE(OpenMP) - -if (OPENMP_FOUND) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS} ") -endif(OPENMP_FOUND) ################### ZEROMQ ##################### # Find ZeroMQ library (used for socket communication & logging) + +# Some platforms package the header-only cppzmq C++ bindings separately, +# others (Ubuntu) bundle them in with libzmq itself +find_package(cppzmq QUIET) FIND_PACKAGE(ZMQ REQUIRED) # Include ZeroMQ headers (needed for compile) include_directories(${ZMQ_INCLUDE_DIRS}) +if (cppzmq_FOUND) + include_directories(${cppzmq_INCLUDE_DIRS}) +endif() ################### RESVG ##################### # Find resvg library (used for rendering svg files) @@ -202,7 +162,7 @@ endif(USE_SYSTEM_JSONCPP) IF (NOT DISABLE_TESTS) ############### SET TEST SOURCE FILES ################# - SET ( OPENSHOT_TEST_FILES tests.cpp + SET ( OPENSHOT_TEST_FILES Cache_Tests.cpp Clip_Tests.cpp Color_Tests.cpp @@ -220,6 +180,7 @@ IF (NOT DISABLE_TESTS) ################ 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} ) @@ -227,7 +188,24 @@ IF (NOT DISABLE_TESTS) # Link libraries to the new executable target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY}) - #################### MAKE TEST ###################### + ##### 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) -ENDIF (NOT DISABLE_TESTS) + list(APPEND OS_TEST_CMDS "'make os_test'") + + # Also hook up 'make test', if possible + # This requires CMake 3.11+, where the CMP0037 policy + # configured to 'NEW' mode will not reserve target names + # unless the corresponding feature is actually used + if (POLICY CMP0037) + cmake_policy(SET CMP0037 NEW) + 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'") + endif() + + string(CONCAT t ${OS_TEST_CMDS}) + message("\nTo run unit tests, use: ${t}") +endif() diff --git a/tests/Clip_Tests.cpp b/tests/Clip_Tests.cpp index 1b7475f4..5789780b 100644 --- a/tests/Clip_Tests.cpp +++ b/tests/Clip_Tests.cpp @@ -120,7 +120,7 @@ TEST(Clip_Properties) if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -132,7 +132,7 @@ TEST(Clip_Properties) catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } @@ -145,7 +145,7 @@ TEST(Clip_Properties) properties.c_str() + properties.size(), &root, &errors ); if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -157,7 +157,7 @@ TEST(Clip_Properties) catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } @@ -170,7 +170,7 @@ TEST(Clip_Properties) properties.c_str() + properties.size(), &root, &errors ); if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -181,7 +181,7 @@ TEST(Clip_Properties) catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } @@ -194,7 +194,7 @@ TEST(Clip_Properties) properties.c_str() + properties.size(), &root, &errors ); if (!success) // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + throw InvalidJSON("JSON could not be parsed (or is invalid)"); try { @@ -206,7 +206,7 @@ TEST(Clip_Properties) catch (const std::exception& e) { // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); } diff --git a/tests/FFmpegReader_Tests.cpp b/tests/FFmpegReader_Tests.cpp index 68aba4bb..4b808d83 100644 --- a/tests/FFmpegReader_Tests.cpp +++ b/tests/FFmpegReader_Tests.cpp @@ -97,10 +97,10 @@ TEST(FFmpegReader_Check_Video_File) int pixel_index = 112 * 4; // pixel 112 (4 bytes per pixel) // Check image properties on scanline 10, pixel 112 - CHECK_EQUAL(21, (int)pixels[pixel_index]); - CHECK_EQUAL(191, (int)pixels[pixel_index + 1]); - CHECK_EQUAL(0, (int)pixels[pixel_index + 2]); - CHECK_EQUAL(255, (int)pixels[pixel_index + 3]); + CHECK_CLOSE(21, (int)pixels[pixel_index], 5); + CHECK_CLOSE(191, (int)pixels[pixel_index + 1], 5); + CHECK_CLOSE(0, (int)pixels[pixel_index + 2], 5); + CHECK_CLOSE(255, (int)pixels[pixel_index + 3], 5); // Check pixel function CHECK_EQUAL(true, f->CheckPixel(10, 112, 21, 191, 0, 255, 5)); @@ -114,10 +114,10 @@ TEST(FFmpegReader_Check_Video_File) pixel_index = 112 * 4; // pixel 112 (4 bytes per pixel) // Check image properties on scanline 10, pixel 112 - CHECK_EQUAL(0, (int)pixels[pixel_index]); - CHECK_EQUAL(96, (int)pixels[pixel_index + 1]); - CHECK_EQUAL(188, (int)pixels[pixel_index + 2]); - CHECK_EQUAL(255, (int)pixels[pixel_index + 3]); + CHECK_CLOSE(0, (int)pixels[pixel_index], 5); + CHECK_CLOSE(96, (int)pixels[pixel_index + 1], 5); + CHECK_CLOSE(188, (int)pixels[pixel_index + 2], 5); + CHECK_CLOSE(255, (int)pixels[pixel_index + 3], 5); // Check pixel function CHECK_EQUAL(true, f->CheckPixel(10, 112, 0, 96, 188, 255, 5)); diff --git a/tests/FFmpegWriter_Tests.cpp b/tests/FFmpegWriter_Tests.cpp index 8cb10e15..1cab8043 100644 --- a/tests/FFmpegWriter_Tests.cpp +++ b/tests/FFmpegWriter_Tests.cpp @@ -75,8 +75,8 @@ TEST(FFmpegWriter_Test_Webm) int pixel_index = 112 * 4; // pixel 112 (4 bytes per pixel) // Check image properties on scanline 10, pixel 112 - CHECK_EQUAL(23, (int)pixels[pixel_index]); - CHECK_EQUAL(23, (int)pixels[pixel_index + 1]); - CHECK_EQUAL(23, (int)pixels[pixel_index + 2]); - CHECK_EQUAL(255, (int)pixels[pixel_index + 3]); + CHECK_CLOSE(23, (int)pixels[pixel_index], 5); + CHECK_CLOSE(23, (int)pixels[pixel_index + 1], 5); + CHECK_CLOSE(23, (int)pixels[pixel_index + 2], 5); + CHECK_CLOSE(255, (int)pixels[pixel_index + 3], 5); } diff --git a/tests/ImageWriter_Tests.cpp b/tests/ImageWriter_Tests.cpp index 4236b462..49202e96 100644 --- a/tests/ImageWriter_Tests.cpp +++ b/tests/ImageWriter_Tests.cpp @@ -75,9 +75,9 @@ TEST(ImageWriter_Test_Gif) int pixel_index = 230 * 4; // pixel 230 (4 bytes per pixel) // Check image properties - CHECK_EQUAL(20, (int)pixels[pixel_index]); - CHECK_EQUAL(18, (int)pixels[pixel_index + 1]); - CHECK_EQUAL(11, (int)pixels[pixel_index + 2]); - CHECK_EQUAL(255, (int)pixels[pixel_index + 3]); + CHECK_CLOSE(20, (int)pixels[pixel_index], 5); + CHECK_CLOSE(18, (int)pixels[pixel_index + 1], 5); + CHECK_CLOSE(11, (int)pixels[pixel_index + 2], 5); + CHECK_CLOSE(255, (int)pixels[pixel_index + 3], 5); } #endif diff --git a/tests/Timeline_Tests.cpp b/tests/Timeline_Tests.cpp index 0bb42b89..77a3bcbc 100644 --- a/tests/Timeline_Tests.cpp +++ b/tests/Timeline_Tests.cpp @@ -121,64 +121,64 @@ TEST(Timeline_Check_Two_Track_Video) int pixel_index = 230 * 4; // pixel 230 (4 bytes per pixel) // Check image properties - CHECK_EQUAL(21, (int)f->GetPixels(pixel_row)[pixel_index]); - CHECK_EQUAL(191, (int)f->GetPixels(pixel_row)[pixel_index + 1]); - CHECK_EQUAL(0, (int)f->GetPixels(pixel_row)[pixel_index + 2]); - CHECK_EQUAL(255, (int)f->GetPixels(pixel_row)[pixel_index + 3]); + CHECK_CLOSE(21, (int)f->GetPixels(pixel_row)[pixel_index], 5); + CHECK_CLOSE(191, (int)f->GetPixels(pixel_row)[pixel_index + 1], 5); + CHECK_CLOSE(0, (int)f->GetPixels(pixel_row)[pixel_index + 2], 5); + CHECK_CLOSE(255, (int)f->GetPixels(pixel_row)[pixel_index + 3], 5); // Get frame f = t.GetFrame(2); // Check image properties - CHECK_EQUAL(176, (int)f->GetPixels(pixel_row)[pixel_index]); - CHECK_EQUAL(0, (int)f->GetPixels(pixel_row)[pixel_index + 1]); - CHECK_EQUAL(186, (int)f->GetPixels(pixel_row)[pixel_index + 2]); - CHECK_EQUAL(255, (int)f->GetPixels(pixel_row)[pixel_index + 3]); + CHECK_CLOSE(176, (int)f->GetPixels(pixel_row)[pixel_index], 5); + CHECK_CLOSE(0, (int)f->GetPixels(pixel_row)[pixel_index + 1], 5); + CHECK_CLOSE(186, (int)f->GetPixels(pixel_row)[pixel_index + 2], 5); + CHECK_CLOSE(255, (int)f->GetPixels(pixel_row)[pixel_index + 3], 5); // Get frame f = t.GetFrame(3); // Check image properties - CHECK_EQUAL(23, (int)f->GetPixels(pixel_row)[pixel_index]); - CHECK_EQUAL(190, (int)f->GetPixels(pixel_row)[pixel_index + 1]); - CHECK_EQUAL(0, (int)f->GetPixels(pixel_row)[pixel_index + 2]); - CHECK_EQUAL(255, (int)f->GetPixels(pixel_row)[pixel_index + 3]); + CHECK_CLOSE(23, (int)f->GetPixels(pixel_row)[pixel_index], 5); + CHECK_CLOSE(190, (int)f->GetPixels(pixel_row)[pixel_index + 1], 5); + CHECK_CLOSE(0, (int)f->GetPixels(pixel_row)[pixel_index + 2], 5); + CHECK_CLOSE(255, (int)f->GetPixels(pixel_row)[pixel_index + 3], 5); // Get frame f = t.GetFrame(24); // Check image properties - CHECK_EQUAL(186, (int)f->GetPixels(pixel_row)[pixel_index]); - CHECK_EQUAL(106, (int)f->GetPixels(pixel_row)[pixel_index + 1]); - CHECK_EQUAL(0, (int)f->GetPixels(pixel_row)[pixel_index + 2]); - CHECK_EQUAL(255, (int)f->GetPixels(pixel_row)[pixel_index + 3]); + CHECK_CLOSE(186, (int)f->GetPixels(pixel_row)[pixel_index], 5); + CHECK_CLOSE(106, (int)f->GetPixels(pixel_row)[pixel_index + 1], 5); + CHECK_CLOSE(0, (int)f->GetPixels(pixel_row)[pixel_index + 2], 5); + CHECK_CLOSE(255, (int)f->GetPixels(pixel_row)[pixel_index + 3], 5); // Get frame f = t.GetFrame(5); // Check image properties - CHECK_EQUAL(23, (int)f->GetPixels(pixel_row)[pixel_index]); - CHECK_EQUAL(190, (int)f->GetPixels(pixel_row)[pixel_index + 1]); - CHECK_EQUAL(0, (int)f->GetPixels(pixel_row)[pixel_index + 2]); - CHECK_EQUAL(255, (int)f->GetPixels(pixel_row)[pixel_index + 3]); + CHECK_CLOSE(23, (int)f->GetPixels(pixel_row)[pixel_index], 5); + CHECK_CLOSE(190, (int)f->GetPixels(pixel_row)[pixel_index + 1], 5); + CHECK_CLOSE(0, (int)f->GetPixels(pixel_row)[pixel_index + 2], 5); + CHECK_CLOSE(255, (int)f->GetPixels(pixel_row)[pixel_index + 3], 5); // Get frame f = t.GetFrame(25); // Check image properties - CHECK_EQUAL(0, (int)f->GetPixels(pixel_row)[pixel_index]); - CHECK_EQUAL(94, (int)f->GetPixels(pixel_row)[pixel_index + 1]); - CHECK_EQUAL(186, (int)f->GetPixels(pixel_row)[pixel_index + 2]); - CHECK_EQUAL(255, (int)f->GetPixels(pixel_row)[pixel_index + 3]); + CHECK_CLOSE(0, (int)f->GetPixels(pixel_row)[pixel_index], 5); + CHECK_CLOSE(94, (int)f->GetPixels(pixel_row)[pixel_index + 1], 5); + CHECK_CLOSE(186, (int)f->GetPixels(pixel_row)[pixel_index + 2], 5); + CHECK_CLOSE(255, (int)f->GetPixels(pixel_row)[pixel_index + 3], 5); // Get frame f = t.GetFrame(4); // Check image properties - CHECK_EQUAL(176, (int)f->GetPixels(pixel_row)[pixel_index]); - CHECK_EQUAL(0, (int)f->GetPixels(pixel_row)[pixel_index + 1]); - CHECK_EQUAL(186, (int)f->GetPixels(pixel_row)[pixel_index + 2]); - CHECK_EQUAL(255, (int)f->GetPixels(pixel_row)[pixel_index + 3]); + CHECK_CLOSE(176, (int)f->GetPixels(pixel_row)[pixel_index], 5); + CHECK_CLOSE(0, (int)f->GetPixels(pixel_row)[pixel_index + 1], 5); + CHECK_CLOSE(186, (int)f->GetPixels(pixel_row)[pixel_index + 2], 5); + CHECK_CLOSE(255, (int)f->GetPixels(pixel_row)[pixel_index + 3], 5); // Close reader t.Close();