diff --git a/CMakeLists.txt b/CMakeLists.txt index 0809c04d..46c75816 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ # along with OpenShot Library. If not, see . ################################################################################ -cmake_minimum_required(VERSION 3.1...3.14 FATAL_ERROR) +cmake_minimum_required(VERSION 3.2...3.14 FATAL_ERROR) message("\ ----------------------------------------------------------------- @@ -56,7 +56,7 @@ STRING(REGEX REPLACE "\-.*$" "" VERSION_NUM "${PROJECT_VERSION_FULL}") PROJECT(libopenshot LANGUAGES C CXX VERSION ${VERSION_NUM}) message(" -Generating build files for OpenShot +Generating build files for OpenShot with CMake ${CMAKE_VERSION} Building ${PROJECT_NAME} (version ${PROJECT_VERSION}) SO/API/ABI Version: ${PROJECT_SO_VERSION} ") @@ -115,5 +115,6 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/html/ endif() ############# PROCESS tests/ DIRECTORY ############## -add_subdirectory(tests) - +if(NOT DISABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/cmake/Modules/FindFFmpeg.cmake b/cmake/Modules/FindFFmpeg.cmake index c4eb7ca3..b2409e05 100644 --- a/cmake/Modules/FindFFmpeg.cmake +++ b/cmake/Modules/FindFFmpeg.cmake @@ -1,42 +1,82 @@ # vim: ts=2 sw=2 -# - Try to find the required ffmpeg components(default: AVFORMAT, AVUTIL, AVCODEC) -# -# Once done this will define -# FFMPEG_FOUND - System has the all required components. -# FFMPEG_INCLUDE_DIRS - Include directory necessary for using the required components headers. -# FFMPEG_LIBRARIES - Link these to use the required ffmpeg components. -# FFMPEG_DEFINITIONS - Compiler switches required for using the required ffmpeg components. -# -# For each of the components it will additionally set. -# - AVCODEC -# - AVDEVICE -# - AVFORMAT -# - AVFILTER -# - AVUTIL -# - POSTPROC -# - SWSCALE -# - SWRESAMPLE -# - AVRESAMPLE -# the following variables will be defined -# _FOUND - System has -# _INCLUDE_DIRS - Include directory necessary for using the headers -# _LIBRARIES - Link these to use -# _DEFINITIONS - Compiler switches required for using -# _VERSION - The components version -# -# Copyright (c) 2006, Matthias Kretz, -# Copyright (c) 2008, Alexander Neundorf, -# Copyright (c) 2011, Michael Jansen, -# -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +#[=======================================================================[.rst: +FindFFmpeg +---------- +Try to find the requested ffmpeg components(default: avformat, avutil, avcodec) +IMPORTED targets +^^^^^^^^^^^^^^^^ + +This module defines :prop_tgt:`IMPORTED` targets ``FFmpeg:`` for +each found component (see below). + +Components +^^^^^^^^^^ + +The module recognizes the following components: + +:: + + avcodec - target FFmpeg::avcodec + avdevice - target FFmpeg::avdevice + avformat - target FFmpeg::avformat + avfilter - target FFmpeg::avfilter + avutil - target FFmpeg::avutil + postproc - target FFmpeg::postproc + swscale - target FFmpeg::swscale + swresample - target FFmpeg::swresample + avresample - target FFmpeg::avresample + +Result Variables +^^^^^^^^^^^^^^^^ + +This module defines the following variables: + +:: + + FFMPEG_FOUND - System has the all required components. + FFMPEG_INCLUDE_DIRS - Include directory necessary for using the required components headers. + FFMPEG_LIBRARIES - Link these to use the required ffmpeg components. + FFMPEG_DEFINITIONS - Compiler switches required for using the required ffmpeg components. + +For each component, ``_FOUND`` will be set if the component is available. + +For each ``_FOUND``, the following variables will be defined: + +:: + + _INCLUDE_DIRS - Include directory necessary for using the headers + _LIBRARIES - Link these to use + _DEFINITIONS - Compiler switches required for using + _VERSION - The components version + +Backwards compatibility +^^^^^^^^^^^^^^^^^^^^^^^ + +For compatibility with previous versions of this module, uppercase names +for FFmpeg and for all components are also recognized, and all-uppercase +versions of the cache variables are also created. + +Copyright (c) 2006, Matthias Kretz, +Copyright (c) 2008, Alexander Neundorf, +Copyright (c) 2011, Michael Jansen, +Copyright (c) 2019, FeRD (Frank Dana) + +Redistribution and use is allowed according to the terms of the BSD license. +For details see the accompanying COPYING-CMAKE-SCRIPTS file. +#]=======================================================================] include(FindPackageHandleStandardArgs) -# The default components were taken from a survey over other FindFFMPEG.cmake files -if (NOT FFmpeg_FIND_COMPONENTS) - set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL) +set(FFmpeg_ALL_COMPONENTS avcodec avdevice avformat avfilter avutil postproc swscale swresample avresample) + +# Default to all components, if not specified +if (FFMPEG_FIND_COMPONENTS AND NOT FFmpeg_FIND_COMPONENTS) + set(FFmpeg_FIND_COMPONENTS ${FFMPEG_FIND_COMPONENTS}) endif () +if (NOT FFmpeg_FIND_COMPONENTS) + set(FFmpeg_FIND_COMPONENTS ${FFmpeg_ALL_COMPONENTS}) +endif () + # ### Macro: set_component_found @@ -44,12 +84,14 @@ endif () # Marks the given component as found if both *_LIBRARIES AND *_INCLUDE_DIRS is present. # macro(set_component_found _component ) - if (${_component}_LIBRARIES AND ${_component}_INCLUDE_DIRS) - # message(STATUS " - ${_component} found.") - set(${_component}_FOUND TRUE) - else () - # message(STATUS " - ${_component} not found.") - endif () + if (${_component}_LIBRARIES AND ${_component}_INCLUDE_DIRS) + # message(STATUS "FFmpeg - ${_component} found.") + set(${_component}_FOUND TRUE) + else () + if (NOT FFmpeg_FIND_QUIETLY AND NOT FFMPEG_FIND_QUIETLY) + message(STATUS "FFmpeg - ${_component} not found.") + endif () + endif () endmacro() # @@ -60,102 +102,146 @@ endmacro() # macro(find_component _component _pkgconfig _library _header) - if (NOT WIN32) - # use pkg-config to get the directories and then use these values - # in the FIND_PATH() and FIND_LIBRARY() calls - find_package(PkgConfig) - if (PKG_CONFIG_FOUND) - pkg_check_modules(PC_${_component} ${_pkgconfig}) - endif () - endif (NOT WIN32) + if (NOT WIN32) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(PC_${_component} ${_pkgconfig}) + endif () + endif (NOT WIN32) - find_path(${_component}_INCLUDE_DIRS ${_header} - HINTS - /opt/ - /opt/include/ - ${PC_LIB${_component}_INCLUDEDIR} - ${PC_LIB${_component}_INCLUDE_DIRS} - $ENV{FFMPEGDIR}/include/ - $ENV{FFMPEGDIR}/include/ffmpeg/ - PATH_SUFFIXES - ffmpeg - ) + find_path(${_component}_INCLUDE_DIRS ${_header} + HINTS + /opt/ + /opt/include/ + ${PC_${_component}_INCLUDEDIR} + ${PC_${_component}_INCLUDE_DIRS} + $ENV{FFMPEGDIR}/include/ + $ENV{FFMPEGDIR}/include/ffmpeg/ + PATH_SUFFIXES + ffmpeg + ) - find_library(${_component}_LIBRARIES NAMES ${_library} - HINTS - ${PC_LIB${_component}_LIBDIR} - ${PC_LIB${_component}_LIBRARY_DIRS} - $ENV{FFMPEGDIR}/lib/ - $ENV{FFMPEGDIR}/lib/ffmpeg/ - $ENV{FFMPEGDIR}/bin/ - ) + find_library(${_component}_LIBRARIES NAMES ${_library} + HINTS + ${PC_${_component}_LIBDIR} + ${PC_${_component}_LIBRARY_DIRS} + $ENV{FFMPEGDIR}/lib/ + $ENV{FFMPEGDIR}/lib/ffmpeg/ + $ENV{FFMPEGDIR}/bin/ + ) - set(${_component}_DEFINITIONS ${PC_${_component}_CFLAGS_OTHER} CACHE STRING "The ${_component} CFLAGS.") - set(${_component}_VERSION ${PC_${_component}_VERSION} CACHE STRING "The ${_component} version number.") + set(${_component}_DEFINITIONS ${PC_${_component}_CFLAGS_OTHER} CACHE STRING "The ${_component} CFLAGS.") + set(${_component}_VERSION ${PC_${_component}_VERSION} CACHE STRING "The ${_component} version number.") - set_component_found(${_component}) + set_component_found(${_component}) - mark_as_advanced( - ${_component}_INCLUDE_DIRS - ${_component}_LIBRARIES - ${_component}_DEFINITIONS - ${_component}_VERSION) + mark_as_advanced( + ${_component}_INCLUDE_DIRS + ${_component}_LIBRARIES + ${_component}_DEFINITIONS + ${_component}_VERSION + ) endmacro() # Check for cached results. If there are skip the costly part. -if (NOT FFMPEG_LIBRARIES) +if (NOT FFmpeg_LIBRARIES) - # Check for all possible component. - find_component(AVCODEC libavcodec avcodec libavcodec/avcodec.h) - find_component(AVFORMAT libavformat avformat libavformat/avformat.h) - find_component(AVDEVICE libavdevice avdevice libavdevice/avdevice.h) - find_component(AVUTIL libavutil avutil libavutil/avutil.h) - find_component(AVFILTER libavfilter avfilter libavfilter/avfilter.h) - find_component(SWSCALE libswscale swscale libswscale/swscale.h) - find_component(POSTPROC libpostproc postproc libpostproc/postprocess.h) - find_component(SWRESAMPLE libswresample swresample libswresample/swresample.h) - find_component(AVRESAMPLE libavresample avresample libavresample/avresample.h) + # Check for all possible component. + find_component(avcodec libavcodec avcodec libavcodec/avcodec.h) + find_component(avdevice libavdevice avdevice libavdevice/avdevice.h) + find_component(avformat libavformat avformat libavformat/avformat.h) + find_component(avfilter libavfilter avfilter libavfilter/avfilter.h) + find_component(avutil libavutil avutil libavutil/avutil.h) + find_component(postproc libpostproc postproc libpostproc/postprocess.h) + find_component(swscale libswscale swscale libswscale/swscale.h) + find_component(swresample libswresample swresample libswresample/swresample.h) + find_component(avresample libavresample avresample libavresample/avresample.h) +else() + # Just set the noncached _FOUND vars for the components. + foreach(_component ${FFmpeg_ALL_COMPONENTS}) + set_component_found(${_component}) + endforeach () +endif() - # Check if the required components were found and add their stuff to the FFMPEG_* vars. - foreach (_component ${FFmpeg_FIND_COMPONENTS}) - if (${_component}_FOUND) - # message(STATUS "Required component ${_component} present.") - set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${${_component}_LIBRARIES}) - set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} ${${_component}_DEFINITIONS}) - list(APPEND FFMPEG_INCLUDE_DIRS ${${_component}_INCLUDE_DIRS}) - else () - # message(STATUS "Required component ${_component} missing.") - endif () - endforeach () - - # Build the include path with duplicates removed. - if (FFMPEG_INCLUDE_DIRS) - list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS) - endif () - - # cache the vars. - set(FFMPEG_INCLUDE_DIRS ${FFMPEG_INCLUDE_DIRS} CACHE STRING "The FFmpeg include directories." FORCE) - set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} CACHE STRING "The FFmpeg libraries." FORCE) - set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} CACHE STRING "The FFmpeg cflags." FORCE) - - mark_as_advanced(FFMPEG_INCLUDE_DIRS - FFMPEG_LIBRARIES - FFMPEG_DEFINITIONS) - -endif () - -# Now set the noncached _FOUND vars for the components. -foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE SWRESAMPLE AVRESAMPLE) - set_component_found(${_component}) +# Check if the requested components were found and add their stuff to the FFmpeg_* vars. +foreach (_component ${FFmpeg_FIND_COMPONENTS}) + string(TOLOWER "${_component}" _component) + if (${_component}_FOUND) + # message(STATUS "Requested component ${_component} present.") + set(FFmpeg_LIBRARIES ${FFmpeg_LIBRARIES} ${${_component}_LIBRARIES}) + set(FFmpeg_DEFINITIONS ${FFmpeg_DEFINITIONS} ${${_component}_DEFINITIONS}) + list(APPEND FFmpeg_INCLUDE_DIRS ${${_component}_INCLUDE_DIRS}) + else () + # message(STATUS "Requested component ${_component} missing.") + endif () endforeach () +# Build the include path with duplicates removed. +if (FFmpeg_INCLUDE_DIRS) + list(REMOVE_DUPLICATES FFmpeg_INCLUDE_DIRS) +endif () + +# cache the vars. +set(FFmpeg_INCLUDE_DIRS ${FFmpeg_INCLUDE_DIRS} CACHE STRING "The FFmpeg include directories." FORCE) +set(FFmpeg_LIBRARIES ${FFmpeg_LIBRARIES} CACHE STRING "The FFmpeg libraries." FORCE) +set(FFmpeg_DEFINITIONS ${FFmpeg_DEFINITIONS} CACHE STRING "The FFmpeg cflags." FORCE) + +mark_as_advanced(FFmpeg_INCLUDE_DIRS + FFmpeg_LIBRARIES + FFmpeg_DEFINITIONS) + +# Backwards compatibility +foreach(_suffix INCLUDE_DIRS LIBRARIES DEFINITIONS) + get_property(_help CACHE FFmpeg_${_suffix} PROPERTY HELPSTRING) + set(FFMPEG_${_suffix} ${FFmpeg_${_suffix}} CACHE STRING "${_help}" FORCE) + mark_as_advanced(FFMPEG_${_suffix}) +endforeach() +foreach(_component ${FFmpeg_ALL_COMPONENTS}) + if(${_component}_FOUND) + string(TOUPPER "${_component}" _uc_component) + set(${_uc_component}_FOUND TRUE) + foreach(_suffix INCLUDE_DIRS LIBRARIES DEFINITIONS VERSION) + get_property(_help CACHE ${_component}_${_suffix} PROPERTY HELPSTRING) + set(${_uc_component}_${_suffix} ${${_component}_${_suffix}} CACHE STRING "${_help}" FORCE) + mark_as_advanced(${_uc_component}_${_suffix}) + endforeach() + endif() +endforeach() + # Compile the list of required vars -set(_FFmpeg_REQUIRED_VARS FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIRS) +set(_FFmpeg_REQUIRED_VARS FFmpeg_LIBRARIES FFmpeg_INCLUDE_DIRS) foreach (_component ${FFmpeg_FIND_COMPONENTS}) - list(APPEND _FFmpeg_REQUIRED_VARS ${_component}_LIBRARIES ${_component}_INCLUDE_DIRS) + list(APPEND _FFmpeg_REQUIRED_VARS + ${_component}_LIBRARIES + ${_component}_INCLUDE_DIRS) endforeach () # Give a nice error message if some of the required vars are missing. find_package_handle_standard_args(FFmpeg DEFAULT_MSG ${_FFmpeg_REQUIRED_VARS}) + +# Export targets for each found component +foreach (_component ${FFmpeg_ALL_COMPONENTS}) + + if(${_component}_FOUND) + # message(STATUS "Creating IMPORTED target FFmpeg::${_component}") + + if(NOT TARGET FFmpeg::${_component}) + add_library(FFmpeg::${_component} UNKNOWN IMPORTED) + + set_target_properties(FFmpeg::${_component} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${${_component}_INCLUDE_DIRS}") + + set_property(TARGET FFmpeg::${_component} APPEND PROPERTY + INTERFACE_COMPILE_DEFINITIONS "${${_component}_DEFINITIONS}") + + set_property(TARGET FFmpeg::${_component} APPEND PROPERTY + IMPORTED_LOCATION "${${_component}_LIBRARIES}") + endif() + + endif() + +endforeach() diff --git a/include/AudioBufferSource.h b/include/AudioBufferSource.h index a16780c2..42e55c94 100644 --- a/include/AudioBufferSource.h +++ b/include/AudioBufferSource.h @@ -80,13 +80,13 @@ namespace openshot /// @brief Set the next read position of this source /// @param newPosition The sample # to start reading from - void setNextReadPosition (int64 newPosition); + void setNextReadPosition (juce::int64 newPosition); /// Get the next read position of this source - int64 getNextReadPosition() const; + juce::int64 getNextReadPosition() const; /// Get the total length (in samples) of this audio source - int64 getTotalLength() const; + juce::int64 getTotalLength() const; /// Determines if this audio source should repeat when it reaches the end bool isLooping() const; diff --git a/include/AudioReaderSource.h b/include/AudioReaderSource.h index edf900d2..33030adf 100644 --- a/include/AudioReaderSource.h +++ b/include/AudioReaderSource.h @@ -52,13 +52,13 @@ namespace openshot * * This allows any reader to play audio through JUCE (our audio framework). */ - class AudioReaderSource : public PositionableAudioSource + class AudioReaderSource : public juce::PositionableAudioSource { private: int position; /// The position of the audio source (index of buffer) bool repeat; /// Repeat the audio source when finished int size; /// The size of the internal buffer - AudioSampleBuffer *buffer; /// The audio sample buffer + juce::AudioSampleBuffer *buffer; /// The audio sample buffer int speed; /// The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...) ReaderBase *reader; /// The reader to pull samples from @@ -88,7 +88,7 @@ namespace openshot /// @brief Get the next block of audio samples /// @param info This struct informs us of which samples are needed next. - void getNextAudioBlock (const AudioSourceChannelInfo& info); + void getNextAudioBlock (const juce::AudioSourceChannelInfo& info); /// Prepare to play this audio source void prepareToPlay(int, double); @@ -98,13 +98,13 @@ namespace openshot /// @brief Set the next read position of this source /// @param newPosition The sample # to start reading from - void setNextReadPosition (int64 newPosition); + void setNextReadPosition (juce::int64 newPosition); /// Get the next read position of this source - int64 getNextReadPosition() const; + juce::int64 getNextReadPosition() const; /// Get the total length (in samples) of this audio source - int64 getTotalLength() const; + juce::int64 getTotalLength() const; /// Determines if this audio source should repeat when it reaches the end bool isLooping() const; @@ -114,7 +114,7 @@ namespace openshot void setLooping (bool shouldLoop); /// Update the internal buffer used by this source - void setBuffer (AudioSampleBuffer *audio_buffer); + void setBuffer (juce::AudioSampleBuffer *audio_buffer); const ReaderInfo & getReaderInfo() const { return reader->info; } diff --git a/include/CacheBase.h b/include/CacheBase.h index 65ce1377..aad65a84 100644 --- a/include/CacheBase.h +++ b/include/CacheBase.h @@ -53,7 +53,7 @@ namespace openshot { int64_t max_bytes; ///< This is the max number of bytes to cache (0 = no limit) /// Section lock for multiple threads - CriticalSection *cacheCriticalSection; + juce::CriticalSection *cacheCriticalSection; public: diff --git a/include/Clip.h b/include/Clip.h index 76bfb923..4fdccea9 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -100,7 +100,7 @@ namespace openshot { class Clip : public openshot::ClipBase { protected: /// Section lock for multiple threads - CriticalSection getFrameCriticalSection; + juce::CriticalSection getFrameCriticalSection; private: bool waveform; ///< Should a waveform be used instead of the clip's image @@ -148,7 +148,7 @@ namespace openshot { openshot::GravityType gravity; ///< The gravity of a clip determines where it snaps to its parent openshot::ScaleType scale; ///< The scale determines how a clip should be resized to fit its parent openshot::AnchorType anchor; ///< The anchor determines what parent a clip should snap to - openshot::FrameDisplayType display; ///< The format to display the frame number (if any) + openshot::FrameDisplayType display; ///< The format to display the frame number (if any) openshot::VolumeMixType mixing; ///< What strategy should be followed when mixing audio with other clips /// Default Constructor diff --git a/include/Frame.h b/include/Frame.h index e1997485..b9b989a5 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -119,8 +119,8 @@ namespace openshot std::shared_ptr wave_image; std::shared_ptr audio; std::shared_ptr previewApp; - CriticalSection addingImageSection; - CriticalSection addingAudioSection; + juce::CriticalSection addingImageSection; + juce::CriticalSection addingAudioSection; const unsigned char *qbuffer; openshot::Fraction pixel_ratio; int channels; diff --git a/include/ReaderBase.h b/include/ReaderBase.h index 4e1cff25..26769338 100644 --- a/include/ReaderBase.h +++ b/include/ReaderBase.h @@ -98,8 +98,8 @@ namespace openshot { protected: /// Section lock for multiple threads - CriticalSection getFrameCriticalSection; - CriticalSection processingCriticalSection; + juce::CriticalSection getFrameCriticalSection; + juce::CriticalSection processingCriticalSection; openshot::ClipBase* parent; public: diff --git a/include/ZmqLogger.h b/include/ZmqLogger.h index 2dc1a0cb..c165299e 100644 --- a/include/ZmqLogger.h +++ b/include/ZmqLogger.h @@ -55,7 +55,7 @@ namespace openshot { */ class ZmqLogger { private: - CriticalSection loggerCriticalSection; + juce::CriticalSection loggerCriticalSection; std::string connection; // Logfile related vars diff --git a/src/AudioBufferSource.cpp b/src/AudioBufferSource.cpp index 912d2552..46b04916 100644 --- a/src/AudioBufferSource.cpp +++ b/src/AudioBufferSource.cpp @@ -34,7 +34,7 @@ using namespace std; using namespace openshot; // Default constructor -AudioBufferSource::AudioBufferSource(AudioSampleBuffer *audio_buffer) +AudioBufferSource::AudioBufferSource(juce::AudioSampleBuffer *audio_buffer) : position(0), start(0), repeat(false), buffer(audio_buffer) { } @@ -46,7 +46,7 @@ AudioBufferSource::~AudioBufferSource() }; // Get the next block of audio samples -void AudioBufferSource::getNextAudioBlock (const AudioSourceChannelInfo& info) +void AudioBufferSource::getNextAudioBlock (const juce::AudioSourceChannelInfo& info) { int buffer_samples = buffer->getNumSamples(); int buffer_channels = buffer->getNumChannels(); @@ -98,7 +98,7 @@ void AudioBufferSource::prepareToPlay(int, double) { } void AudioBufferSource::releaseResources() { } // Set the next read position of this source -void AudioBufferSource::setNextReadPosition (int64 newPosition) +void AudioBufferSource::setNextReadPosition (juce::int64 newPosition) { // set position (if the new position is in range) if (newPosition >= 0 && newPosition < buffer->getNumSamples()) @@ -106,14 +106,14 @@ void AudioBufferSource::setNextReadPosition (int64 newPosition) } // Get the next read position of this source -int64 AudioBufferSource::getNextReadPosition() const +juce::int64 AudioBufferSource::getNextReadPosition() const { // return the next read position return position; } // Get the total length (in samples) of this audio source -int64 AudioBufferSource::getTotalLength() const +juce::int64 AudioBufferSource::getTotalLength() const { // Get the length return buffer->getNumSamples(); @@ -134,7 +134,7 @@ void AudioBufferSource::setLooping (bool shouldLoop) } // Use a different AudioSampleBuffer for this source -void AudioBufferSource::setBuffer (AudioSampleBuffer *audio_buffer) +void AudioBufferSource::setBuffer (juce::AudioSampleBuffer *audio_buffer) { buffer = audio_buffer; setNextReadPosition(0); diff --git a/src/AudioReaderSource.cpp b/src/AudioReaderSource.cpp index 8195d03b..41c0b3f6 100644 --- a/src/AudioReaderSource.cpp +++ b/src/AudioReaderSource.cpp @@ -152,7 +152,7 @@ juce::AudioSampleBuffer* AudioReaderSource::reverse_buffer(juce::AudioSampleBuff ZmqLogger::Instance()->AppendDebugMethod("AudioReaderSource::reverse_buffer", "number_of_samples", number_of_samples, "channels", channels); // Reverse array (create new buffer to hold the reversed version) - AudioSampleBuffer *reversed = new juce::AudioSampleBuffer(channels, number_of_samples); + juce::AudioSampleBuffer *reversed = new juce::AudioSampleBuffer(channels, number_of_samples); reversed->clear(); for (int channel = 0; channel < channels; channel++) @@ -177,7 +177,7 @@ juce::AudioSampleBuffer* AudioReaderSource::reverse_buffer(juce::AudioSampleBuff } // Get the next block of audio samples -void AudioReaderSource::getNextAudioBlock(const AudioSourceChannelInfo& info) +void AudioReaderSource::getNextAudioBlock(const juce::AudioSourceChannelInfo& info) { int buffer_samples = buffer->getNumSamples(); int buffer_channels = buffer->getNumChannels(); @@ -248,7 +248,7 @@ void AudioReaderSource::prepareToPlay(int, double) { } void AudioReaderSource::releaseResources() { } // Set the next read position of this source -void AudioReaderSource::setNextReadPosition (int64 newPosition) +void AudioReaderSource::setNextReadPosition (juce::int64 newPosition) { // set position (if the new position is in range) if (newPosition >= 0 && newPosition < buffer->getNumSamples()) @@ -256,14 +256,14 @@ void AudioReaderSource::setNextReadPosition (int64 newPosition) } // Get the next read position of this source -int64 AudioReaderSource::getNextReadPosition() const +juce::int64 AudioReaderSource::getNextReadPosition() const { // return the next read position return position; } // Get the total length (in samples) of this audio source -int64 AudioReaderSource::getTotalLength() const +juce::int64 AudioReaderSource::getTotalLength() const { // Get the length if (reader) @@ -287,7 +287,7 @@ void AudioReaderSource::setLooping (bool shouldLoop) } // Update the internal buffer used by this source -void AudioReaderSource::setBuffer (AudioSampleBuffer *audio_buffer) +void AudioReaderSource::setBuffer (juce::AudioSampleBuffer *audio_buffer) { buffer = audio_buffer; setNextReadPosition(0); diff --git a/src/AudioResampler.cpp b/src/AudioResampler.cpp index cacd7e5b..145f5d91 100644 --- a/src/AudioResampler.cpp +++ b/src/AudioResampler.cpp @@ -49,10 +49,10 @@ AudioResampler::AudioResampler() buffer_source = new AudioBufferSource(buffer); // Init resampling source - resample_source = new ResamplingAudioSource(buffer_source, false, 2); + resample_source = new juce::ResamplingAudioSource(buffer_source, false, 2); // Init resampled buffer - resampled_buffer = new AudioSampleBuffer(2, 1); + resampled_buffer = new juce::AudioSampleBuffer(2, 1); resampled_buffer->clear(); // Init callback buffer diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 398d6154..566fa9da 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,13 +29,11 @@ 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) +option(ENABLE_IWYU "Enable 'Include What You Use' scanner" OFF) ################ WINDOWS ################## # Set some compiler options for Windows @@ -84,20 +82,6 @@ IF (ImageMagick_FOUND) ENDIF (ImageMagick_FOUND) -################### FFMPEG ##################### -# Find FFmpeg libraries (used for video encoding / decoding) -FIND_PACKAGE(FFmpeg REQUIRED) - -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 FIND_PACKAGE(OpenShotAudio 0.1.8 REQUIRED) @@ -181,6 +165,21 @@ endif(USE_SYSTEM_JSONCPP) #set(PROFILER "/usr/lib/libprofiler.so.0.3.2") #set(PROFILER "/usr/lib/libtcmalloc.so.4") +if(ENABLE_IWYU) + find_program(IWYU_PATH NAMES "iwyu" + DOC "include-what-you-use source code scanner executable") + if(IWYU_PATH) + if(IWYU_OPTS) + separate_arguments(IWYU_OPTS) + list(APPEND _iwyu_cmd ${IWYU_PATH} "-Xiwyu" ${IWYU_OPTS}) + endif() + set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${_iwyu_cmd}) + else() + set(ENABLE_IWYU FALSE) + endif() +endif() +add_feature_info("IWYU (include-what-you-use)" ENABLE_IWYU "Scan all source files with 'iwyu'") + #### GET LIST OF EFFECT FILES #### FILE(GLOB EFFECT_FILES "${CMAKE_CURRENT_SOURCE_DIR}/effects/*.cpp") @@ -273,6 +272,17 @@ set_target_properties(openshot INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" ) + +################### FFMPEG ##################### +# Find FFmpeg libraries (used for video encoding / decoding) +FIND_PACKAGE(FFmpeg REQUIRED COMPONENTS avcodec avdevice avformat avutil swscale) + +foreach(ff_comp avcodec avdevice avformat avfilter avutil postproc swscale swresample avresample) + if(TARGET FFmpeg::${ff_comp}) + target_link_libraries(openshot PUBLIC FFmpeg::${ff_comp}) + endif() +endforeach() + ################### OPENMP ##################### # Check for OpenMP (used for multi-core processing) @@ -291,10 +301,10 @@ endif() target_link_libraries(openshot PUBLIC OpenMP::OpenMP_CXX) + ############### LINK LIBRARY ################# SET ( REQUIRED_LIBRARIES ${LIBOPENSHOT_AUDIO_LIBRARIES} - ${FF_LIBRARIES} ${QT_LIBRARIES} ${PROFILER} ${JSONCPP_LIBRARY} diff --git a/src/Clip.cpp b/src/Clip.cpp index 30b28885..e3f33a18 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -367,7 +367,7 @@ void Clip::reverse_buffer(juce::AudioSampleBuffer* buffer) int channels = buffer->getNumChannels(); // Reverse array (create new buffer to hold the reversed version) - AudioSampleBuffer *reversed = new juce::AudioSampleBuffer(channels, number_of_samples); + juce::AudioSampleBuffer *reversed = new juce::AudioSampleBuffer(channels, number_of_samples); reversed->clear(); for (int channel = 0; channel < channels; channel++) @@ -399,7 +399,7 @@ void Clip::get_time_mapped_frame(std::shared_ptr frame, int64_t frame_num // Check for a valid time map curve if (time.Values.size() > 1) { - const GenericScopedLock lock(getFrameCriticalSection); + const GenericScopedLock lock(getFrameCriticalSection); // create buffer and resampler juce::AudioSampleBuffer *samples = NULL; @@ -423,7 +423,7 @@ void Clip::get_time_mapped_frame(std::shared_ptr frame, int64_t frame_num if (time.GetRepeatFraction(frame_number).den > 1) { // SLOWING DOWN AUDIO // Resample data, and return new buffer pointer - AudioSampleBuffer *resampled_buffer = NULL; + juce::AudioSampleBuffer *resampled_buffer = NULL; int resampled_buffer_size = 0; // SLOW DOWN audio (split audio) @@ -482,7 +482,7 @@ void Clip::get_time_mapped_frame(std::shared_ptr frame, int64_t frame_num delta_frame <= new_frame_number; delta_frame++) { // buffer to hold detal samples int number_of_delta_samples = GetOrCreateFrame(delta_frame)->GetAudioSamplesCount(); - AudioSampleBuffer *delta_samples = new juce::AudioSampleBuffer(channels, + juce::AudioSampleBuffer *delta_samples = new juce::AudioSampleBuffer(channels, number_of_delta_samples); delta_samples->clear(); @@ -526,7 +526,7 @@ void Clip::get_time_mapped_frame(std::shared_ptr frame, int64_t frame_num delta_frame >= new_frame_number; delta_frame--) { // buffer to hold delta samples int number_of_delta_samples = GetOrCreateFrame(delta_frame)->GetAudioSamplesCount(); - AudioSampleBuffer *delta_samples = new juce::AudioSampleBuffer(channels, + juce::AudioSampleBuffer *delta_samples = new juce::AudioSampleBuffer(channels, number_of_delta_samples); delta_samples->clear(); @@ -557,7 +557,7 @@ void Clip::get_time_mapped_frame(std::shared_ptr frame, int64_t frame_num resampler->SetBuffer(samples, float(start) / float(number_of_samples)); // Resample data, and return new buffer pointer - AudioSampleBuffer *buffer = resampler->GetResampledBuffer(); + juce::AudioSampleBuffer *buffer = resampler->GetResampledBuffer(); int resampled_buffer_size = buffer->getNumSamples(); // Add the newly resized audio samples to the current frame diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 84915a56..5865d3bb 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -172,59 +172,50 @@ 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 ( (strcmp(codec.c_str(),"h264_vaapi") == 0)) { +#if defined(__linux__) + if (strstr(codec.c_str(), "_vaapi") != NULL) { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; hw_en_supported = 1; hw_en_av_pix_fmt = AV_PIX_FMT_VAAPI; hw_en_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + } else if (strstr(codec.c_str(), "_nvenc") != NULL) { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 1; + hw_en_supported = 1; + hw_en_av_pix_fmt = AV_PIX_FMT_CUDA; + hw_en_av_device_type = AV_HWDEVICE_TYPE_CUDA; + } else { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 0; + hw_en_supported = 0; } - else { - if ( (strcmp(codec.c_str(),"h264_nvenc") == 0)) { - new_codec = avcodec_find_encoder_by_name(codec.c_str()); - hw_en_on = 1; - hw_en_supported = 1; - hw_en_av_pix_fmt = AV_PIX_FMT_CUDA; - hw_en_av_device_type = AV_HWDEVICE_TYPE_CUDA; - } - else { - new_codec = avcodec_find_encoder_by_name(codec.c_str()); - hw_en_on = 0; - hw_en_supported = 0; - } - } - #elif defined(_WIN32) - if ( (strcmp(codec.c_str(),"h264_dxva2") == 0)) { +#elif defined(_WIN32) + if (strstr(codec.c_str(), "_dxva2") != NULL) { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; hw_en_supported = 1; hw_en_av_pix_fmt = AV_PIX_FMT_DXVA2_VLD; hw_en_av_device_type = AV_HWDEVICE_TYPE_DXVA2; + } else if (strstr(codec.c_str(), "_nvenc") != NULL) { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 1; + hw_en_supported = 1; + hw_en_av_pix_fmt = AV_PIX_FMT_CUDA; + hw_en_av_device_type = AV_HWDEVICE_TYPE_CUDA; + } else { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 0; + hw_en_supported = 0; } - else { - if ( (strcmp(codec.c_str(),"h264_nvenc") == 0)) { - new_codec = avcodec_find_encoder_by_name(codec.c_str()); - hw_en_on = 1; - hw_en_supported = 1; - hw_en_av_pix_fmt = AV_PIX_FMT_CUDA; - hw_en_av_device_type = AV_HWDEVICE_TYPE_CUDA; - } - else { - new_codec = avcodec_find_encoder_by_name(codec.c_str()); - hw_en_on = 0; - hw_en_supported = 0; - } - } - #elif defined(__APPLE__) - if ( (strcmp(codec.c_str(),"h264_videotoolbox") == 0)) { +#elif defined(__APPLE__) + if (strstr(codec.c_str(), "_videotoolbox") != NULL) { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; hw_en_supported = 1; hw_en_av_pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX; hw_en_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; - } - else { + } else { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 0; hw_en_supported = 0; @@ -350,7 +341,7 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va // Was option found? if (option || (name == "g" || name == "qmin" || name == "qmax" || name == "max_b_frames" || name == "mb_decision" || name == "level" || name == "profile" || name == "slices" || name == "rc_min_rate" || name == "rc_max_rate" || - name == "crf")) { + name == "crf" || name == "cqp")) { // Check for specific named options if (name == "g") // Set gop_size @@ -396,7 +387,57 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va // Buffer size convert >> c->rc_buffer_size; - else if (name == "crf") { + else if (name == "cqp") { + // encode quality and special settings like lossless + // This might be better in an extra methods as more options + // and way to set quality are possible + #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) + #if IS_FFMPEG_3_2 + if (hw_en_on) { + av_opt_set_int(c->priv_data, "qp", min(stoi(value),63), 0); // 0-63 + } else + #endif + { + switch (c->codec_id) { + #if (LIBAVCODEC_VERSION_MAJOR >= 58) + case AV_CODEC_ID_AV1 : + c->bit_rate = 0; + av_opt_set_int(c->priv_data, "qp", min(stoi(value),63), 0); // 0-63 + break; + #endif + case AV_CODEC_ID_VP8 : + c->bit_rate = 10000000; + av_opt_set_int(c->priv_data, "qp", max(min(stoi(value), 63), 4), 0); // 4-63 + break; + case AV_CODEC_ID_VP9 : + c->bit_rate = 0; // Must be zero! + av_opt_set_int(c->priv_data, "qp", min(stoi(value), 63), 0); // 0-63 + if (stoi(value) == 0) { + av_opt_set(c->priv_data, "preset", "veryslow", 0); + av_opt_set_int(c->priv_data, "lossless", 1, 0); + } + break; + case AV_CODEC_ID_H264 : + av_opt_set_int(c->priv_data, "qp", min(stoi(value), 51), 0); // 0-51 + if (stoi(value) == 0) { + av_opt_set(c->priv_data, "preset", "veryslow", 0); + } + break; + case AV_CODEC_ID_H265 : + av_opt_set_int(c->priv_data, "qp", min(stoi(value), 51), 0); // 0-51 + if (stoi(value) == 0) { + av_opt_set(c->priv_data, "preset", "veryslow", 0); + av_opt_set_int(c->priv_data, "lossless", 1, 0); + } + break; + default: + // For all other codecs assume a range of 0-63 + av_opt_set_int(c->priv_data, "qp", min(stoi(value), 63), 0); // 0-63 + c->bit_rate = 0; + } + } + #endif + } else if (name == "crf") { // encode quality and special settings like lossless // This might be better in an extra methods as more options // and way to set quality are possible @@ -480,7 +521,7 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va // write selfcontained fragmented file, minimum length of the fragment 8 sec; only for MOV, MP4 av_dict_set(&mux_dict, "movflags", "frag_keyframe", 0); av_dict_set(&mux_dict, "min_frag_duration", "8000000", 0); - } + } } else { throw InvalidOptions("The option is not valid for this codec.", path); } @@ -543,6 +584,7 @@ void FFmpegWriter::WriteHeader() { // Write the stream header if (avformat_write_header(oc, &dict) != 0) { + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::WriteHeader (avformat_write_header)"); throw InvalidFile("Could not write header to file.", path); }; @@ -1241,7 +1283,7 @@ void FFmpegWriter::open_audio(AVFormatContext *oc, AVStream *st) { // Open the codec if (avcodec_open2(audio_codec, codec, &opts) < 0) - throw InvalidCodec("Could not open codec", path); + throw InvalidCodec("Could not open audio codec", path); AV_COPY_PARAMS_FROM_CONTEXT(st, audio_codec); // Free options @@ -1330,7 +1372,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) { #elif defined(__APPLE__) if( adapter_ptr != NULL ) { #endif - ZmqLogger::Instance()->AppendDebugMethod("Encode Device present using device"); + ZmqLogger::Instance()->AppendDebugMethod("Encode Device present using device", "adapter", adapter_num); } else { adapter_ptr = NULL; // use default @@ -1361,23 +1403,58 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) { #if IS_FFMPEG_3_2 if (hw_en_on && hw_en_supported) { - video_codec->max_b_frames = 0; // At least this GPU doesn't support b-frames video_codec->pix_fmt = hw_en_av_pix_fmt; - video_codec->profile = FF_PROFILE_H264_BASELINE | FF_PROFILE_H264_CONSTRAINED; - av_opt_set(video_codec->priv_data,"preset","slow",0); - av_opt_set(video_codec->priv_data,"tune","zerolatency",0); - av_opt_set(video_codec->priv_data, "vprofile", "baseline", AV_OPT_SEARCH_CHILDREN); + + // for the list of possible options, see the list of codec-specific options: + // e.g. ffmpeg -h encoder=h264_vaapi or ffmpeg -h encoder=hevc_vaapi + // and "man ffmpeg-codecs" + + // For VAAPI, it is safer to explicitly set rc_mode instead of relying on auto-selection + // which is ffmpeg version-specific. + if (hw_en_av_pix_fmt == AV_PIX_FMT_VAAPI) { + int64_t qp; + if (av_opt_get_int(video_codec->priv_data, "qp", 0, &qp) != 0 || qp == 0) { + // unless "qp" was set for CQP, switch to VBR RC mode + av_opt_set(video_codec->priv_data, "rc_mode", "VBR", 0); + + // In the current state (ffmpeg-4.2-4 libva-mesa-driver-19.1.5-1) to use VBR, + // one has to specify both bit_rate and maxrate, otherwise a small low quality file is generated on Intel iGPU). + video_codec->rc_max_rate = video_codec->bit_rate; + } + } + + switch (video_codec->codec_id) { + case AV_CODEC_ID_H264: + video_codec->max_b_frames = 0; // At least this GPU doesn't support b-frames + video_codec->profile = FF_PROFILE_H264_BASELINE | FF_PROFILE_H264_CONSTRAINED; + av_opt_set(video_codec->priv_data, "preset", "slow", 0); + av_opt_set(video_codec->priv_data, "tune", "zerolatency", 0); + av_opt_set(video_codec->priv_data, "vprofile", "baseline", AV_OPT_SEARCH_CHILDREN); + break; + case AV_CODEC_ID_HEVC: + // tested to work with defaults + break; + case AV_CODEC_ID_VP9: + // tested to work with defaults + break; + default: + ZmqLogger::Instance()->AppendDebugMethod("No codec-specific options defined for this codec. HW encoding may fail", + "codec_id", video_codec->codec_id); + break; + } + // set hw_frames_ctx for encoder's AVCodecContext int err; if ((err = set_hwframe_ctx(video_codec, hw_device_ctx, info.width, info.height)) < 0) { - fprintf(stderr, "Failed to set hwframe context.\n"); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_video (set_hwframe_ctx) ERROR faled to set hwframe context", + "width", info.width, "height", info.height, av_err2str(err), -1); } } #endif /* open the codec */ if (avcodec_open2(video_codec, codec, &opts) < 0) - throw InvalidCodec("Could not open codec", path); + throw InvalidCodec("Could not open video codec", path); AV_COPY_PARAMS_FROM_CONTEXT(st, video_codec); // Free options diff --git a/src/Frame.cpp b/src/Frame.cpp index dcc140e5..475d5c28 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -340,7 +340,7 @@ float* Frame::GetAudioSamples(int channel) float* Frame::GetPlanarAudioSamples(int new_sample_rate, AudioResampler* resampler, int* sample_count) { float *output = NULL; - AudioSampleBuffer *buffer(audio.get()); + juce::AudioSampleBuffer *buffer(audio.get()); int num_of_channels = audio->getNumChannels(); int num_of_samples = GetAudioSamplesCount(); @@ -386,7 +386,7 @@ float* Frame::GetPlanarAudioSamples(int new_sample_rate, AudioResampler* resampl float* Frame::GetInterleavedAudioSamples(int new_sample_rate, AudioResampler* resampler, int* sample_count) { float *output = NULL; - AudioSampleBuffer *buffer(audio.get()); + juce::AudioSampleBuffer *buffer(audio.get()); int num_of_channels = audio->getNumChannels(); int num_of_samples = GetAudioSamplesCount(); @@ -430,7 +430,7 @@ float* Frame::GetInterleavedAudioSamples(int new_sample_rate, AudioResampler* re // Get number of audio channels int Frame::GetAudioChannelsCount() { - const GenericScopedLock lock(addingAudioSection); + const GenericScopedLock lock(addingAudioSection); if (audio) return audio->getNumChannels(); else @@ -440,7 +440,7 @@ int Frame::GetAudioChannelsCount() // Get number of audio samples int Frame::GetAudioSamplesCount() { - const GenericScopedLock lock(addingAudioSection); + const GenericScopedLock lock(addingAudioSection); return max_audio_sample; } @@ -735,7 +735,7 @@ void Frame::AddColor(int new_width, int new_height, std::string new_color) color = new_color; // Create new image object, and fill with pixel data - const GenericScopedLock lock(addingImageSection); + const GenericScopedLock lock(addingImageSection); #pragma omp critical (AddImage) { image = std::shared_ptr(new QImage(new_width, new_height, QImage::Format_RGBA8888)); @@ -753,7 +753,7 @@ void Frame::AddColor(int new_width, int new_height, std::string new_color) void Frame::AddImage(int new_width, int new_height, int bytes_per_pixel, QImage::Format type, const unsigned char *pixels_) { // Create new buffer - const GenericScopedLock lock(addingImageSection); + const GenericScopedLock lock(addingImageSection); int buffer_size = new_width * new_height * bytes_per_pixel; qbuffer = new unsigned char[buffer_size](); @@ -784,7 +784,7 @@ void Frame::AddImage(std::shared_ptr new_image) return; // assign image data - const GenericScopedLock lock(addingImageSection); + const GenericScopedLock lock(addingImageSection); #pragma omp critical (AddImage) { image = new_image; @@ -823,7 +823,7 @@ void Frame::AddImage(std::shared_ptr new_image, bool only_odd_lines) return; // Get the frame's image - const GenericScopedLock lock(addingImageSection); + const GenericScopedLock lock(addingImageSection); #pragma omp critical (AddImage) { const unsigned char *pixels = image->bits(); @@ -851,7 +851,7 @@ void Frame::AddImage(std::shared_ptr new_image, bool only_odd_lines) // Resize audio container to hold more (or less) samples and channels void Frame::ResizeAudio(int channels, int length, int rate, ChannelLayout layout) { - const GenericScopedLock lock(addingAudioSection); + const GenericScopedLock lock(addingAudioSection); // Resize JUCE audio buffer audio->setSize(channels, length, true, true, false); @@ -864,7 +864,7 @@ void Frame::ResizeAudio(int channels, int length, int rate, ChannelLayout layout // Add audio samples to a specific channel void Frame::AddAudio(bool replaceSamples, int destChannel, int destStartSample, const float* source, int numSamples, float gainToApplyToSource = 1.0f) { - const GenericScopedLock lock(addingAudioSection); + const GenericScopedLock lock(addingAudioSection); #pragma omp critical (adding_audio) { // Clamp starting sample to 0 @@ -895,7 +895,7 @@ void Frame::AddAudio(bool replaceSamples, int destChannel, int destStartSample, // Apply gain ramp (i.e. fading volume) void Frame::ApplyGainRamp(int destChannel, int destStartSample, int numSamples, float initial_gain = 0.0f, float final_gain = 1.0f) { - const GenericScopedLock lock(addingAudioSection); + const GenericScopedLock lock(addingAudioSection); // Apply gain ramp audio->applyGainRamp(destChannel, destStartSample, numSamples, initial_gain, final_gain); @@ -970,7 +970,7 @@ void Frame::Play() if (!GetAudioSamplesCount()) return; - AudioDeviceManager deviceManager; + juce::AudioDeviceManager deviceManager; String error = deviceManager.initialise (0, /* number of input channels */ 2, /* number of output channels */ 0, /* no XML settings.. */ @@ -981,14 +981,14 @@ void Frame::Play() cout << "Error on initialise(): " << error.toStdString() << endl; } - AudioSourcePlayer audioSourcePlayer; + juce::AudioSourcePlayer audioSourcePlayer; deviceManager.addAudioCallback (&audioSourcePlayer); ScopedPointer my_source; my_source = new AudioBufferSource(audio.get()); // Create TimeSliceThread for audio buffering - TimeSliceThread my_thread("Audio buffer thread"); + juce::TimeSliceThread my_thread("Audio buffer thread"); // Start thread my_thread.startThread(); @@ -1004,7 +1004,7 @@ void Frame::Play() // Create MIXER - MixerAudioSource mixer; + juce::MixerAudioSource mixer; mixer.addInputSource(&transport1, false); audioSourcePlayer.setSource (&mixer); @@ -1047,7 +1047,7 @@ void Frame::cleanUpBuffer(void *info) // Add audio silence void Frame::AddAudioSilence(int numSamples) { - const GenericScopedLock lock(addingAudioSection); + const GenericScopedLock lock(addingAudioSection); // Resize audio container audio->setSize(channels, numSamples, false, true, false); diff --git a/src/ImageReader.cpp b/src/ImageReader.cpp index 1aa20ab4..ad871f1f 100644 --- a/src/ImageReader.cpp +++ b/src/ImageReader.cpp @@ -82,7 +82,7 @@ void ImageReader::Open() info.height = image->size().height(); info.pixel_ratio.num = 1; info.pixel_ratio.den = 1; - info.duration = 60 * 60 * 24; // 24 hour duration + info.duration = 60 * 60 * 1; // 1 hour duration info.fps.num = 30; info.fps.den = 1; info.video_timebase.num = 1; diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp index 55306446..7163b097 100644 --- a/src/QtImageReader.cpp +++ b/src/QtImageReader.cpp @@ -123,7 +123,7 @@ void QtImageReader::Open() info.height = image->height(); info.pixel_ratio.num = 1; info.pixel_ratio.den = 1; - info.duration = 60 * 60 * 24; // 24 hour duration + info.duration = 60 * 60 * 1; // 1 hour duration info.fps.num = 30; info.fps.den = 1; info.video_timebase.num = 1; diff --git a/src/TextReader.cpp b/src/TextReader.cpp index 504cfc92..1983b104 100644 --- a/src/TextReader.cpp +++ b/src/TextReader.cpp @@ -127,7 +127,7 @@ void TextReader::Open() info.height = image->size().height(); info.pixel_ratio.num = 1; info.pixel_ratio.den = 1; - info.duration = 60 * 60 * 24; // 24 hour duration + info.duration = 60 * 60 * 1; // 1 hour duration info.fps.num = 30; info.fps.den = 1; info.video_timebase.num = 1; diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 5c143e0b..eb860751 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -55,6 +55,13 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) separate_arguments(sw_flags UNIX_COMMAND ${SWIG_CXX_FLAGS}) set_property(SOURCE openshot.i PROPERTY GENERATED_COMPILE_OPTIONS ${sw_flags}) + ### Take include dirs from target, automatically if possible + if (CMAKE_VERSION VERSION_GREATER 3.13) + set_property(SOURCE openshot.i PROPERTY USE_TARGET_INCLUDE_DIRECTORIES True) + else () + set_property(SOURCE openshot.i PROPERTY INCLUDE_DIRECTORIES $) + endif () + ### Add the SWIG interface file (which defines all the SWIG methods) if (CMAKE_VERSION VERSION_LESS 3.8.0) swig_add_module(pyopenshot python openshot.i) @@ -68,29 +75,24 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) ### Link the new python wrapper library with libopenshot target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} - ${PYTHON_LIBRARIES} openshot) + PUBLIC ${PYTHON_LIBRARIES} openshot) ### Check if the following Debian-friendly python module path exists - SET(PYTHON_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages") + SET(PYTHON_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/dist-packages") if (NOT EXISTS ${PYTHON_MODULE_PATH}) - ### Check if another Debian-friendly python module path exists - SET(PYTHON_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/dist-packages") - if (NOT EXISTS ${PYTHON_MODULE_PATH}) - - ### Calculate the python module path (using distutils) - execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ + ### Calculate the python module path (using distutils) + execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ from distutils.sysconfig import get_python_lib; \ print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )" - OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE ) + OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) - GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH - "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) - FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH - ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) - SET(PYTHON_MODULE_PATH ${_ABS_PYTHON_MODULE_PATH}) - endif() + GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH + "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) + FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH + ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) + SET(PYTHON_MODULE_PATH ${_ABS_PYTHON_MODULE_PATH}) endif() message("PYTHON_MODULE_PATH: ${PYTHON_MODULE_PATH}") diff --git a/src/bindings/python/openshot.i b/src/bindings/python/openshot.i index 5bf592ee..0bc284f5 100644 --- a/src/bindings/python/openshot.i +++ b/src/bindings/python/openshot.i @@ -122,6 +122,34 @@ } } +/* Instantiate the required template specializations */ +%template() std::map; + +/* Make openshot.Fraction more Pythonic */ +%extend openshot::Fraction { +%{ + #include + #include +%} + double __float__() { + return $self->ToDouble(); + } + int __int__() { + return $self->ToInt(); + } + std::map GetMap() { + std::map map1; + map1.insert({"num", $self->num}); + map1.insert({"den", $self->den}); + return map1; + } + std::string __repr__() { + std::ostringstream result; + result << $self->num << ":" << $self->den; + return result.str(); + } +} + %extend openshot::OpenShotVersion { // Give the struct a string representation const std::string __str__() { diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt index c7eb1d78..0a9fe6de 100644 --- a/src/bindings/ruby/CMakeLists.txt +++ b/src/bindings/ruby/CMakeLists.txt @@ -56,6 +56,13 @@ IF (RUBY_FOUND) separate_arguments(sw_flags UNIX_COMMAND ${SWIG_CXX_FLAGS}) set_property(SOURCE openshot.i PROPERTY GENERATED_COMPILE_OPTIONS ${sw_flags}) + ### Take include dirs from target, automatically if possible + if (CMAKE_VERSION VERSION_GREATER 3.13) + set_property(SOURCE openshot.i PROPERTY USE_TARGET_INCLUDE_DIRECTORIES True) + else () + set_property(SOURCE openshot.i PROPERTY INCLUDE_DIRECTORIES $) + endif () + ### Add the SWIG interface file (which defines all the SWIG methods) if (CMAKE_VERSION VERSION_LESS 3.8.0) swig_add_module(rbopenshot ruby openshot.i) diff --git a/src/examples/Example.py b/src/examples/Example.py index a5d483f6..31541b96 100755 --- a/src/examples/Example.py +++ b/src/examples/Example.py @@ -30,7 +30,6 @@ # 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. # diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0bfd56d8..d2b826bf 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -77,20 +77,6 @@ IF (ImageMagick_FOUND) ENDIF (ImageMagick_FOUND) -################### FFMPEG ##################### -# Find FFmpeg libraries (used for video encoding / decoding) -FIND_PACKAGE(FFmpeg REQUIRED) - -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 FIND_PACKAGE(OpenShotAudio 0.1.8 REQUIRED) @@ -160,52 +146,50 @@ else() include_directories("../thirdparty/jsoncpp") endif(USE_SYSTEM_JSONCPP) -IF (NOT DISABLE_TESTS) - ############### SET TEST SOURCE FILES ################# - SET ( OPENSHOT_TEST_FILES - Cache_Tests.cpp - Clip_Tests.cpp - Color_Tests.cpp - Coordinate_Tests.cpp - ReaderBase_Tests.cpp - ImageWriter_Tests.cpp - FFmpegReader_Tests.cpp - FFmpegWriter_Tests.cpp - Fraction_Tests.cpp - FrameMapper_Tests.cpp - KeyFrame_Tests.cpp - Point_Tests.cpp - Settings_Tests.cpp - Timeline_Tests.cpp ) +############### SET TEST SOURCE FILES ################# +SET ( OPENSHOT_TEST_FILES + Cache_Tests.cpp + Clip_Tests.cpp + Color_Tests.cpp + Coordinate_Tests.cpp + ReaderBase_Tests.cpp + ImageWriter_Tests.cpp + FFmpegReader_Tests.cpp + FFmpegWriter_Tests.cpp + Fraction_Tests.cpp + FrameMapper_Tests.cpp + KeyFrame_Tests.cpp + Point_Tests.cpp + Settings_Tests.cpp + Timeline_Tests.cpp ) - ################ 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} ) +################ 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} ) - # Link libraries to the new executable - target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY}) +# Link libraries to the new executable +target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY}) - ##### RUNNING TESTS (make os_test / make test) ##### - # Hook up the 'make os_test' target to the 'openshot-test' executable - ADD_CUSTOM_TARGET(os_test COMMAND openshot-test) - list(APPEND OS_TEST_CMDS "'make os_test'") +##### RUNNING TESTS (make os_test / make test) ##### +# Hook up the 'make os_test' target to the 'openshot-test' executable +ADD_CUSTOM_TARGET(os_test COMMAND openshot-test) +list(APPEND OS_TEST_CMDS "'make os_test'") - # 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}") +# 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}") diff --git a/tests/Cache_Tests.cpp b/tests/Cache_Tests.cpp index 7e42c741..ea5b45ce 100644 --- a/tests/Cache_Tests.cpp +++ b/tests/Cache_Tests.cpp @@ -29,10 +29,11 @@ */ #include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" #include "../include/Json.h" -using namespace std; using namespace openshot; TEST(Cache_Default_Constructor) @@ -461,4 +462,4 @@ TEST(CacheMemory_JSON) CHECK_EQUAL(1, c.JsonValue()["ranges"].size()); CHECK_EQUAL("5", c.JsonValue()["version"].asString()); -} \ No newline at end of file +} diff --git a/tests/Clip_Tests.cpp b/tests/Clip_Tests.cpp index 5789780b..711fef03 100644 --- a/tests/Clip_Tests.cpp +++ b/tests/Clip_Tests.cpp @@ -29,6 +29,8 @@ */ #include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" using namespace std; diff --git a/tests/Color_Tests.cpp b/tests/Color_Tests.cpp index 86b3a458..210cca59 100644 --- a/tests/Color_Tests.cpp +++ b/tests/Color_Tests.cpp @@ -29,6 +29,8 @@ */ #include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" using namespace std; diff --git a/tests/Coordinate_Tests.cpp b/tests/Coordinate_Tests.cpp index ec8c29a1..a666ce8c 100644 --- a/tests/Coordinate_Tests.cpp +++ b/tests/Coordinate_Tests.cpp @@ -29,6 +29,8 @@ */ #include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" using namespace std; diff --git a/tests/FFmpegReader_Tests.cpp b/tests/FFmpegReader_Tests.cpp index 4b808d83..0a8620c9 100644 --- a/tests/FFmpegReader_Tests.cpp +++ b/tests/FFmpegReader_Tests.cpp @@ -29,6 +29,8 @@ */ #include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" using namespace std; @@ -219,4 +221,3 @@ TEST(FFmpegReader_Multiple_Open_and_Close) // Close reader r.Close(); } - diff --git a/tests/FFmpegWriter_Tests.cpp b/tests/FFmpegWriter_Tests.cpp index 1cab8043..21940b1b 100644 --- a/tests/FFmpegWriter_Tests.cpp +++ b/tests/FFmpegWriter_Tests.cpp @@ -29,6 +29,8 @@ */ #include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" using namespace std; diff --git a/tests/Fraction_Tests.cpp b/tests/Fraction_Tests.cpp index 72bd6407..8f4f5f83 100644 --- a/tests/Fraction_Tests.cpp +++ b/tests/Fraction_Tests.cpp @@ -29,6 +29,8 @@ */ #include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" using namespace std; diff --git a/tests/FrameMapper_Tests.cpp b/tests/FrameMapper_Tests.cpp index f400d830..921f3a15 100644 --- a/tests/FrameMapper_Tests.cpp +++ b/tests/FrameMapper_Tests.cpp @@ -29,6 +29,8 @@ */ #include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" using namespace std; diff --git a/tests/ImageWriter_Tests.cpp b/tests/ImageWriter_Tests.cpp index 49202e96..bdf73a07 100644 --- a/tests/ImageWriter_Tests.cpp +++ b/tests/ImageWriter_Tests.cpp @@ -29,6 +29,8 @@ */ #include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" using namespace std; diff --git a/tests/KeyFrame_Tests.cpp b/tests/KeyFrame_Tests.cpp index 3d790739..3c94fa22 100644 --- a/tests/KeyFrame_Tests.cpp +++ b/tests/KeyFrame_Tests.cpp @@ -29,6 +29,8 @@ */ #include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" using namespace std; @@ -396,4 +398,4 @@ TEST(Keyframe_Large_Number_Values) CHECK_EQUAL(kf.GetLength(), large_value + 1); CHECK_CLOSE(kf.GetPoint(0).co.Y, 1.0, 0.01); CHECK_CLOSE(kf.GetPoint(1).co.Y, 100.0, 0.01); -} \ No newline at end of file +} diff --git a/tests/Point_Tests.cpp b/tests/Point_Tests.cpp index ed560a9d..dfe35d2a 100644 --- a/tests/Point_Tests.cpp +++ b/tests/Point_Tests.cpp @@ -29,6 +29,8 @@ */ #include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" using namespace std; diff --git a/tests/ReaderBase_Tests.cpp b/tests/ReaderBase_Tests.cpp index 9f56cf6d..8ac28321 100644 --- a/tests/ReaderBase_Tests.cpp +++ b/tests/ReaderBase_Tests.cpp @@ -29,6 +29,8 @@ */ #include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" using namespace std; diff --git a/tests/Settings_Tests.cpp b/tests/Settings_Tests.cpp index cf7b8a00..b63b56a8 100644 --- a/tests/Settings_Tests.cpp +++ b/tests/Settings_Tests.cpp @@ -29,6 +29,8 @@ */ #include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" using namespace std; diff --git a/tests/Timeline_Tests.cpp b/tests/Timeline_Tests.cpp index 77a3bcbc..946693a1 100644 --- a/tests/Timeline_Tests.cpp +++ b/tests/Timeline_Tests.cpp @@ -29,6 +29,8 @@ */ #include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" using namespace std;