diff --git a/.gitignore b/.gitignore index b3ba47ba..d7b09fae 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,11 @@ **/.DS* **/Builds/ +**/Cache/ **/JuceLibraryCode/ **/!JuceLibraryCode/AppConfig.h + +# ingore ffmpeg lib folder contents libs/ +ffmpeg/ +# except for the .gitkeep(s) +!.gitkeep \ No newline at end of file diff --git a/Basics/foleys_AudioFifo.cpp b/Basics/foleys_AudioFifo.cpp index 708aeef2..dab92f9a 100644 --- a/Basics/foleys_AudioFifo.cpp +++ b/Basics/foleys_AudioFifo.cpp @@ -45,7 +45,7 @@ void AudioFifo::pushSamples (const juce::AudioBuffer& samples) void AudioFifo::setNumSamples (int samples) { audioFifo.setTotalSize (samples); - audioBuffer.setSize (2, samples); + audioBuffer.setSize (audioBuffer.getNumChannels(), samples); } void AudioFifo::pullSamples (const juce::AudioSourceChannelInfo& info) diff --git a/Basics/foleys_VideoEngine.h b/Basics/foleys_VideoEngine.h index b8c9177f..597a39a5 100644 --- a/Basics/foleys_VideoEngine.h +++ b/Basics/foleys_VideoEngine.h @@ -133,7 +133,7 @@ class VideoEngine : private juce::Timer juce::OptionalScopedPointer undoManager { new juce::UndoManager(), true }; - juce::ThreadPool jobThreads { std::max (4, juce::SystemStats::getNumCpus()) }; + juce::ThreadPool jobThreads{ (std::max)(4, juce::SystemStats::getNumCpus()) }; std::vector> readingThreads; std::vector> releasePool; diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..8877c34a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,77 @@ +cmake_minimum_required (VERSION 3.15 FATAL_ERROR) + +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + project (FoleysVideoEngine + VERSION 0.2.0 + LANGUAGES CXX OBJC C + DESCRIPTION "A video engine module for JUCE" + HOMEPAGE_URL "https://foleysfinest.com/foleys_video_engine/") +else() + project (FoleysVideoEngine + VERSION 0.2.0 + LANGUAGES CXX C + DESCRIPTION "A video engine module for JUCE" + HOMEPAGE_URL "https://foleysfinest.com/foleys_video_engine/") +endif() + +list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") + +if(NOT ffmpeg_FOUND) + find_package (ffmpeg REQUIRED) +endif() + +if(PROJECT_IS_TOP_LEVEL) + message(STATUS "No parent project found, requiring JUCE") + find_package (JUCE 6 REQUIRED) +endif() + +juce_add_module ("${CMAKE_CURRENT_LIST_DIR}" ALIAS_NAMESPACE Foleys) + +target_compile_definitions (foleys_video_engine INTERFACE + JUCE_MODAL_LOOPS_PERMITTED=1 + JUCE_STRICT_REFCOUNTEDPOINTER=1 + JUCE_PLUGINHOST_AU=1 + JUCE_PLUGINHOST_VST3=1 + JUCE_PLUGINHOST_LADSPA=1) + +target_link_libraries (foleys_video_engine INTERFACE FFmpeg::FFmpeg) + +# + +set (FVE_INSTALL_DEST "${CMAKE_INSTALL_LIBDIR}/cmake/foleys_video_engine" + CACHE STRING + "Directory below INSTALL_PREFIX where the foleys_video_engine CMake package files will be installed to") + +install (DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" + DESTINATION "${FVE_INSTALL_DEST}/.." + COMPONENT foleys_video_engine + PATTERN *.md EXCLUDE + PATTERN .git/* EXCLUDE + PATTERN .github/* EXCLUDE + PATTERN *.json EXCLUDE + PATTERN CMakeLists.txt EXCLUDE + PATTERN "${CMAKE_CURRENT_BINARY_DIR}/" EXCLUDE) + +include (CPackComponent) + +cpack_add_component (foleys_video_engine + GROUP Foleys + INSTALL_TYPES Developer) + +include (CMakePackageConfigHelpers) + +write_basic_package_version_file (foleys_video_engine-config-version.cmake + VERSION "${PROJECT_VERSION}" + COMPATIBILITY SameMajorVersion + ARCH_INDEPENDENT) + +configure_package_config_file (cmake/config.cmake foleys_video_engine-config.cmake + INSTALL_DESTINATION "${FVE_INSTALL_DEST}" + NO_SET_AND_CHECK_MACRO) + +install (FILES "${CMAKE_CURRENT_BINARY_DIR}/foleys_video_engine-config-version.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/foleys_video_engine-config.cmake" + DESTINATION "${FVE_INSTALL_DEST}" + COMPONENT foleys_video_engine) + +export (PACKAGE foleys_video_engine) diff --git a/Clips/foleys_AVClip.h b/Clips/foleys_AVClip.h index 114bd492..76521d1d 100644 --- a/Clips/foleys_AVClip.h +++ b/Clips/foleys_AVClip.h @@ -97,6 +97,8 @@ class AVClip : public juce::PositionableAudioSource, /** Returns true, if this clip will produce audio */ virtual bool hasAudio() const = 0; + virtual int getNumChannels() const = 0; + /** This is the samplerate supplied from prepareToPlay and the sample rate this clip will produce audio and use as clock source. */ diff --git a/Clips/foleys_AudioClip.h b/Clips/foleys_AudioClip.h index 39b27470..8e6c9cd5 100644 --- a/Clips/foleys_AudioClip.h +++ b/Clips/foleys_AudioClip.h @@ -86,6 +86,8 @@ class AudioClip : public AVClip std::shared_ptr createCopy (StreamTypes types) override; + int getNumChannels() const override { return reader.get() ? reader->numChannels : 0; } + double getSampleRate() const override { return sampleRate; } private: diff --git a/Clips/foleys_ComposedClip.cpp b/Clips/foleys_ComposedClip.cpp index 39220d4d..e2add487 100644 --- a/Clips/foleys_ComposedClip.cpp +++ b/Clips/foleys_ComposedClip.cpp @@ -356,6 +356,11 @@ std::shared_ptr ComposedClip::createCopy (StreamTypes) return clipCopy; } +int ComposedClip::getNumChannels() const +{ + return audioSettings.numChannels; +} + double ComposedClip::getSampleRate() const { return audioSettings.timebase; diff --git a/Clips/foleys_ComposedClip.h b/Clips/foleys_ComposedClip.h index cf44c415..07d32a40 100644 --- a/Clips/foleys_ComposedClip.h +++ b/Clips/foleys_ComposedClip.h @@ -94,6 +94,8 @@ class ComposedClip : public AVClip, std::shared_ptr createCopy (StreamTypes types) override; + int getNumChannels() const override; + double getSampleRate() const override; /** When rendering non realtime (bounce), use this to wait for background diff --git a/Clips/foleys_ImageClip.cpp b/Clips/foleys_ImageClip.cpp index 5f942409..d90e8414 100644 --- a/Clips/foleys_ImageClip.cpp +++ b/Clips/foleys_ImageClip.cpp @@ -143,6 +143,12 @@ std::shared_ptr ImageClip::createCopy (StreamTypes types) return engine->createClipFromFile (getMediaFile(), types); } + +int ImageClip::getNumChannels() const +{ + return 0; +} + double ImageClip::getSampleRate() const { return sampleRate; diff --git a/Clips/foleys_ImageClip.h b/Clips/foleys_ImageClip.h index 99e6ade1..c53e20d9 100644 --- a/Clips/foleys_ImageClip.h +++ b/Clips/foleys_ImageClip.h @@ -78,6 +78,8 @@ class ImageClip : public AVClip std::shared_ptr createCopy (StreamTypes types) override; + int getNumChannels() const override; + double getSampleRate() const override; private: diff --git a/Clips/foleys_MovieClip.cpp b/Clips/foleys_MovieClip.cpp index d947c21b..92943277 100644 --- a/Clips/foleys_MovieClip.cpp +++ b/Clips/foleys_MovieClip.cpp @@ -245,6 +245,11 @@ double MovieClip::getSampleRate() const return sampleRate; } +int MovieClip::getNumChannels() const +{ + return movieReader ? movieReader->numChannels : 0; +} + void MovieClip::handleAsyncUpdate() { if (sampleRate > 0 && hasVideo()) diff --git a/Clips/foleys_MovieClip.h b/Clips/foleys_MovieClip.h index 7b9c9d14..8f9ab39b 100644 --- a/Clips/foleys_MovieClip.h +++ b/Clips/foleys_MovieClip.h @@ -89,6 +89,8 @@ class MovieClip : public AVClip, std::shared_ptr createCopy (StreamTypes types) override; + int getNumChannels() const override; + double getSampleRate() const override; /** When rendering non realtime (bounce), use this to wait for background diff --git a/Processing/foleys_ProcessorController.cpp b/Processing/foleys_ProcessorController.cpp index 8b0d5c2a..c3d29d9c 100644 --- a/Processing/foleys_ProcessorController.cpp +++ b/Processing/foleys_ProcessorController.cpp @@ -52,13 +52,24 @@ struct AudioProcessorAdapter : public ProcessorController::ProcessorAdapter public: PlayHead() = default; - bool getCurrentPosition (juce::AudioPlayHead::CurrentPositionInfo &result) override +#if JUCE_VERSION > 0x70000 + juce::Optional getPosition() const override + { + PositionInfo result; + result.setTimeInSamples(timeInSamples); + result.setTimeInSeconds(timeInSeconds); + result.setFrameRate(frameRate); + return juce::Optional(result); + } +#else + bool getCurrentPosition (juce::AudioPlayHead::CurrentPositionInfo &result) override { result.timeInSamples = timeInSamples; result.timeInSeconds = timeInSeconds; result.frameRate = frameRate; return true; } +#endif bool canControlTransport() override { diff --git a/README.md b/README.md index 2871017d..d1fe82d7 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,35 @@ Foleys Finest Audio Ltd. With the module foleys_video_engine we offer a simple way to implement reading, writing, displaying and editing of videos using the audio framework JUCE (https://juce.com) +Setup +-------- + +To use the video engine, add this module via Projucer or CMake to your JUCE project. + +In CMake, this module can be added like this: +```cmake +add_subdirectory (foleys_video_engine) +``` +or like this: +```cmake +find_package (foleys_video_engine) +``` +This repo's CMake scripts add JUCE by calling `find_package()`. Foleys video engine requires JUCE version 6, and may +be incompatible with JUCE version 7. + +You can override the path to JUCE on the command line like so: +```shell +cmake -B Builds -D FETCHCONTENT_SOURCE_DIR_JUCE= +``` + +If you are using CMake and the CPM.cmake package manager to add this repository, be aware that: +- JUCE's module system expects the root folder of a module to have the same name as the module +- By default, CPM.cmake will download the source code into a nested folder named with the version, for example `foleys_video_engine//` +This can cause the JUCE module system to get confused. If you are using CPM.cmake, we recommend you set the `CPM_USE_NAMED_CACHE_DIRECTORIES` CMake or environment variable to `ON` to prevent this issue. + +foleys_video_engine requires [ffmpeg](https://www.ffmpeg.org/), which is built in CMake using [this repository](https://github.com/ffAudio/FFmpegBuild). The CMake configuration should "just work" out of the box, you don't need +to download or install anything. + Features -------- diff --git a/ReadWrite/FFmpeg/foleys_FFmpegHelpers.h b/ReadWrite/FFmpeg/foleys_FFmpegHelpers.h index 07007739..4316af9b 100644 --- a/ReadWrite/FFmpeg/foleys_FFmpegHelpers.h +++ b/ReadWrite/FFmpeg/foleys_FFmpegHelpers.h @@ -29,19 +29,12 @@ #pragma clang diagnostic ignored "-Wfloat-conversion" #endif -#if JUCE_MSVC -#pragma comment (lib, "avformat.lib") -#pragma comment (lib, "avutil.lib") -#pragma comment (lib, "avcodec.lib") -#pragma comment (lib, "swscale.lib") -#pragma comment (lib, "swresample.lib") -#pragma comment (lib, "avresample.lib") -#endif #ifdef __cplusplus extern "C" { #endif +#include #include #include #include diff --git a/ReadWrite/FFmpeg/foleys_FFmpegReader.cpp b/ReadWrite/FFmpeg/foleys_FFmpegReader.cpp index 2733a9d8..a01014ed 100644 --- a/ReadWrite/FFmpeg/foleys_FFmpegReader.cpp +++ b/ReadWrite/FFmpeg/foleys_FFmpegReader.cpp @@ -21,7 +21,7 @@ #if FOLEYS_USE_FFMPEG #include "foleys_FFmpegHelpers.h" - +#include namespace foleys { @@ -353,7 +353,7 @@ class FFmpegReader::Pimpl enum AVMediaType type, bool refCounted) { - AVCodec *decoder = nullptr; + const AVCodec *decoder = nullptr; AVDictionary *opts = nullptr; int id = av_find_best_stream (formatContext, type, -1, -1, nullptr, 0); diff --git a/Widgets/foleys_OpenGLDraw.h b/Widgets/foleys_OpenGLDraw.h index d57e1fee..0722eebe 100644 --- a/Widgets/foleys_OpenGLDraw.h +++ b/Widgets/foleys_OpenGLDraw.h @@ -27,24 +27,25 @@ namespace foleys namespace OpenGLDrawing { +using namespace juce::gl; #if JUCE_DEBUG static const char* getGLErrorMessage (const GLenum e) noexcept { switch (e) { - case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; - case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; - case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; - case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; + case juce::gl::GL_INVALID_ENUM: return "GL_INVALID_ENUM"; + case juce::gl::GL_INVALID_VALUE: return "GL_INVALID_VALUE"; + case juce::gl::GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; + case juce::gl::GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; #ifdef GL_STACK_OVERFLOW - case GL_STACK_OVERFLOW: return "GL_STACK_OVERFLOW"; + case juce::gl::GL_STACK_OVERFLOW: return "GL_STACK_OVERFLOW"; #endif #ifdef GL_STACK_UNDERFLOW - case GL_STACK_UNDERFLOW: return "GL_STACK_UNDERFLOW"; + case juce::gl::GL_STACK_UNDERFLOW: return "GL_STACK_UNDERFLOW"; #endif #ifdef GL_INVALID_FRAMEBUFFER_OPERATION - case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION"; + case juce::gl::GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION"; #endif default: break; } @@ -56,9 +57,9 @@ static void checkGLError (const char* file, const int line) { for (;;) { - const GLenum e = glGetError(); + const GLenum e = juce::gl::glGetError(); - if (e == GL_NO_ERROR) + if (e == juce::gl::GL_NO_ERROR) break; DBG ("***** " << getGLErrorMessage (e) << " at " << file << " : " << line); @@ -73,7 +74,7 @@ static void checkGLError (const char* file, const int line) static void clearGLError() noexcept { - while (glGetError() != GL_NO_ERROR) {} + while (juce::gl::glGetError() != juce::gl::GL_NO_ERROR) {} } @@ -81,19 +82,19 @@ struct DepthTestDisabler { DepthTestDisabler() noexcept { - glGetBooleanv (GL_DEPTH_TEST, &wasEnabled); + juce::gl::glGetBooleanv (juce::gl::GL_DEPTH_TEST, &wasEnabled); if (wasEnabled) - glDisable (GL_DEPTH_TEST); + juce::gl::glDisable (juce::gl::GL_DEPTH_TEST); } ~DepthTestDisabler() noexcept { if (wasEnabled) - glEnable (GL_DEPTH_TEST); + juce::gl::glEnable (juce::gl::GL_DEPTH_TEST); } - GLboolean wasEnabled; + GLboolean wasEnabled; }; static inline void drawTexture (juce::OpenGLContext& context, @@ -110,8 +111,8 @@ static inline void drawTexture (juce::OpenGLContext& context, juce::ignoreUnused (transform); JUCE_CHECK_OPENGL_ERROR - glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glEnable (GL_BLEND); + juce::gl::glBlendFunc (juce::gl::GL_ONE, juce::gl::GL_ONE_MINUS_SRC_ALPHA); + juce::gl::glEnable (juce::gl::GL_BLEND); DepthTestDisabler depthDisabler; @@ -218,20 +219,20 @@ static inline void drawTexture (juce::OpenGLContext& context, GLuint vertexBuffer = 0; context.extensions.glGenBuffers (1, &vertexBuffer); - context.extensions.glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer); - context.extensions.glBufferData (GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STATIC_DRAW); + context.extensions.glBindBuffer (juce::gl::GL_ARRAY_BUFFER, vertexBuffer); + context.extensions.glBufferData (juce::gl::GL_ARRAY_BUFFER, sizeof (vertices), vertices, juce::gl::GL_STATIC_DRAW); JUCE_CHECK_OPENGL_ERROR auto index = (GLuint) program.params.positionAttribute.attributeID; - context.extensions.glVertexAttribPointer (index, 2, GL_SHORT, GL_FALSE, 4, nullptr); + context.extensions.glVertexAttribPointer (index, 2, juce::gl::GL_SHORT, juce::gl::GL_FALSE, 4, nullptr); context.extensions.glEnableVertexAttribArray (index); JUCE_CHECK_OPENGL_ERROR - if (context.extensions.glCheckFramebufferStatus (GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) + if (context.extensions.glCheckFramebufferStatus (juce::gl::GL_FRAMEBUFFER) == juce::gl::GL_FRAMEBUFFER_COMPLETE) { - glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); + juce::gl::glDrawArrays (juce::gl::GL_TRIANGLE_STRIP, 0, 4); - context.extensions.glBindBuffer (GL_ARRAY_BUFFER, 0); + context.extensions.glBindBuffer (juce::gl::GL_ARRAY_BUFFER, 0); context.extensions.glUseProgram (0); context.extensions.glDisableVertexAttribArray (index); context.extensions.glDeleteBuffers (1, &vertexBuffer); diff --git a/Widgets/foleys_OpenGLView.cpp b/Widgets/foleys_OpenGLView.cpp index 85e8e8d2..d07de9b8 100644 --- a/Widgets/foleys_OpenGLView.cpp +++ b/Widgets/foleys_OpenGLView.cpp @@ -22,6 +22,7 @@ namespace foleys { +using namespace juce::gl; OpenGLView::OpenGLView() { @@ -54,10 +55,10 @@ void OpenGLView::render() auto desktopScale = (float) openGLContext.getRenderingScale(); juce::OpenGLHelpers::clear (juce::Colours::black); - glEnable (GL_BLEND); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + juce::gl::glEnable (juce::gl::GL_BLEND); + juce::gl::glBlendFunc (juce::gl::GL_SRC_ALPHA, juce::gl::GL_ONE_MINUS_SRC_ALPHA); - glViewport (0, 0, juce::roundToInt (desktopScale * (float) getWidth()), juce::roundToInt (desktopScale * (float) getHeight())); + juce::gl::glViewport (0, 0, juce::roundToInt (desktopScale * (float) getWidth()), juce::roundToInt (desktopScale * (float) getHeight())); clip->render (*this, clip->getCurrentTimeInSeconds()); } diff --git a/cmake/FindJUCE.cmake b/cmake/FindJUCE.cmake new file mode 100644 index 00000000..0f14ec4e --- /dev/null +++ b/cmake/FindJUCE.cmake @@ -0,0 +1,30 @@ +cmake_minimum_required (VERSION 3.15 FATAL_ERROR) + +include_guard (GLOBAL) + +include (FetchContent) +include (FeatureSummary) +include (FindPackageMessage) + +set_package_properties ("${CMAKE_FIND_PACKAGE_NAME}" + PROPERTIES + URL "https://juce.com/" + DESCRIPTION "Cross platform framework for plugin and app development") + +set (juce_git_hash 37d6161da2aa94d1530cef860b1642e1e4d9e08d) # most recent JUCE 6 commit + +FetchContent_Declare (JUCE + GIT_REPOSITORY https://github.com/juce-framework/JUCE.git + GIT_TAG "${juce_git_hash}") + +set (JUCE_BUILD_EXAMPLES OFF) +set (JUCE_BUILD_EXTRAS OFF) +set (JUCE_ENABLE_MODULE_SOURCE_GROUPS ON) + +FetchContent_MakeAvailable (JUCE) + +find_package_message ("${CMAKE_FIND_PACKAGE_NAME}" + "JUCE package found -- Sources downloaded" + "JUCE (GitHub) [${juce_git_hash}]") + +set (${CMAKE_FIND_PACKAGE_NAME}_FOUND TRUE) diff --git a/cmake/Findffmpeg.cmake b/cmake/Findffmpeg.cmake new file mode 100644 index 00000000..a88e1a04 --- /dev/null +++ b/cmake/Findffmpeg.cmake @@ -0,0 +1,124 @@ +cmake_minimum_required (VERSION 3.15 FATAL_ERROR) + +include_guard (GLOBAL) + +include (FetchContent) +include (FeatureSummary) +include (FindPackageMessage) +include(FindPackageHandleStandardArgs) + +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set_package_properties ("${CMAKE_FIND_PACKAGE_NAME}" + PROPERTIES + URL "https://www.ffmpeg.org/" + DESCRIPTION "Audio and video codecs") + FetchContent_Declare (ffmpeg + GIT_REPOSITORY "https://github.com/mach1studios/FFmpegBuild.git" + GIT_TAG origin/main) + +elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows" AND ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64") + + set(BUILT_FFMPEG_RELEASE "ffmpeg-master-latest-win64-lgpl-shared.zip") + + if(NOT BUILT_FFMPEG_RELEASE) + message(FATAL_ERROR "Platform ${CMAKE_SYSTEM_PROCESSOR} on system ${CMAKE_SYSTEM_NAME} is not supported!") + endif() + + if (NOT "${PROJECT_BINARY_DIR}/.local" IN_LIST "${CMAKE_PREFIX_PATH}") + list(APPEND CMAKE_PREFIX_PATH "${PROJECT_BINARY_DIR}/.local") + endif() + + FetchContent_Declare(ffmpeg + URL "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/${BUILT_FFMPEG_RELEASE}" + SOURCE_DIR "${PROJECT_BINARY_DIR}/.local" + ) + +elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + + if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "amd64") + set(BUILT_FFMPEG_RELEASE "ffmpeg-master-latest-linux64-lgpl-shared.tar.xz") + elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL aarch64) + set(BUILT_FFMPEG_RELEASE "ffmpeg-master-latest-linuxarm64-lgpl-shared.tar.xz") + endif() + + if(NOT BUILT_FFMPEG_RELEASE) + message(FATAL_ERROR "Platform ${CMAKE_SYSTEM_PROCESSOR} on system ${CMAKE_SYSTEM_NAME} is not supported!") + endif() + + if (NOT "${PROJECT_BINARY_DIR}/.local" IN_LIST "${CMAKE_PREFIX_PATH}") + list(APPEND CMAKE_PREFIX_PATH "${PROJECT_BINARY_DIR}/.local") + endif() + + FetchContent_Declare(ffmpeg + URL "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/${BUILT_FFMPEG_RELEASE}" + SOURCE_DIR "${PROJECT_BINARY_DIR}/.local" + ) + +endif() + +FetchContent_MakeAvailable (ffmpeg) + +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + + find_package_message ("${CMAKE_FIND_PACKAGE_NAME}" + "ffmpeg package found -- Sources downloaded" + "ffmpeg (GitHub)") + + set (${CMAKE_FIND_PACKAGE_NAME}_FOUND TRUE) + +else() + +macro(find_component _component _header) + find_path(${_component}_INCLUDE_DIRS "${_header}" PATH_SUFFIXES ffmpeg) + find_library(${_component}_LIBRARY NAMES "${_component}" PATH_SUFFIXES ffmpeg) + + if (${_component}_LIBRARY AND ${_component}_INCLUDE_DIRS) + set(FFmpeg_${_component}_FOUND TRUE) + set(FFmpeg_LINK_LIBRARIES ${FFmpeg_LINK_LIBRARIES} ${${_component}_LIBRARY}) + list(APPEND FFmpeg_INCLUDE_DIRS ${${_component}_INCLUDE_DIRS}) + + if (NOT TARGET FFmpeg::${_component}) + add_library(FFmpeg_${_component} UNKNOWN IMPORTED) + set_target_properties(FFmpeg_${_component} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${${_component}_INCLUDE_DIRS}" + IMPORTED_LOCATION "${${_component}_LIBRARY}" + ) + add_library(FFmpeg::${_component} ALIAS FFmpeg_${_component}) + endif () + endif () + + mark_as_advanced(${_component}_INCLUDE_DIRS) + mark_as_advanced(${_component}_LIBRARY) +endmacro() + +#------------------------------------------------------------------------------ + +# The default components +if (NOT FFmpeg_FIND_COMPONENTS) + set(FFmpeg_FIND_COMPONENTS avcodec avfilter avformat avdevice avutil swresample swscale) +endif () + +# Traverse the user-selected components of the package and find them +set(FFmpeg_INCLUDE_DIRS) +set(FFmpeg_LINK_LIBRARIES) +foreach(_component ${FFmpeg_FIND_COMPONENTS}) + find_component(${_component} lib${_component}/${_component}.h) +endforeach() +mark_as_advanced(FFmpeg_INCLUDE_DIRS) +mark_as_advanced(FFmpeg_LINK_LIBRARIES) + +# Handle findings +list(LENGTH FFmpeg_FIND_COMPONENTS FFmpeg_COMPONENTS_COUNT) +find_package_handle_standard_args(FFmpeg REQUIRED_VARS FFmpeg_COMPONENTS_COUNT HANDLE_COMPONENTS) + +# Publish targets if succeeded to find the FFmpeg package and the requested components +if (FFmpeg_FOUND AND NOT TARGET FFmpeg::FFmpeg) + add_library(FFmpeg INTERFACE) + set_target_properties(FFmpeg PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${FFmpeg_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFmpeg_LINK_LIBRARIES}" + ) + add_library(FFmpeg::FFmpeg ALIAS FFmpeg) +endif() + +endif() \ No newline at end of file diff --git a/cmake/config.cmake b/cmake/config.cmake new file mode 100644 index 00000000..b276eb95 --- /dev/null +++ b/cmake/config.cmake @@ -0,0 +1,54 @@ +#[[ + +CMake package configuration file for foleys_video_engine + +This file is loaded by the find_package command to load an installed copy of foleys_video_engine +and bring it into another CMake build tree. + +The way our install works is that we replicate the layout of the source tree in the package root, and +in this file we call juce_add_module just the same way that building this project does. + +]] + +@PACKAGE_INIT@ + +check_required_components ("@PROJECT_NAME@") + +# + +include (FeatureSummary) +include (FindPackageMessage) + +set_package_properties ("${CMAKE_FIND_PACKAGE_NAME}" + PROPERTIES + URL "https://foleysfinest.com/foleys_video_engine/" + DESCRIPTION "A video engine module for JUCE") + +# + +list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") + +include (CMakeFindDependencyMacro) + +if(PROJECT_IS_TOP_LEVEL) + message(STATUS "No parent project found, requiring JUCE") +find_dependency (JUCE 6) +endif() +find_dependency (ffmpeg) + +juce_add_module ("${CMAKE_CURRENT_LIST_DIR}" + ALIAS_NAMESPACE Foleys) + +target_compile_definitions (foleys_video_engine INTERFACE + JUCE_MODAL_LOOPS_PERMITTED=1 + JUCE_STRICT_REFCOUNTEDPOINTER=1 + JUCE_PLUGINHOST_AU=1 + JUCE_PLUGINHOST_VST3=1 + JUCE_PLUGINHOST_LADSPA=1) + +target_link_libraries (foleys_video_engine INTERFACE ffmpeg::ffmpeg) + +find_package_message ("${CMAKE_FIND_PACKAGE_NAME}" + "foleys_video_engine - local install" + "foleys_video_engine [${CMAKE_CURRENT_LIST_DIR}]") + diff --git a/foleys_video_engine.h b/foleys_video_engine.h index 3e306d09..01b4c7b2 100644 --- a/foleys_video_engine.h +++ b/foleys_video_engine.h @@ -25,10 +25,11 @@ name: Video engine to read, process, display and write video in JUCE description: Provides classes to read audio streams from video files or to mux audio into an existing video - dependencies: juce_audio_basics juce_audio_formats juce_gui_basics - juce_graphics juce_core juce_audio_utils + dependencies: juce_audio_basics juce_audio_devices juce_audio_formats juce_gui_basics juce_graphics juce_core juce_audio_utils juce_audio_processors minimumCppStandard: 17 - + searchpaths: ffmpeg/include + windowsLibs: avformat,avutil,avcodec,swscale,swresample + OSXLibs: avformat,avutil,avcodec,swscale,swresample website: https://foleysfinest.com/ END_JUCE_MODULE_DECLARATION