diff --git a/.github/stale.yml b/.github/stale.yml
index c5ec1048c..bba68742f 100644
--- a/.github/stale.yml
+++ b/.github/stale.yml
@@ -11,9 +11,17 @@ exemptLabels:
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
- This issue has been automatically marked as **stale** because it has not had
- recent activity. It will be closed if no further activity occurs. Thank you
- for your contributions.
+ Thank you so much for submitting an issue to help improve OpenShot Video Editor. We are sorry about this, but this particular issue has gone unnoticed for quite some time. To help keep the OpenShot GitHub Issue Tracker organized and focused, we must ensure that every issue is correctly labelled and triaged, to get the proper attention.
+
+ This issue will be closed, as it meets the following criteria:
+ - No activity in the past 90 days
+ - No one is assigned to this issue
+
+ We'd like to ask you to help us out and determine whether this issue should be reopened.
+ - If this issue is reporting a bug, please can you attempt to reproduce on the [latest daily build](https://www.openshot.org/download/#daily) to help us to understand whether the bug still needs our attention.
+ - If this issue is proposing a new feature, please can you verify whether the feature proposal is still relevant.
+
+ Thanks again for your help!
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
# Only close issues
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c15bcb984..8ee17e4f4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,6 +2,9 @@ stages:
- build-libopenshot
- trigger-openshot-qt
+variables:
+ GIT_LOG_FORMAT: "- %h %ad %s [%aN]"
+
linux-builder:
stage: build-libopenshot
artifacts:
@@ -22,7 +25,7 @@ linux-builder:
- make doc
- ~/auto-update-docs "$CI_PROJECT_DIR/build" "$CI_COMMIT_REF_NAME"
- echo -e "CI_PROJECT_NAME:$CI_PROJECT_NAME\nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME\nCI_COMMIT_SHA:$CI_COMMIT_SHA\nCI_JOB_ID:$CI_JOB_ID" > "install-x64/share/$CI_PROJECT_NAME"
- - git log $(git describe --tags --abbrev=0 @^)..@ --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log"
+ - git log $(git describe --tags --abbrev=0 '@^')..@ --oneline --no-abbrev --date=short --no-merges --pretty="tformat:$GIT_LOG_FORMAT" > "install-x64/share/$CI_PROJECT_NAME.log"
when: always
except:
- tags
@@ -47,7 +50,7 @@ mac-builder:
- make
- make install
- echo -e "CI_PROJECT_NAME:$CI_PROJECT_NAME\nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME\nCI_COMMIT_SHA:$CI_COMMIT_SHA\nCI_JOB_ID:$CI_JOB_ID" > "install-x64/share/$CI_PROJECT_NAME"
- - git log $(git describe --tags --abbrev=0 @^)..@ --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log"
+ - git log $(git describe --tags --abbrev=0 '@^')..@ --oneline --no-abbrev --date=short --no-merges --pretty="tformat:$GIT_LOG_FORMAT" > "install-x64/share/$CI_PROJECT_NAME.log"
when: always
except:
- tags
@@ -74,7 +77,7 @@ windows-builder-x64:
- mingw32-make install
- New-Item -path "install-x64/share/" -Name "$CI_PROJECT_NAME" -Value "CI_PROJECT_NAME:$CI_PROJECT_NAME`nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME`nCI_COMMIT_SHA:$CI_COMMIT_SHA`nCI_JOB_ID:$CI_JOB_ID" -ItemType file -force
- $PREV_GIT_LABEL=(git describe --tags --abbrev=0 '@^')
- - git log "$PREV_GIT_LABEL..@" --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log"
+ - git log "$PREV_GIT_LABEL..@" --oneline --no-abbrev --date=short --no-merges --pretty="tformat:$GIT_LOG_FORMAT" > "install-x64/share/$CI_PROJECT_NAME.log"
when: always
except:
- tags
@@ -101,7 +104,7 @@ windows-builder-x86:
- mingw32-make install
- New-Item -path "install-x86/share/" -Name "$CI_PROJECT_NAME" -Value "CI_PROJECT_NAME:$CI_PROJECT_NAME`nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME`nCI_COMMIT_SHA:$CI_COMMIT_SHA`nCI_JOB_ID:$CI_JOB_ID" -ItemType file -force
- $PREV_GIT_LABEL=(git describe --tags --abbrev=0 '@^')
- - git log "$PREV_GIT_LABEL..@" --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x86/share/$CI_PROJECT_NAME.log"
+ - git log "$PREV_GIT_LABEL..@" --oneline --no-abbrev --date=short --no-merges --pretty="tformat:$GIT_LOG_FORMAT" > "install-x86/share/$CI_PROJECT_NAME.log"
when: always
except:
- tags
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 94b09879b..ec608257d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -75,17 +75,14 @@ option(USE_SYSTEM_JSONCPP "Use system installed JsonCpp, if found" ON)
option(DISABLE_BUNDLED_JSONCPP "Don't fall back to bundled JsonCpp" OFF)
option(ENABLE_IWYU "Enable 'Include What You Use' scanner (CMake 3.3+)" OFF)
option(ENABLE_TESTS "Build unit tests (requires UnitTest++)" ON)
+option(ENABLE_COVERAGE "Scan test coverage using gcov and report" OFF)
option(ENABLE_DOCS "Build API documentation (requires Doxygen)" ON)
option(APPIMAGE_BUILD "Build to install in an AppImage (Linux only)" OFF)
+option(ENABLE_MAGICK "Use ImageMagick, if available" ON)
# Legacy commandline override
if (DISABLE_TESTS)
- if(ENABLE_COVERAGE)
- message(WARNING "ENABLE_COVERAGE requires tests, overriding DISABLE_TESTS")
- set(ENABLE_TESTS ON)
- else()
- set(ENABLE_TESTS OFF)
- endif()
+ set(ENABLE_TESTS OFF)
endif()
if(DEFINED ENABLE_TESTS)
@@ -109,9 +106,9 @@ IF (WIN32)
ENDIF(WIN32)
############## Code Coverage #########################
-if (DISABLE_TESTS AND ENABLE_COVERAGE)
- message(WARNING "ENABLE_COVERAGE requires tests, overriding DISABLE_TESTS")
- set(DISABLE_TESTS OFF CACHE BOOL "Don't build unit tests" FORCE)
+if (ENABLE_COVERAGE AND NOT ENABLE_TESTS)
+ message(WARNING "ENABLE_COVERAGE requires unit tests, forcing ENABLE_TESTS")
+ set(ENABLE_TESTS ON CACHE BOOL "Don't build unit tests" FORCE)
endif()
if (ENABLE_COVERAGE)
@@ -124,25 +121,29 @@ if (ENABLE_COVERAGE)
endif()
add_feature_info("Coverage" ENABLE_COVERAGE "analyze test coverage and generate report")
-# Juce requires either DEBUG or NDEBUG to be defined on MacOS.
-# -DNDEBUG is set by cmake for all release configs, so add
-# -DDEBUG for debug builds. We'll do this for all OSes, even
-# though only MacOS requires it.
-set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
-# Make sure we've picked some build type, default to debug
+# Make sure we've picked some build type, default to release
if(NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
- set(CMAKE_BUILD_TYPE "Debug")
+ set(CMAKE_BUILD_TYPE "Release")
endif()
-############## PROCESS src/ DIRECTORIES ##############
+###
+### Process subdirectories
+###
add_subdirectory(src)
-
-########## Configure Version.h header ##############
-configure_file(include/OpenShotVersion.h.in include/OpenShotVersion.h @ONLY)
+add_subdirectory(examples)
+add_subdirectory(bindings)
+
+###
+### Configure Version.h header
+###
+# (Note: This comes after the subdirectories, because it needs variables
+# set during the dependency discovery in src/CMakeLists.txt)
+configure_file(src/OpenShotVersion.h.in src/OpenShotVersion.h @ONLY)
# We'll want that installed later
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/OpenShotVersion.h
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/src/OpenShotVersion.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libopenshot)
+
################### DOCUMENTATION ###################
# Find Doxygen (used for documentation)
set(DOCS_ENABLED FALSE) # Only set true if Doxygen is found and configured
@@ -179,8 +180,10 @@ if (ENABLE_COVERAGE)
NAME coverage
LCOV_ARGS "--no-external"
EXECUTABLE openshot-test
- DEPENDENCIES openshot-test)
- message("Generate coverage report with 'make coverage'")
+ DEPENDENCIES openshot-test
+ EXCLUDE "bindings" "examples" "${CMAKE_CURRENT_BINARY_DIR}/bindings"
+ )
+ message("Generate coverage report with 'make coverage'")
endif()
########### PRINT FEATURE SUMMARY ##############
diff --git a/Doxyfile.in b/Doxyfile.in
index c47d6e651..343190a17 100644
--- a/Doxyfile.in
+++ b/Doxyfile.in
@@ -148,7 +148,7 @@ INLINE_INHERITED_MEMB = NO
# shortest path that makes the file name unique will be used
# The default value is: YES.
-FULL_PATH_NAMES = NO
+FULL_PATH_NAMES = YES
# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
# Stripping is only done if one of the specified strings matches the left-hand
@@ -160,7 +160,7 @@ FULL_PATH_NAMES = NO
# will be relative from the directory where doxygen is started.
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-STRIP_FROM_PATH =
+STRIP_FROM_PATH = "@PROJECT_SOURCE_DIR@/src"
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
# path mentioned in the documentation of a class, which tells the reader which
@@ -169,7 +169,7 @@ STRIP_FROM_PATH =
# specify the list of include paths that are normally passed to the compiler
# using the -I flag.
-STRIP_FROM_INC_PATH =
+STRIP_FROM_INC_PATH = "@PROJECT_SOURCE_DIR@/src"
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
# less readable) file names. This can be useful is your file systems doesn't
@@ -803,9 +803,9 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
-INPUT = "@CMAKE_CURRENT_SOURCE_DIR@/include" \
- "@CMAKE_CURRENT_SOURCE_DIR@/src" \
- "@CMAKE_CURRENT_SOURCE_DIR@/doc"
+INPUT = "@PROJECT_SOURCE_DIR@/src" \
+ "@PROJECT_SOURCE_DIR@/doc" \
+ "@PROJECT_BINARY_DIR@/src/OpenShotVersion.h"
# This tag can be used to specify the character encoding of the source files
@@ -862,11 +862,7 @@ EXCLUDE_SYMLINKS = NO
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
-EXCLUDE_PATTERNS = "*/.*" \
- "*/.*/*" \
- "*/src/examples/*" \
- "*/src/bindings/*" \
- "*.py"
+EXCLUDE_PATTERNS =
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
@@ -883,27 +879,27 @@ EXCLUDE_SYMBOLS =
# that contain example code fragments that are included (see the \include
# command).
-EXAMPLE_PATH = "@CMAKE_CURRENT_SOURCE_DIR@/tests"
+EXAMPLE_PATH = "@PROJECT_SOURCE_DIR@/examples"
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
# *.h) to filter out the source-files in the directories. If left blank all
# files are included.
-EXAMPLE_PATTERNS =
+EXAMPLE_PATTERNS = "*.cpp"
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
# searched for input files to be used with the \include or \dontinclude commands
# irrespective of the value of the RECURSIVE tag.
# The default value is: NO.
-EXAMPLE_RECURSIVE = NO
+EXAMPLE_RECURSIVE = YES
# The IMAGE_PATH tag can be used to specify one or more files or directories
# that contain images that are to be included in the documentation (see the
# \image command).
-IMAGE_PATH = "@CMAKE_CURRENT_SOURCE_DIR@"
+IMAGE_PATH = "@PROJECT_SOURCE_DIR@"
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
@@ -2086,7 +2082,7 @@ INCLUDE_PATH =
# used.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-INCLUDE_FILE_PATTERNS =
+INCLUDE_FILE_PATTERNS = "*.h"
# The PREDEFINED tag can be used to specify one or more macro names that are
# defined before the preprocessor is started (similar to the -D option of e.g.
diff --git a/INSTALL.md b/INSTALL.md
index f2d0dda77..b1ddc7961 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -2,74 +2,100 @@
Operating system specific install instructions are located in:
-* [doc/INSTALL-LINUX.md][INSTALL-LINUX]
-* [doc/INSTALL-MAC.md][INSTALL-MAC]
-* [doc/INSTALL-WINDOWS.md][INSTALL-WINDOWS]
+* [doc/INSTALL-LINUX.md][INSTALL-LINUX]
+* [doc/INSTALL-MAC.md][INSTALL-MAC]
+* [doc/INSTALL-WINDOWS.md][INSTALL-WINDOWS]
## Getting Started
-The best way to get started with libopenshot, is to learn about our build system, obtain all the source code,
-install a development IDE and tools, and better understand our dependencies. So, please read through the
-following sections, and follow the instructions. And keep in mind, that your computer is likely different
-than the one used when writing these instructions. Your file paths and versions of applications might be
-slightly different, so keep an eye out for subtle file path differences in the commands you type.
+The best way to get started with libopenshot is to learn about our build system,
+obtain all the source code, install a development IDE and tools,
+and better understand our dependencies.
+So, please read through the following sections, and follow the instructions.
+And keep in mind, your computer is likely different than the one used when writing these instructions.
+Your file paths and versions of applications will be different,
+so you should treat the specifics used here as examples and adjust as necessary.
+Keep an eye out for subtle file path differences in the commands you type.
## Dependencies
The following libraries are required to build libopenshot.
Instructions on how to install these dependencies vary for each operating system.
-Libraries and Executables have been labeled in the list below to help distinguish between them.
+Libraries and executables have been labeled in the list below to help distinguish between them.
#### FFmpeg (libavformat, libavcodec, libavutil, libavdevice, libavresample, libswscale)
+* **(Library)**
- * http://www.ffmpeg.org/ **(Library)**
- * This library is used to decode and encode video, audio, and image files. It is also used to obtain information about media files, such as frame rate, sample rate, aspect ratio, and other common attributes.
+* This library is used to decode and encode video, audio, and image files.
+ It is also used to obtain information about media files,
+ such as frame rate, sample rate, aspect ratio, and other common attributes.
#### ImageMagick++ (libMagick++, libMagickWand, libMagickCore)
- * http://www.imagemagick.org/script/magick++.php **(Library)**
- * This library is **optional**, and used to decode and encode images.
+* **(Library)**
+* This library is **optional**, and used to decode and encode images.
#### OpenShot Audio Library (libopenshot-audio)
- * https://github.com/OpenShot/libopenshot-audio/ **(Library)**
- * This library is used to mix, resample, host plug-ins, and play audio. It is based on the JUCE project, which is an outstanding audio library used by many different applications
+* **(Library)**
+
+* This library is used to mix, resample, host plug-ins, and play audio.
+ It is based on the JUCE project,
+ an outstanding audio library used by many different applications.
#### Qt 5 (libqt5)
- * http://www.qt.io/qt5/ **(Library)**
- * Qt5 is used to display video, store image data, composite images, apply image effects, and many other utility functions, such as file system manipulation, high resolution timers, etc...
+* **(Library)**
+
+* Qt5 is used to display video, store image data, composite images,
+ apply image effects, and many other utility functions,
+ such as file system manipulation, high resolution timers, etc.
#### ZeroMQ (libzmq)
- * http://zeromq.org/ **(Library)**
- * This library is used to communicate between libopenshot and other applications (publisher / subscriber). Primarily used to send debug data from libopenshot.
+* **(Library)**
+
+* This library is used to communicate between libopenshot and other applications (publisher / subscriber).
+ Primarily used to send debug data from libopenshot.
#### OpenMP (`-fopenmp`)
- * http://openmp.org/wp/ **(Compiler Flag)**
- * If your compiler supports this flag (GCC, Clang, and most other compilers), it provides libopenshot with easy methods of using parallel programming techniques to improve performance and take advantage of multi-core processors.
+* **(Compiler Flag)**
+
+* If your compiler supports this flag (GCC, Clang, and most other compilers),
+ it provides libopenshot with implementations of common parallel programming techniques
+ used to improve performance and take advantage of multi-core processors.
#### CMake (`cmake`)
- * http://www.cmake.org/ **(Executable)**
- * This executable is used to automate the generation of Makefiles, check for dependencies, and is the backbone of libopenshot’s cross-platform build process.
+* **(Executable)**
+
+* This executable is used to automate the generation of Makefiles,
+ check for dependencies, and is the backbone of libopenshot’s cross-platform build process.
#### SWIG (`swig`)
- * http://www.swig.org/ **(Executable)**
- * This executable is used to generate the Python and Ruby bindings for libopenshot. It is a simple and powerful wrapper for C++ libraries, and supports many languages.
+* **(Executable)**
+
+* This executable is used to generate the Python and Ruby bindings for libopenshot.
+ It is a powerful wrapper for C++ libraries, and supports many languages.
#### Python 3 (libpython)
- * http://www.python.org/ **(Executable and Library)**
- * This library is used by swig to create the Python (version 3+) bindings for libopenshot. This is also the official language used by OpenShot Video Editor (a graphical interface to libopenshot).
+* **(Executable and Library)**
+
+* This library is used by swig to create the Python (version 3+) bindings for libopenshot.
+ This is also the official language used by OpenShot Video Editor (a graphical interface to libopenshot).
#### Doxygen (doxygen)
- * http://www.stack.nl/~dimitri/doxygen/ **(Executable)**
- * This executable is used to auto-generate the documentation used by libopenshot.
+* **(Executable)**
+* This executable is used to auto-generate the documentation used by libopenshot.
#### UnitTest++ (libunittest++)
- * https://github.com/unittest-cpp/ **(Library)**
- * This library is used to execute unit tests for libopenshot. It contains many macros used to keep our unit testing code very clean and simple.
+* **(Library)**
+
+* This library is used to execute unit tests for libopenshot.
+ It contains many macros used to keep our unit testing code clean and easy-to-follow.
## Obtaining Source Code
-The first step in installing libopenshot is to obtain the most recent source code. The source code is available on [GitHub](https://github.com/OpenShot/libopenshot). Use the following command to obtain the latest libopenshot source code.
+The first step in installing libopenshot is to obtain the most recent source code.
+The source code is available on [GitHub](https://github.com/OpenShot/libopenshot).
+Use the following command to obtain the latest libopenshot source code.
-```
+```sh
git clone https://github.com/OpenShot/libopenshot.git
git clone https://github.com/OpenShot/libopenshot-audio.git
```
@@ -79,27 +105,36 @@ git clone https://github.com/OpenShot/libopenshot-audio.git
The source code is divided up into the following folders.
#### `build/`
-This folder needs to be manually created, and is used by cmake to store the temporary build files, such as makefiles, as well as the final binaries (library and test executables).
+This folder needs to be manually created,
+and is used by cmake to store the build system control files and generated output
+(such as compiled object files and the result of template-file processing)
+as well as the final results of the build (library, tool, and test program binaries).
#### `cmake/`
This folder contains custom modules not included by default in cmake.
-CMake find modules are used to discover dependency libraries on the system, and to incorporate their headers and object files.
+CMake find modules are used to discover dependency libraries on the system,
+and to incorporate their headers and object files.
CMake code modules are used to implement build features such as test coverage scanning.
#### `doc/`
This folder contains documentation and related files.
This includes logos and images required by the doxygen-generated API documentation.
-#### `include/`
-This folder contains all headers (*.h) used by libopenshot.
-
#### `src/`
-This folder contains all source code (*.cpp) used by libopenshot.
+This folder contains all source code (`*.cpp`) and headers (`*.h`) for libopenshot.
+
+#### `bindings/`
+This folder contains language bindings for the libopenshot API.
+Current supported languages are Python and Ruby.
+
+#### `examples/`
+This folder contains various pieces of example code written in C++, Ruby, or Python.
+It also holds the media files (data files) used in examples and unit tests.
#### `tests/`
This folder contains all unit test code.
Each test file (`_Tests.cpp`) contains the tests for the named class.
-We use UnitTest++ macros to keep the test code simple and manageable.
+We use UnitTest++ macros to keep the test code uncomplicated and manageable.
#### `thirdparty/`
This folder contains code not written by the OpenShot team.
@@ -113,79 +148,91 @@ locates header files and libraries, and generates a build system in various form
We use CMake's Makefile generators to compile libopenshot and libopenshot-audio.
CMake uses an out-of-source build concept.
-This means that the build system, all temporary files, and all generated products are kept separate from the source code.
+This means that the build system,
+along with all temporary/intermediate files and generated products output during the build,
+is kept strictly separate from the source code.
This includes Makefiles, object files, and even the final binaries.
-While it is possible to build in-tree, we highly recommend you use a `/build/` sub-folder to compile each library.
-This prevents the build process from cluttering up the source
-code.
-These instructions have only been tested with the GNU compiler suite (including MSYS2/MinGW for Windows), and the Clang compiler (including AppleClang on MacOS).
+The source code files and directories are never modified by the build system,
+which makes it convenient and safe to re-run, reconfigure, or discard builds as needed.
+While it is possible to build in-tree,
+we highly recommend you use a `/build/` sub-folder to compile each library.
+
+These instructions have only been tested with the following compiler stacks:
+* The GNU compiler suite (including MSYS2/MinGW for Windows)
+* The Clang compiler (including AppleClang on MacOS)
+
+Other compilers, including MSVC, are entirely unsupported.
+It may be possible to build libopenshot using other compiler stacks,
+but most likely not without modifications to the build system which you would have to make yourself.
-## CMake Flags (Optional)
-There are many different build flags that can be passed to cmake to adjust how libopenshot is compiled. Some of these flags might be required when compiling on certain OSes, just depending on how your build environment is setup.
+### CMake Flags (Optional)
+There are many different build flags that can be passed to cmake to adjust how libopenshot is compiled.
+Some of these flags might be required when compiling on certain OSes,
+depending on how your build environment is setup.
To add a build flag, follow this general syntax:
```sh
-$ cmake -DMAGICKCORE_HDRI_ENABLE=1 -DENABLE_TESTS=1 ..
+cmake -B build -S . -DMAGICKCORE_HDRI_ENABLE=1 -DENABLE_TESTS=1 ...
```
Following are some of the flags you might need to set when generating your build system.
-##### Optional behavior:
-* `-DENABLE_TESTS=0` (default: `ON`)
-* `-DENABLE_COVERAGE=1` (default: `OFF`)
-* `-DENABLE_DOCS=0` (default: `ON` if doxygen found)
-
-##### Compiler configuration:
-* `-DCMAKE_BUILD_TYPE=Release`, `-DCMAKE_BUILD_TYPE=Debug` (default: `Debug` if unset)
-* `-DCMAKE_CXX_FLAGS="-Wall -Wextra"` (default: CMake builtin defaults for build type)
-* `-DCMAKE_CXX_COMPILER=/path/to/g++`, `-DCMAKE_CXX_COMPILER=/path/to/clang++`
-* `-DCMAKE_C_COMPILER=/path/to/gcc`, `-DCMAKE_CXX_COMPILER=/path/to/clang` (used by CMake for OS probes)
-
-##### Dependency configuration:
-* `-DCMAKE_PREFIX_PATH=/extra/path/to/search/for/libraries/`
-* `-DUSE_SYSTEM_JSONCPP=0` (default: auto if discovered)
-* `-DImageMagick_FOUND=0` (default: auto if discovered)
-
-##### To compile bindings for a specific Python installation:
-* `-DPYTHON_INCLUDE_DIR=/location/of/python/includes/`
-* `-DPYTHON_LIBRARY=/location/of/libpython*.so`
-* `-DPYTHON_FRAMEWORKS=/usr/local/Cellar/python3/3.3.2/Frameworks/Python.framework/` (MacOS only)
-
-##### Only used when building with ImageMagick enabled:
-* `-DMAGICKCORE_HDRI_ENABLE=1` (default `0`)
-* `-DMAGICKCORE_QUANTUM_DEPTH=8` (default `16`)
+#### Optional behaviors of the build system
+* `-DENABLE_TESTS=0` (default: `ON`)
+* `-DENABLE_COVERAGE=1` (default: `OFF`)
+* `-DENABLE_DOCS=0` (default: `ON` if doxygen found)
+* `-DENABLE_RUBY=0` (default: `ON` if SWIG and Ruby detected)
+* `-DENABLE_PYTHON=0` (default: `ON` if SWIG and Python detected)
+
+#### Options to configure the compiler
+* `-DCMAKE_BUILD_TYPE=Release`, `-DCMAKE_BUILD_TYPE=Debug` (default: `Release` if unset)
+* `-DCMAKE_CXX_FLAGS="-Wall -Wextra"` (default: CMake builtin defaults for build type)
+* `-DCMAKE_CXX_COMPILER=/path/to/g++`, `-DCMAKE_CXX_COMPILER=/path/to/clang++`
+* `-DCMAKE_C_COMPILER=/path/to/gcc`, `-DCMAKE_CXX_COMPILER=/path/to/clang` (used by CMake for OS probes)
+
+#### Options to configure dependencies
+* `-DCMAKE_PREFIX_PATH=/extra/path/to/search/for/libraries/`
+* `-DUSE_SYSTEM_JSONCPP=0` (default: auto if discovered)
+* `-DENABLE_MAGICK=0` (default: auto if discovered)
+
+#### Options to compile bindings for a specific Python installation
+* `-DPYTHON_INCLUDE_DIR=/location/of/python/includes/`
+* `-DPYTHON_LIBRARY=/location/of/libpython*.so`
+* `-DPYTHON_FRAMEWORKS=/usr/local/Cellar/python3/3.3.2/Frameworks/Python.framework/` (MacOS only)
+
+#### Options only relevant when building with ImageMagick
+* `-DMAGICKCORE_HDRI_ENABLE=1` (default `0`)
+* `-DMAGICKCORE_QUANTUM_DEPTH=8` (default `16`)
## Linux Build Instructions (libopenshot-audio)
-To compile libopenshot-audio, we need to go through a few additional steps to manually build and install it. Launch a terminal and enter:
+To compile libopenshot-audio, we need to build it from source code and install the results.
+Launch a terminal and enter:
-```
+```sh
cd [libopenshot-audio repo folder]
-mkdir build
-cd build
-cmake ../
-make
-make install
-./src/openshot-audio-test-sound (This should play a test sound)
+cmake -B build -S .
+cmake --build build
+./build/src/openshot-audio-test-sound (This should play a test sound)
+cmake --install build
```
## Linux Build Instructions (libopenshot)
Run the following commands to compile libopenshot:
-```
+```sh
cd [libopenshot repo directory]
-mkdir -p build
-cd build
-cmake ../
-make
-make install
+cmake -B build -S .
+cmake --build build
+cmake --build build --target test
+cmake --install build
```
For more detailed instructions, please see:
-* [doc/INSTALL-LINUX.md][INSTALL-LINUX]
-* [doc/INSTALL-MAC.md][INSTALL-MAC]
-* [doc/INSTALL-WINDOWS.md][INSTALL-WINDOWS]
+* [doc/INSTALL-LINUX.md][INSTALL-LINUX]
+* [doc/INSTALL-MAC.md][INSTALL-MAC]
+* [doc/INSTALL-WINDOWS.md][INSTALL-WINDOWS]
[INSTALL-LINUX]: https://github.com/OpenShot/libopenshot/blob/develop/doc/INSTALL-LINUX.md
[INSTALL-MAC]: https://github.com/OpenShot/libopenshot/blob/develop/doc/INSTALL-MAC.md
diff --git a/src/bindings/CMakeLists.txt b/bindings/CMakeLists.txt
similarity index 100%
rename from src/bindings/CMakeLists.txt
rename to bindings/CMakeLists.txt
diff --git a/src/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt
similarity index 97%
rename from src/bindings/python/CMakeLists.txt
rename to bindings/python/CMakeLists.txt
index 6d7ce79ea..b020592bd 100644
--- a/src/bindings/python/CMakeLists.txt
+++ b/bindings/python/CMakeLists.txt
@@ -50,11 +50,11 @@ include_directories(${PYTHON_INCLUDE_PATH})
if (CMAKE_VERSION VERSION_LESS 3.12)
### Include project headers
include_directories(
- "${PROJECT_SOURCE_DIR}/include"
- "${PROJECT_BINARY_DIR}/include")
+ "${PROJECT_SOURCE_DIR}/src"
+ "${PROJECT_BINARY_DIR}/src")
endif()
-### Enable C++ support in SWIG
+### Enable C++ in SWIG
set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON)
set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot)
diff --git a/src/bindings/python/openshot.i b/bindings/python/openshot.i
similarity index 98%
rename from src/bindings/python/openshot.i
rename to bindings/python/openshot.i
index 36d030cf9..c204b4070 100644
--- a/src/bindings/python/openshot.i
+++ b/bindings/python/openshot.i
@@ -92,6 +92,7 @@
#include "KeyFrame.h"
#include "RendererBase.h"
#include "Settings.h"
+#include "TimelineBase.h"
#include "Timeline.h"
#include "ZmqLogger.h"
#include "AudioDeviceInfo.h"
@@ -212,6 +213,7 @@
%include "KeyFrame.h"
%include "RendererBase.h"
%include "Settings.h"
+%include "TimelineBase.h"
%include "Timeline.h"
%include "ZmqLogger.h"
%include "AudioDeviceInfo.h"
@@ -255,5 +257,5 @@
%template(PointsVector) std::vector;
%template(FieldVector) std::vector;
%template(MappedFrameVector) std::vector;
-%template(MappedMetadata) std::map;
+%template(MetadataMap) std::map;
%template(AudioDeviceInfoVector) std::vector;
diff --git a/src/bindings/ruby/CMakeLists.txt b/bindings/ruby/CMakeLists.txt
similarity index 88%
rename from src/bindings/ruby/CMakeLists.txt
rename to bindings/ruby/CMakeLists.txt
index 2ec16dcf3..72d1a9857 100644
--- a/src/bindings/ruby/CMakeLists.txt
+++ b/bindings/ruby/CMakeLists.txt
@@ -46,11 +46,11 @@ endif()
option(SILENCE_RUBY_VERSION_WARNING
"Don't warn about possible SWIG incompatibilities with Ruby 2.7.0+" OFF)
-if (${RUBY_VERSION} VERSION_GREATER 2.6.9 AND ${SWIG_VERSION} VERSION_LESS 4.0.3)
+if (${RUBY_VERSION} VERSION_GREATER 2.6.9 AND ${SWIG_VERSION} VERSION_LESS 4.0.2)
if (NOT ${SILENCE_RUBY_VERSION_WARNING})
message(WARNING "\
Ruby 2.7.0+ detected, building the libopenshot Ruby API bindings \
-requires either SWIG 4.0.3 or an older version patched with this commit: \
+requires either SWIG 4.0.2+ or an older version patched with this commit: \
https://github.com/swig/swig/commit/5542cc228ad10bdc5c91107afb77c808c43bf2a4 \
(Recent Fedora and Ubuntu distro packages of SWIG 4.0.1 have already been \
patched.)")
@@ -64,19 +64,16 @@ endif()
include_directories(${RUBY_INCLUDE_DIRS})
if (CMAKE_VERSION VERSION_LESS 3.12)
- ### Include Ruby header files and project headers
+ ### Include project headers
include_directories(
- "${PROJECT_SOURCE_DIR}/include"
- "${PROJECT_BINARY_DIR}/include")
+ "${PROJECT_SOURCE_DIR}/src"
+ "${PROJECT_BINARY_DIR}/src")
endif()
### Enable C++ in SWIG
set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON)
set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot)
-### Unbreak std::isfinite()
-add_definitions(-DHAVE_ISFINITE=1)
-
### Suppress a ton of warnings in the generated SWIG C++ code
set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function \
-Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \
@@ -99,6 +96,14 @@ else()
swig_add_library(rbopenshot LANGUAGE ruby SOURCES openshot.i)
endif()
+### Set name of target (with no prefix, since Ruby does not like that)
+# XXX: If this is not done exactly this way, the module builds as
+# e.g. rbopenshot.so, but its initializer method will be named
+# 'Init_openshot()' (via the module name set in the SWIG .i file).
+# Which leads to Ruby barfing when it attempts to load the module.
+set_target_properties(${SWIG_MODULE_rbopenshot_REAL_NAME} PROPERTIES
+ PREFIX "" OUTPUT_NAME "openshot")
+
### Link the new Ruby wrapper library with libopenshot
target_link_libraries(${SWIG_MODULE_rbopenshot_REAL_NAME} PUBLIC
${RUBY_LIBRARY} openshot)
diff --git a/src/bindings/ruby/openshot.i b/bindings/ruby/openshot.i
similarity index 94%
rename from src/bindings/ruby/openshot.i
rename to bindings/ruby/openshot.i
index 2f24d2200..e7a6fa7b7 100644
--- a/src/bindings/ruby/openshot.i
+++ b/bindings/ruby/openshot.i
@@ -42,23 +42,20 @@
%include "std_list.i"
%include "std_vector.i"
%include "std_map.i"
+%include
/* Unhandled STL Exception Handling */
%include
-namespace std {
- template class shared_ptr {
- public:
- T *operator->();
- };
-}
+/* Include shared pointer code */
+%include
/* Mark these classes as shared_ptr classes */
#ifdef USE_IMAGEMAGICK
- %template(SPtrImage) std::shared_ptr;
+ %shared_ptr(Magick::Image)
#endif
-%template(SPtrAudioBuffer) std::shared_ptr;
-%template(SPtrOpenFrame) std::shared_ptr;
+%shared_ptr(juce::AudioSampleBuffer)
+%shared_ptr(openshot::Frame)
%{
/* Ruby and FFmpeg define competing RSHIFT macros,
@@ -103,6 +100,7 @@ namespace std {
#include "KeyFrame.h"
#include "RendererBase.h"
#include "Settings.h"
+#include "TimelineBase.h"
#include "Timeline.h"
#include "ZmqLogger.h"
#include "AudioDeviceInfo.h"
@@ -192,6 +190,7 @@ namespace std {
%include "KeyFrame.h"
%include "RendererBase.h"
%include "Settings.h"
+%include "TimelineBase.h"
%include "Timeline.h"
%include "ZmqLogger.h"
%include "AudioDeviceInfo.h"
@@ -227,5 +226,5 @@ namespace std {
%template(PointsVector) std::vector;
%template(FieldVector) std::vector;
%template(MappedFrameVector) std::vector;
-%template(MappedMetadata) std::map;
+%template(MetadataMap) std::map;
%template(AudioDeviceInfoVector) std::vector;
diff --git a/cmake/Modules/FindOpenShotAudio.cmake b/cmake/Modules/FindOpenShotAudio.cmake
index a0cb9200c..4716112e3 100644
--- a/cmake/Modules/FindOpenShotAudio.cmake
+++ b/cmake/Modules/FindOpenShotAudio.cmake
@@ -11,12 +11,14 @@ endif()
# Find the libopenshot-audio header files (check env/cache vars first)
find_path(
- LIBOPENSHOT_AUDIO_INCLUDE_DIR
+ OpenShotAudio_INCLUDE_DIR
JuceHeader.h
HINTS
ENV LIBOPENSHOT_AUDIO_DIR
PATHS
${LIBOPENSHOT_AUDIO_DIR}
+ ${OpenShotAudio_ROOT}
+ ${OpenShotAudio_INCLUDE_DIR}
PATH_SUFFIXES
include/libopenshot-audio
libopenshot-audio
@@ -26,12 +28,14 @@ find_path(
# Find the libopenshot-audio header files (fallback to std. paths)
find_path(
- LIBOPENSHOT_AUDIO_INCLUDE_DIR
+ OpenShotAudio_INCLUDE_DIR
JuceHeader.h
HINTS
ENV LIBOPENSHOT_AUDIO_DIR
PATHS
${LIBOPENSHOT_AUDIO_DIR}
+ ${OpenShotAudio_ROOT}
+ ${OpenShotAudio_INCLUDE_DIR}
PATH_SUFFIXES
include/libopenshot-audio
libopenshot-audio
@@ -40,7 +44,7 @@ find_path(
# Find libopenshot-audio.so / libopenshot-audio.dll (check env/cache vars first)
find_library(
- LIBOPENSHOT_AUDIO_LIBRARY
+ OpenShotAudio_LIBRARY
NAMES
libopenshot-audio
openshot-audio
@@ -48,6 +52,8 @@ find_library(
ENV LIBOPENSHOT_AUDIO_DIR
PATHS
${LIBOPENSHOT_AUDIO_DIR}
+ ${OpenShotAudio_ROOT}
+ ${OpenShotAudio_LIBRARY}
PATH_SUFFIXES
lib/libopenshot-audio
libopenshot-audio
@@ -57,7 +63,7 @@ find_library(
# Find libopenshot-audio.so / libopenshot-audio.dll (fallback)
find_library(
- LIBOPENSHOT_AUDIO_LIBRARY
+ OpenShotAudio_LIBRARY
NAMES
libopenshot-audio
openshot-audio
@@ -65,39 +71,41 @@ find_library(
ENV LIBOPENSHOT_AUDIO_DIR
PATHS
${LIBOPENSHOT_AUDIO_DIR}
+ ${OpenShotAudio_ROOT}
+ ${OpenShotAudio_LIBRARY}
PATH_SUFFIXES
lib/libopenshot-audio
libopenshot-audio
lib
)
-set(LIBOPENSHOT_AUDIO_LIBRARIES "${LIBOPENSHOT_AUDIO_LIBRARY}")
-set(LIBOPENSHOT_AUDIO_LIBRARY "${LIBOPENSHOT_AUDIO_LIBRARIES}")
-set(LIBOPENSHOT_AUDIO_INCLUDE_DIRS "${LIBOPENSHOT_AUDIO_INCLUDE_DIR}")
+set(OpenShotAudio_LIBRARIES "${OpenShotAudio_LIBRARY}")
+set(OpenShotAudio_LIBRARY "${OpenShotAudio_LIBRARIES}")
+set(OpenShotAudio_INCLUDE_DIRS "${OpenShotAudio_INCLUDE_DIR}")
-if(LIBOPENSHOT_AUDIO_INCLUDE_DIR AND EXISTS "${LIBOPENSHOT_AUDIO_INCLUDE_DIR}/JuceHeader.h")
- file(STRINGS "${LIBOPENSHOT_AUDIO_INCLUDE_DIR}/JuceHeader.h" libosa_version_str
+if(OpenShotAudio_INCLUDE_DIR AND EXISTS "${OpenShotAudio_INCLUDE_DIR}/JuceHeader.h")
+ file(STRINGS "${OpenShotAudio_INCLUDE_DIR}/JuceHeader.h" libosa_version_str
REGEX "versionString.*=.*\"[^\"]+\"")
if(libosa_version_str MATCHES "versionString.*=.*\"([^\"]+)\"")
- set(LIBOPENSHOT_AUDIO_VERSION_STRING ${CMAKE_MATCH_1})
+ set(OpenShotAudio_VERSION_STRING ${CMAKE_MATCH_1})
endif()
unset(libosa_version_str)
string(REGEX REPLACE "^([0-9]+\.[0-9]+\.[0-9]+).*$" "\\1"
- LIBOPENSHOT_AUDIO_VERSION "${LIBOPENSHOT_AUDIO_VERSION_STRING}")
+ OpenShotAudio_VERSION "${OpenShotAudio_VERSION_STRING}")
endif()
# If we couldn't parse M.N.B version, don't keep any of it
-if(NOT LIBOPENSHOT_AUDIO_VERSION)
- unset(LIBOPENSHOT_AUDIO_VERSION)
- unset(LIBOPENSHOT_AUDIO_VERSION_STRING)
+if(NOT OpenShotAudio_VERSION)
+ unset(OpenShotAudio_VERSION)
+ unset(OpenShotAudio_VERSION_STRING)
endif()
# Determine compatibility with requested version in find_package()
-if(OpenShotAudio_FIND_VERSION AND LIBOPENSHOT_AUDIO_VERSION)
- if("${OpenShotAudio_FIND_VERSION}" STREQUAL "${LIBOPENSHOT_AUDIO_VERSION}")
+if(OpenShotAudio_FIND_VERSION AND OpenShotAudio_VERSION)
+ if("${OpenShotAudio_FIND_VERSION}" STREQUAL "${OpenShotAudio_VERSION}")
set(OpenShotAudio_VERSION_EXACT TRUE)
endif()
- if("${OpenShotAudio_FIND_VERSION}" VERSION_GREATER "${LIBOPENSHOT_AUDIO_VERSION}")
+ if("${OpenShotAudio_FIND_VERSION}" VERSION_GREATER "${OpenShotAudio_VERSION}")
set(OpenShotAudio_VERSION_COMPATIBLE FALSE)
else()
set(OpenShotAudio_VERSION_COMPATIBLE TRUE)
@@ -105,12 +113,76 @@ if(OpenShotAudio_FIND_VERSION AND LIBOPENSHOT_AUDIO_VERSION)
endif()
include(FindPackageHandleStandardArgs)
-# handle the QUIETLY and REQUIRED arguments and set LIBOPENSHOT_AUDIO_FOUND to TRUE
+# handle the QUIETLY and REQUIRED arguments and set OpenShotAudio_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(OpenShotAudio
REQUIRED_VARS
- LIBOPENSHOT_AUDIO_LIBRARY
- LIBOPENSHOT_AUDIO_INCLUDE_DIRS
+ OpenShotAudio_LIBRARIES
+ OpenShotAudio_INCLUDE_DIRS
VERSION_VAR
- LIBOPENSHOT_AUDIO_VERSION_STRING
+ OpenShotAudio_VERSION_STRING
)
+
+if(OpenShotAudio_FOUND)
+ set(OpenShotAudio_INCLUDE_DIRS "${OpenShotAudio_INCLUDE_DIRS}"
+ CACHE PATH "The paths to libopenshot-audio's header files" FORCE)
+ set(OpenShotAudio_LIBRARIES "${OpenShotAudio_LIBRARIES}"
+ CACHE STRING "The libopenshot-audio library to link with" FORCE)
+ if(DEFINED OpenShotAudio_VERSION)
+ set(OpenShotAudio_VERSION ${OpenShotAudio_VERSION}
+ CACHE STRING "The version of libopenshot-audio detected" FORCE)
+ endif()
+endif()
+
+if(OpenShotAudio_FOUND AND NOT TARGET OpenShot::Audio)
+ message(STATUS "Creating IMPORTED target OpenShot::Audio")
+ if(WIN32)
+ add_library(OpenShot::Audio UNKNOWN IMPORTED)
+ else()
+ add_library(OpenShot::Audio SHARED IMPORTED)
+ endif()
+
+ set_property(TARGET OpenShot::Audio APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES "${OpenShotAudio_INCLUDE_DIRS}")
+
+ # Juce requires either DEBUG or NDEBUG to be defined on MacOS.
+ # -DNDEBUG is set by cmake for all release configs, so add
+ # -DDEBUG for debug builds. We'll do this for all OSes, even
+ # though only MacOS requires it.
+ # The generator expression translates to:
+ # CONFIG == "DEBUG" ? "DEBUG" : ""
+ set_property(TARGET OpenShot::Audio APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS $<$:DEBUG>)
+
+ # For the Ruby bindings
+ set_property(TARGET OpenShot::Audio APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS HAVE_ISFINITE=1)
+
+ if(WIN32)
+ set_property(TARGET OpenShot::Audio APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS IGNORE_JUCE_HYPOT=1)
+ set_property(TARGET OpenShot::Audio APPEND PROPERTY
+ INTERFACE_COMPILE_OPTIONS -include cmath)
+ elseif(APPLE)
+ # Prevent compiling with __cxx11
+ set_property(TARGET OpenShot::Audio APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS _GLIBCXX_USE_CXX11_ABI=0)
+ list(APPEND framework_deps
+ "-framework Carbon"
+ "-framework Cocoa"
+ "-framework CoreFoundation"
+ "-framework CoreAudio"
+ "-framework CoreMidi"
+ "-framework IOKit"
+ "-framework AGL"
+ "-framework AudioToolbox"
+ "-framework QuartzCore"
+ "-lobjc"
+ "-framework Accelerate"
+ )
+ target_link_libraries(OpenShot::Audio INTERFACE ${framework_deps})
+ endif()
+
+ set_property(TARGET OpenShot::Audio APPEND PROPERTY
+ IMPORTED_LOCATION "${OpenShotAudio_LIBRARIES}")
+endif()
diff --git a/cmake/Modules/FindRESVG.cmake b/cmake/Modules/FindResvg.cmake
similarity index 59%
rename from cmake/Modules/FindRESVG.cmake
rename to cmake/Modules/FindResvg.cmake
index 0538eacd5..452a81c8b 100644
--- a/cmake/Modules/FindRESVG.cmake
+++ b/cmake/Modules/FindResvg.cmake
@@ -1,13 +1,13 @@
# vim: ts=2 sw=2
#[=======================================================================[.rst:
-FindRESVG
+FindResvg
---------
Try to find the shared-library build of resvg, the Rust SVG library
IMPORTED targets
^^^^^^^^^^^^^^^^
-This module defines :prop_tgt:`IMPORTED` target ``RESVG::resvg`` when
+This module defines :prop_tgt:`IMPORTED` target ``Resvg::Resvg`` when
the library and headers are found.
Result Variables
@@ -17,10 +17,10 @@ This module defines the following variables:
::
- RESVG_FOUND - Library and header files found
- RESVG_INCLUDE_DIRS - Include directory path
- RESVG_LIBRARIES - Link path to the library
- RESVG_DEFINITIONS - Compiler switches (currently unused)
+ Resvg_FOUND - Library and header files found
+ Resvg_INCLUDE_DIRS - Include directory path
+ Resvg_LIBRARIES - Link path to the library
+ Resvg_DEFINITIONS - Compiler switches (currently unused)
Backwards compatibility
^^^^^^^^^^^^^^^^^^^^^^^
@@ -47,7 +47,7 @@ if(DEFINED RESVGDIR AND CMAKE_VERSION VERSION_GREATER 3.4)
BASE_DIR ${CMAKE_CURRENT_BINARY_DIR})
endif()
-find_path(RESVG_INCLUDE_DIRS
+find_path(Resvg_INCLUDE_DIRS
ResvgQt.h
PATHS
${RESVGDIR}
@@ -62,7 +62,7 @@ find_path(RESVG_INCLUDE_DIRS
resvg/capi/include
)
-find_library(RESVG_LIBRARIES
+find_library(Resvg_LIBRARIES
NAMES resvg
PATHS
${RESVGDIR}
@@ -77,39 +77,39 @@ find_library(RESVG_LIBRARIES
resvg/target/release
)
-if (RESVG_INCLUDE_DIRS AND RESVG_LIBRARIES)
- set(RESVG_FOUND TRUE)
+if (Resvg_INCLUDE_DIRS AND Resvg_LIBRARIES)
+ set(Resvg_FOUND TRUE)
endif()
-set(RESVG_LIBRARIES ${RESVG_LIBRARIES} CACHE STRING "The Resvg library link path")
-set(RESVG_INCLUDE_DIRS ${RESVG_INCLUDE_DIRS} CACHE STRING "The Resvg include directories")
-set(RESVG_DEFINITIONS "" CACHE STRING "The Resvg CFLAGS")
+set(Resvg_LIBRARIES ${Resvg_LIBRARIES} CACHE STRING "The Resvg library link path")
+set(Resvg_INCLUDE_DIRS ${Resvg_INCLUDE_DIRS} CACHE STRING "The Resvg include directories")
+set(Resvg_DEFINITIONS "" CACHE STRING "The Resvg CFLAGS")
-mark_as_advanced(RESVG_LIBRARIES RESVG_INCLUDE_DIRS RESVG_DEFINITIONS)
+mark_as_advanced(Resvg_LIBRARIES Resvg_INCLUDE_DIRS Resvg_DEFINITIONS)
# Give a nice error message if some of the required vars are missing.
-find_package_handle_standard_args(RESVG
- "Could NOT find RESVG, using Qt SVG parsing instead"
- RESVG_LIBRARIES RESVG_INCLUDE_DIRS )
+find_package_handle_standard_args(Resvg
+ "Could NOT find Resvg, using Qt SVG parsing instead"
+ Resvg_LIBRARIES Resvg_INCLUDE_DIRS )
# Export target
-if(RESVG_FOUND AND NOT TARGET RESVG::resvg)
- message(STATUS "Creating IMPORTED target RESVG::resvg")
+if(Resvg_FOUND AND NOT TARGET Resvg::Resvg)
+ message(STATUS "Creating IMPORTED target Resvg::Resvg")
if (WIN32)
# Windows mis-links SHARED library targets
- add_library(RESVG::resvg UNKNOWN IMPORTED)
+ add_library(Resvg::Resvg UNKNOWN IMPORTED)
else()
# Linux needs SHARED to link because libresvg has no SONAME
- add_library(RESVG::resvg SHARED IMPORTED)
- set_property(TARGET RESVG::resvg APPEND PROPERTY
+ add_library(Resvg::Resvg SHARED IMPORTED)
+ set_property(TARGET Resvg::Resvg APPEND PROPERTY
IMPORTED_NO_SONAME TRUE)
endif()
- set_property(TARGET RESVG::resvg APPEND PROPERTY
- INTERFACE_INCLUDE_DIRECTORIES "${RESVG_INCLUDE_DIRS}")
+ set_property(TARGET Resvg::Resvg APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES "${Resvg_INCLUDE_DIRS}")
- set_property(TARGET RESVG::resvg APPEND PROPERTY
- INTERFACE_COMPILE_DEFINITIONS "${RESVG_DEFINITIONS}")
+ set_property(TARGET Resvg::Resvg APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS "${Resvg_DEFINITIONS}")
- set_property(TARGET RESVG::resvg APPEND PROPERTY
- IMPORTED_LOCATION "${RESVG_LIBRARIES}")
+ set_property(TARGET Resvg::Resvg APPEND PROPERTY
+ IMPORTED_LOCATION "${Resvg_LIBRARIES}")
endif()
diff --git a/codecov.yml b/codecov.yml
index ee151daaf..e00103e78 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -7,10 +7,11 @@ coverage:
base: pr # Only post a status to pull requests
informational: true # Don't block PRs based on coverage stats (yet?)
ignore:
- - "/src/examples"
- - "/src/Qt/demo"
- - "/thirdparty/jsoncpp/*.cpp"
- - "/thirdparty/jsoncpp/json/*.h"
+ - "/examples"
+ - "/bindings"
+ - "/thirdparty/jsoncpp"
- "/doc"
- "/cmake"
- "/*.md"
+ - "bindings"
+ - "src/openshot_autogen"
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644
index 000000000..874751288
--- /dev/null
+++ b/examples/CMakeLists.txt
@@ -0,0 +1,65 @@
+####################### CMakeLists.txt (libopenshot) #########################
+# @brief CMake build file for libopenshot (used to generate makefiles)
+# @author Jonathan Thomas
+# @author FeRD (Frank Dana)
+#
+# @section LICENSE
+#
+# Copyright (c) 2008-2020 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(GNUInstallDirs)
+
+# Dependencies
+find_package(Qt5 COMPONENTS Gui REQUIRED)
+
+############### CLI EXECUTABLES ################
+# Create test executable
+add_executable(openshot-example Example.cpp)
+
+# Define path to test input files
+file(TO_NATIVE_PATH "${PROJECT_SOURCE_DIR}/examples/" TEST_MEDIA_PATH)
+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)
+
+add_executable(openshot-html-test ExampleHtml.cpp)
+target_link_libraries(openshot-html-test openshot Qt5::Gui)
+
+############### PLAYER EXECUTABLE ################
+# Create test executable
+add_executable(openshot-player qt-demo/main.cpp)
+
+set_target_properties(openshot-player PROPERTIES AUTOMOC ON)
+
+# Link test executable to the new library
+target_link_libraries(openshot-player openshot)
+
+############### TEST BLACKMAGIC CAPTURE APP ################
+if (BLACKMAGIC_FOUND)
+ # Create test executable
+ add_executable(openshot-blackmagic
+ examples/ExampleBlackmagic.cpp)
+
+ # Link test executable to the new library
+ target_link_libraries(openshot-blackmagic openshot)
+endif()
diff --git a/src/examples/Example.cpp b/examples/Example.cpp
similarity index 97%
rename from src/examples/Example.cpp
rename to examples/Example.cpp
index c9e616288..2cd770712 100644
--- a/src/examples/Example.cpp
+++ b/examples/Example.cpp
@@ -31,8 +31,8 @@
#include
#include
#include
-#include "../../include/OpenShot.h"
-#include "../../include/CrashHandler.h"
+#include "OpenShot.h"
+#include "CrashHandler.h"
using namespace openshot;
diff --git a/src/examples/Example.py b/examples/Example.py
similarity index 100%
rename from src/examples/Example.py
rename to examples/Example.py
diff --git a/src/examples/Example.rb b/examples/Example.rb
similarity index 66%
rename from src/examples/Example.rb
rename to examples/Example.rb
index 7d2e4e1aa..5e4c79409 100644
--- a/src/examples/Example.rb
+++ b/examples/Example.rb
@@ -1,13 +1,13 @@
# Find and load the ruby libopenshot wrapper library
-require "./openshot"
+require "openshot"
# Create a new FFmpegReader and Open it
-r = OpenShot::FFmpegReader.new("myfile.mp4")
+r = Openshot::FFmpegReader.new("test.mp4")
r.Open()
# Get frame 1
f = r.GetFrame(1)
# Display the frame
-r.Display()
+f.Display()
diff --git a/src/examples/ExampleBlackmagic.cpp b/examples/ExampleBlackmagic.cpp
similarity index 100%
rename from src/examples/ExampleBlackmagic.cpp
rename to examples/ExampleBlackmagic.cpp
diff --git a/src/examples/ExampleHtml.cpp b/examples/ExampleHtml.cpp
similarity index 97%
rename from src/examples/ExampleHtml.cpp
rename to examples/ExampleHtml.cpp
index 576961bc5..928a05fe8 100644
--- a/src/examples/ExampleHtml.cpp
+++ b/examples/ExampleHtml.cpp
@@ -35,8 +35,8 @@
#include
#include
-#include "../../include/OpenShot.h"
-#include "../../include/CrashHandler.h"
+#include "OpenShot.h"
+#include "CrashHandler.h"
using namespace openshot;
diff --git a/src/examples/ExampleHtml.py b/examples/ExampleHtml.py
similarity index 100%
rename from src/examples/ExampleHtml.py
rename to examples/ExampleHtml.py
diff --git a/src/examples/OpenShot Wipe Tests.py b/examples/OpenShot Wipe Tests.py
similarity index 100%
rename from src/examples/OpenShot Wipe Tests.py
rename to examples/OpenShot Wipe Tests.py
diff --git a/src/examples/back.png b/examples/back.png
similarity index 100%
rename from src/examples/back.png
rename to examples/back.png
diff --git a/src/examples/final-composite.png b/examples/final-composite.png
similarity index 100%
rename from src/examples/final-composite.png
rename to examples/final-composite.png
diff --git a/src/examples/front.png b/examples/front.png
similarity index 100%
rename from src/examples/front.png
rename to examples/front.png
diff --git a/src/examples/front3.png b/examples/front3.png
similarity index 100%
rename from src/examples/front3.png
rename to examples/front3.png
diff --git a/src/examples/interlaced.png b/examples/interlaced.png
similarity index 100%
rename from src/examples/interlaced.png
rename to examples/interlaced.png
diff --git a/src/examples/mask.png b/examples/mask.png
similarity index 100%
rename from src/examples/mask.png
rename to examples/mask.png
diff --git a/src/examples/mask2.png b/examples/mask2.png
similarity index 100%
rename from src/examples/mask2.png
rename to examples/mask2.png
diff --git a/src/examples/output-final.png b/examples/output-final.png
similarity index 100%
rename from src/examples/output-final.png
rename to examples/output-final.png
diff --git a/src/examples/piano-mono.wav b/examples/piano-mono.wav
similarity index 100%
rename from src/examples/piano-mono.wav
rename to examples/piano-mono.wav
diff --git a/src/examples/piano.wav b/examples/piano.wav
similarity index 100%
rename from src/examples/piano.wav
rename to examples/piano.wav
diff --git a/src/Qt/demo/main.cpp b/examples/qt-demo/main.cpp
similarity index 96%
rename from src/Qt/demo/main.cpp
rename to examples/qt-demo/main.cpp
index 3e5f00bab..8c02795ab 100644
--- a/src/Qt/demo/main.cpp
+++ b/examples/qt-demo/main.cpp
@@ -28,7 +28,9 @@
* along with OpenShot Library. If not, see .
*/
-#include "../../../include/Qt/PlayerDemo.h"
+#include "Qt/PlayerDemo.h"
+
+#include
int main(int argc, char *argv[])
{
diff --git a/src/examples/sintel_trailer-720p.mp4 b/examples/sintel_trailer-720p.mp4
similarity index 100%
rename from src/examples/sintel_trailer-720p.mp4
rename to examples/sintel_trailer-720p.mp4
diff --git a/src/examples/test.mp4 b/examples/test.mp4
similarity index 100%
rename from src/examples/test.mp4
rename to examples/test.mp4
diff --git a/src/examples/test.wav b/examples/test.wav
similarity index 100%
rename from src/examples/test.wav
rename to examples/test.wav
diff --git a/src/examples/test1.mp4 b/examples/test1.mp4
similarity index 100%
rename from src/examples/test1.mp4
rename to examples/test1.mp4
diff --git a/src/AudioBufferSource.cpp b/src/AudioBufferSource.cpp
index 69e5713ad..6b2bc59e2 100644
--- a/src/AudioBufferSource.cpp
+++ b/src/AudioBufferSource.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/AudioBufferSource.h"
+#include "AudioBufferSource.h"
using namespace std;
using namespace openshot;
diff --git a/include/AudioBufferSource.h b/src/AudioBufferSource.h
similarity index 100%
rename from include/AudioBufferSource.h
rename to src/AudioBufferSource.h
diff --git a/include/AudioDeviceInfo.h b/src/AudioDeviceInfo.h
similarity index 100%
rename from include/AudioDeviceInfo.h
rename to src/AudioDeviceInfo.h
diff --git a/src/AudioReaderSource.cpp b/src/AudioReaderSource.cpp
index 999d109d2..b6a01a890 100644
--- a/src/AudioReaderSource.cpp
+++ b/src/AudioReaderSource.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/AudioReaderSource.h"
+#include "AudioReaderSource.h"
using namespace std;
using namespace openshot;
diff --git a/include/AudioReaderSource.h b/src/AudioReaderSource.h
similarity index 100%
rename from include/AudioReaderSource.h
rename to src/AudioReaderSource.h
diff --git a/src/AudioResampler.cpp b/src/AudioResampler.cpp
index 145f5d91f..8c27043e5 100644
--- a/src/AudioResampler.cpp
+++ b/src/AudioResampler.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/AudioResampler.h"
+#include "AudioResampler.h"
using namespace std;
using namespace openshot;
diff --git a/include/AudioResampler.h b/src/AudioResampler.h
similarity index 100%
rename from include/AudioResampler.h
rename to src/AudioResampler.h
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 79c12c8c1..e47105886 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -90,51 +90,6 @@ if (ImageMagick_FOUND)
mark_as_advanced(HAVE_IMAGEMAGICK)
endif()
-################ OPENCV ##################
-
-find_package( OpenCV 4 )
-if (OpenCV_FOUND)
- message("\nCOMPILING WITH OPENCV\n")
- set(CMAKE_SWIG_FLAGS "-DUSE_OPENCV=1")
- add_definitions( -DUSE_OPENCV=1 )
-else()
- message("\nOPENCV NOT FOUND, SOME FUNCTIONALITIES WILL BE DISABLED\n")
-endif()
-
-################ PROTOBUF ##################
-if (OpenCV_FOUND)
- find_package(Protobuf 3)
-
- if (NOT Protobuf_FOUND)
- # Protobuf is required when compiling with opencv
- message(FATAL_ERROR "\nPLEASE INSTALL PROTOBUF. Protobuf is required when compiling with opencv.\n")
- endif()
-
- include_directories(${PROTOBUF_INCLUDE_DIR})
-
- set(PROTOBUF_MESSAGES_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/protobuf_messages")
-
- FILE(GLOB PROTO_MSGS "${PROTOBUF_MESSAGES_FOLDER}/*.proto")
- foreach(PROTO_MSG ${PROTO_MSGS})
- execute_process (
- COMMAND bash -c "${PROTOBUF_PROTOC_EXECUTABLE} -I=${PROTOBUF_MESSAGES_FOLDER} --cpp_out=${PROTOBUF_MESSAGES_FOLDER} ${PROTO_MSG}"
- )
- endforeach()
-
- FILE(GLOB PROTO_CCS "${PROTOBUF_MESSAGES_FOLDER}/*.pb.cc")
- foreach(PROTO_CC ${PROTO_CCS})
- execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${PROTO_CC} ${CMAKE_CURRENT_SOURCE_DIR})
- file(REMOVE ${PROTO_CC})
- endforeach()
-
- FILE(GLOB PROTO_HS "${PROTOBUF_MESSAGES_FOLDER}/*.pb.h")
- foreach(PROTO_H ${PROTO_HS})
- execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${PROTO_H} ${CMAKE_CURRENT_SOURCE_DIR}/../include)
- file(REMOVE ${PROTO_H})
- endforeach()
-
-endif()
-
################# LIBOPENSHOT-AUDIO ###################
# Find JUCE-based openshot Audio libraries
find_package(OpenShotAudio 0.2.0 REQUIRED)
@@ -221,6 +176,7 @@ set(OPENSHOT_SOURCES
QtPlayer.cpp
QtTextReader.cpp
Settings.cpp
+ TimelineBase.cpp
Timeline.cpp)
# OpenCV related classes
@@ -271,9 +227,6 @@ set(QT_PLAYER_SOURCES
Qt/VideoRenderer.cpp
Qt/VideoRenderWidget.cpp)
-# Get list of MOC'able headers
-file(GLOB_RECURSE OPENSHOT_QT_HEADERS ${CMAKE_SOURCE_DIR}/include/Qt/*.h)
-
# Disable RPATH
set(CMAKE_MACOSX_RPATH 0)
@@ -285,31 +238,78 @@ target_sources(openshot PRIVATE
${OPENSHOT_SOURCES}
${EFFECTS_SOURCES}
${QT_PLAYER_SOURCES}
- ${OPENSHOT_QT_HEADERS})
+ )
# Set SONAME and other library properties
set_target_properties(openshot PROPERTIES
AUTOMOC ON
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_SO_VERSION}
- INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib")
+ INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib"
+)
+
+# Location of our includes, both internally and when installed
+target_include_directories(openshot
+ PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ PUBLIC
+ $
+ $
+ $)
+
+################# LIBOPENSHOT-AUDIO ###################
+# Find JUCE-based openshot Audio libraries
+find_package(OpenShotAudio 0.2.0 REQUIRED)
+target_link_libraries(openshot PUBLIC OpenShot::Audio)
+
+###
+### ImageMagick
+###
+
+# Find the ImageMagick++ library
+find_package(ImageMagick COMPONENTS Magick++ MagickWand MagickCore)
-# Add optional ImageMagic-dependent sources
if(ImageMagick_FOUND)
+ if(NOT TARGET ImageMagick::Magick++ AND NOT TARGET Magick++_TARGET)
+ add_library(Magick++_TARGET INTERFACE)
+
+ # Include ImageMagick++ headers (needed for compile)
+ set_property(TARGET Magick++_TARGET APPEND PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES ${ImageMagick_INCLUDE_DIRS})
+
+ # Set the Quantum Depth that ImageMagick was built with (default to 16 bits)
+ if(NOT DEFINED MAGICKCORE_QUANTUM_DEPTH)
+ set(MAGICKCORE_QUANTUM_DEPTH 16)
+ endif()
+ if(NOT DEFINED MAGICKCORE_HDRI_ENABLE)
+ set(MAGICKCORE_HDRI_ENABLE 0)
+ endif()
+
+ set_property(TARGET Magick++_TARGET APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS
+ MAGICKCORE_QUANTUM_DEPTH=${MAGICKCORE_QUANTUM_DEPTH})
+ set_property(TARGET Magick++_TARGET APPEND PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS
+ MAGICKCORE_HDRI_ENABLE=${MAGICKCORE_HDRI_ENABLE})
+
+ target_link_libraries(Magick++_TARGET INTERFACE
+ ${ImageMagick_LIBRARIES})
+
+ # Alias to our namespaced name
+ add_library(ImageMagick::Magick++ ALIAS Magick++_TARGET)
+
+ endif()
+
+ # Add optional ImageMagic-dependent sources
target_sources(openshot PRIVATE
ImageReader.cpp
ImageWriter.cpp
TextReader.cpp)
-endif()
-# BlackMagic related files
-if(BLACKMAGIC_FOUND)
- target_sources(openshot PRIVATE
- DecklinkInput.cpp
- DecklinkReader.cpp
- DecklinkOutput.cpp
- DecklinkWriter.cpp)
-endif()
+ # define a preprocessor macro (used in the C++ source)
+ target_compile_definitions(openshot PUBLIC USE_IMAGEMAGICK=1)
+ list(APPEND CMAKE_SWIG_FLAGS -DUSE_IMAGEMAGICK=1)
# OpenCV related files
if (OpenCV_FOUND)
@@ -328,6 +328,12 @@ target_include_directories(openshot
$
$
$)
+ # Link with ImageMagick library
+ target_link_libraries(openshot PUBLIC ImageMagick::Magick++)
+
+ set(HAVE_IMAGEMAGICK TRUE CACHE BOOL "Building with ImageMagick support" FORCE)
+ mark_as_advanced(HAVE_IMAGEMAGICK)
+endif()
################### JSONCPP #####################
@@ -414,7 +420,10 @@ endif()
target_link_libraries(openshot PUBLIC OpenMP::OpenMP_CXX)
-################### ZEROMQ #####################
+###
+### ZeroMQ
+###
+
# Find ZeroMQ library (used for socket communication & logging)
find_package(ZeroMQ REQUIRED) # Creates libzmq target
@@ -431,39 +440,62 @@ if (TARGET cppzmq)
target_link_libraries(openshot PUBLIC cppzmq)
endif()
-################### RESVG #####################
+###
+### Resvg, the Rust SVG library
+###
+
# Migrate some legacy variable names
-if(DEFINED RESVGDIR AND NOT DEFINED RESVG_ROOT)
- set(RESVG_ROOT ${RESVGDIR})
+if(DEFINED RESVGDIR AND NOT DEFINED Resvg_ROOT)
+ set(Resvg_ROOT ${RESVGDIR})
endif()
-if(DEFINED ENV{RESVGDIR} AND NOT DEFINED RESVG_ROOT)
- set(RESVG_ROOT $ENV{RESVGDIR})
+if(DEFINED ENV{RESVGDIR} AND NOT DEFINED Resvg_ROOT)
+ set(Resvg_ROOT $ENV{RESVGDIR})
endif()
# Find resvg library (used for rendering svg files)
-find_package(RESVG)
+find_package(Resvg)
# Include resvg headers (optional SVG library)
-if (TARGET RESVG::resvg)
- #include_directories(${RESVG_INCLUDE_DIRS})
- target_link_libraries(openshot PUBLIC RESVG::resvg)
+if (TARGET Resvg::Resvg)
+ #include_directories(${Resvg_INCLUDE_DIRS})
+ target_link_libraries(openshot PUBLIC Resvg::Resvg)
- target_compile_definitions(openshot PUBLIC "-DUSE_RESVG=1")
- list(APPEND CMAKE_SWIG_FLAGS "-DUSE_RESVG=1")
+ target_compile_definitions(openshot PUBLIC -DUSE_RESVG=1)
+ list(APPEND CMAKE_SWIG_FLAGS -DUSE_RESVG=1)
set(HAVE_RESVG TRUE CACHE BOOL "Building with Resvg support" FORCE)
mark_as_advanced(HAVE_RESVG)
+endif()
+
+################# BLACKMAGIC DECKLINK ###################
+# Find BlackMagic DeckLinkAPI libraries
+if (ENABLE_BLACKMAGIC)
+ find_package(BlackMagic)
+ if (BLACKMAGIC_FOUND)
+ # BlackMagic related files
+ target_sources(openshot PRIVATE
+ DecklinkInput.cpp
+ DecklinkReader.cpp
+ DecklinkOutput.cpp
+ DecklinkWriter.cpp)
+
+ # Include Blackmagic headers (needed for compile)
+ target_include_directories(openshot PRIVATE ${BLACKMAGIC_INCLUDE_DIR})
+
+ # Link libopenshot with BlackMagic libs
+ target_link_libraries(openshot PUBLIC ${BLACKMAGIC_LIBRARY_DIR})
+
+ # define a preprocessor macro (used in the C++)
+ target_compile_definitions(openshot PUBLIC -DUSE_BLACKMAGIC=1)
+ list(APPEND CMAKE_SWIG_FLAGS -DUSE_BLACKMAGIC=1)
+ endif()
endif()
############### LINK LIBRARY #################
# Link remaining dependency libraries
-target_link_libraries(openshot PUBLIC
- ${LIBOPENSHOT_AUDIO_LIBRARIES}
- ${PROFILER})
-
-if(ImageMagick_FOUND)
- target_link_libraries(openshot PUBLIC ${ImageMagick_LIBRARIES})
+if(DEFINED PROFILER)
+ target_link_libraries(openshot PUBLIC ${PROFILER})
endif()
if(BLACKMAGIC_FOUND)
@@ -479,6 +511,9 @@ if(WIN32)
target_link_libraries(openshot PUBLIC "imagehlp" "dbghelp" )
endif()
+###
+### INSTALL HEADERS & LIBRARY
+###
############### CLI EXECUTABLES ################
# Create test executable
@@ -539,11 +574,14 @@ add_subdirectory(bindings)
install(TARGETS openshot
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
- RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libopenshot)
-install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/
+install(
+ DIRECTORY .
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libopenshot
- FILES_MATCHING PATTERN "*.h")
+ FILES_MATCHING PATTERN "*.h"
+)
############### CPACK PACKAGING ##############
if(MINGW)
diff --git a/src/CacheBase.cpp b/src/CacheBase.cpp
index bc57f3f45..72381792c 100644
--- a/src/CacheBase.cpp
+++ b/src/CacheBase.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/CacheBase.h"
+#include "CacheBase.h"
using namespace std;
using namespace openshot;
diff --git a/include/CacheBase.h b/src/CacheBase.h
similarity index 100%
rename from include/CacheBase.h
rename to src/CacheBase.h
diff --git a/src/CacheDisk.cpp b/src/CacheDisk.cpp
index 91153c8f4..ba5f5d9e2 100644
--- a/src/CacheDisk.cpp
+++ b/src/CacheDisk.cpp
@@ -28,8 +28,8 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/CacheDisk.h"
-#include "../include/QtUtilities.h"
+#include "CacheDisk.h"
+#include "QtUtilities.h"
#include
#include
#include
@@ -231,14 +231,14 @@ std::shared_ptr CacheDisk::GetFrame(int64_t frame_number)
if (path.exists(frame_path)) {
// Load image file
- std::shared_ptr image = std::shared_ptr(new QImage());
+ auto image = std::make_shared();
image->load(frame_path);
// Set pixel formatimage->
- image = std::shared_ptr(new QImage(image->convertToFormat(QImage::Format_RGBA8888)));
+ image = std::make_shared(image->convertToFormat(QImage::Format_RGBA8888_Premultiplied));
// Create frame object
- std::shared_ptr frame(new Frame());
+ auto frame = std::make_shared();
frame->number = frame_number;
frame->AddImage(image);
diff --git a/include/CacheDisk.h b/src/CacheDisk.h
similarity index 100%
rename from include/CacheDisk.h
rename to src/CacheDisk.h
diff --git a/src/CacheMemory.cpp b/src/CacheMemory.cpp
index 70feef03d..685c86ecf 100644
--- a/src/CacheMemory.cpp
+++ b/src/CacheMemory.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/CacheMemory.h"
+#include "CacheMemory.h"
using namespace std;
using namespace openshot;
diff --git a/include/CacheMemory.h b/src/CacheMemory.h
similarity index 100%
rename from include/CacheMemory.h
rename to src/CacheMemory.h
diff --git a/include/ChannelLayouts.h b/src/ChannelLayouts.h
similarity index 100%
rename from include/ChannelLayouts.h
rename to src/ChannelLayouts.h
diff --git a/src/ChunkReader.cpp b/src/ChunkReader.cpp
index c194ce33a..1675962ee 100644
--- a/src/ChunkReader.cpp
+++ b/src/ChunkReader.cpp
@@ -28,8 +28,10 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/ChunkReader.h"
-#include "../include/FFmpegReader.h"
+#include "ChunkReader.h"
+#include "FFmpegReader.h"
+
+#include
using namespace openshot;
@@ -222,7 +224,6 @@ std::shared_ptr ChunkReader::GetFrame(int64_t requested_frame)
// Close existing reader (if needed)
if (local_reader)
{
- std::cout << "Close READER" << std::endl;
// Close and delete old reader
local_reader->Close();
delete local_reader;
@@ -230,7 +231,6 @@ std::shared_ptr ChunkReader::GetFrame(int64_t requested_frame)
try
{
- std::cout << "Load READER: " << chunk_video_path << std::endl;
// Load new FFmpegReader
local_reader = new FFmpegReader(chunk_video_path);
local_reader->Open(); // open reader
diff --git a/include/ChunkReader.h b/src/ChunkReader.h
similarity index 97%
rename from include/ChunkReader.h
rename to src/ChunkReader.h
index 50b260838..7a041f714 100644
--- a/include/ChunkReader.h
+++ b/src/ChunkReader.h
@@ -32,18 +32,12 @@
#define OPENSHOT_CHUNK_READER_H
#include "ReaderBase.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+#include
#include
-#include
+
+#include "Frame.h"
#include "Json.h"
#include "CacheMemory.h"
-#include "Exceptions.h"
namespace openshot
{
diff --git a/src/ChunkWriter.cpp b/src/ChunkWriter.cpp
index f9d653b0c..80ea6d57b 100644
--- a/src/ChunkWriter.cpp
+++ b/src/ChunkWriter.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/ChunkWriter.h"
+#include "ChunkWriter.h"
using namespace openshot;
@@ -134,7 +134,9 @@ void ChunkWriter::WriteFrame(std::shared_ptr frame)
writer_thumb->WriteFrame(last_frame);
} else {
// Write the 1st frame (of the 1st chunk)... since no previous chunk is available
- std::shared_ptr blank_frame(new Frame(1, info.width, info.height, "#000000", info.sample_rate, info.channels));
+ auto blank_frame = std::make_shared(
+ 1, info.width, info.height, "#000000",
+ info.sample_rate, info.channels);
blank_frame->AddColor(info.width, info.height, "#000000");
writer_final->WriteFrame(blank_frame);
writer_preview->WriteFrame(blank_frame);
@@ -157,10 +159,6 @@ void ChunkWriter::WriteFrame(std::shared_ptr frame)
// Write the frames once it reaches the correct chunk size
if (frame_count % chunk_size == 0 && frame_count >= chunk_size)
{
- std::cout << "Done with chunk" << std::endl;
- std::cout << "frame_count: " << frame_count << std::endl;
- std::cout << "chunk_size: " << chunk_size << std::endl;
-
// Pad an additional 12 frames
for (int z = 0; z<12; z++)
{
@@ -229,10 +227,6 @@ void ChunkWriter::Close()
// Write the frames once it reaches the correct chunk size
if (is_writing)
{
- std::cout << "Final chunk" << std::endl;
- std::cout << "frame_count: " << frame_count << std::endl;
- std::cout << "chunk_size: " << chunk_size << std::endl;
-
// Pad an additional 12 frames
for (int z = 0; z<12; z++)
{
diff --git a/include/ChunkWriter.h b/src/ChunkWriter.h
similarity index 100%
rename from include/ChunkWriter.h
rename to src/ChunkWriter.h
diff --git a/src/Clip.cpp b/src/Clip.cpp
index 570424925..f26af54a8 100644
--- a/src/Clip.cpp
+++ b/src/Clip.cpp
@@ -28,17 +28,17 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/Clip.h"
-#include "../include/FFmpegReader.h"
-#include "../include/FrameMapper.h"
+#include "Clip.h"
+#include "FFmpegReader.h"
+#include "FrameMapper.h"
#ifdef USE_IMAGEMAGICK
- #include "../include/ImageReader.h"
- #include "../include/TextReader.h"
+ #include "ImageReader.h"
+ #include "TextReader.h"
#endif
-#include "../include/QtImageReader.h"
-#include "../include/ChunkReader.h"
-#include "../include/DummyReader.h"
-#include "../include/Timeline.h"
+#include "QtImageReader.h"
+#include "ChunkReader.h"
+#include "DummyReader.h"
+#include "Timeline.h"
using namespace openshot;
@@ -69,9 +69,6 @@ void Clip::init_settings()
// Init alpha
alpha = Keyframe(1.0);
- // Init rotation
- init_reader_rotation();
-
// Init time & volume
time = Keyframe(1.0);
volume = Keyframe(1.0);
@@ -79,13 +76,6 @@ void Clip::init_settings()
// Init audio waveform color
wave_color = Color((unsigned char)0, (unsigned char)123, (unsigned char)255, (unsigned char)255);
- // Init crop settings
- crop_gravity = GRAVITY_TOP_LEFT;
- crop_width = Keyframe(1.0);
- crop_height = Keyframe(1.0);
- crop_x = Keyframe(0.0);
- crop_y = Keyframe(0.0);
-
// Init shear and perspective curves
shear_x = Keyframe(0.0);
shear_y = Keyframe(0.0);
@@ -107,6 +97,23 @@ void Clip::init_settings()
// Init audio and video overrides
has_audio = Keyframe(-1.0);
has_video = Keyframe(-1.0);
+
+ // Init reader info struct and cache size
+ init_reader_settings();
+}
+
+// Init reader info details
+void Clip::init_reader_settings() {
+ if (reader) {
+ // Init rotation (if any)
+ init_reader_rotation();
+
+ // Initialize info struct
+ info = reader->info;
+
+ // Initialize Clip cache
+ cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels);
+ }
}
// Init reader's rotation (if any)
@@ -134,14 +141,14 @@ void Clip::init_reader_rotation() {
}
// Default Constructor for a clip
-Clip::Clip() : resampler(NULL), reader(NULL), allocated_reader(NULL)
+Clip::Clip() : resampler(NULL), reader(NULL), allocated_reader(NULL), is_open(false)
{
// Init all default settings
init_settings();
}
// Constructor with reader
-Clip::Clip(ReaderBase* new_reader) : resampler(NULL), reader(new_reader), allocated_reader(NULL)
+Clip::Clip(ReaderBase* new_reader) : resampler(NULL), reader(new_reader), allocated_reader(NULL), is_open(false)
{
// Init all default settings
init_settings();
@@ -153,12 +160,12 @@ Clip::Clip(ReaderBase* new_reader) : resampler(NULL), reader(new_reader), alloca
// Update duration and set parent
if (reader) {
End(reader->info.duration);
- reader->SetParentClip(this);
+ reader->ParentClip(this);
}
}
// Constructor with filepath
-Clip::Clip(std::string path) : resampler(NULL), reader(NULL), allocated_reader(NULL)
+Clip::Clip(std::string path) : resampler(NULL), reader(NULL), allocated_reader(NULL), is_open(false)
{
// Init all default settings
init_settings();
@@ -174,7 +181,7 @@ Clip::Clip(std::string path) : resampler(NULL), reader(NULL), allocated_reader(N
try
{
// Open common video format
- reader = new FFmpegReader(path);
+ reader = new openshot::FFmpegReader(path);
} catch(...) { }
}
@@ -183,7 +190,7 @@ Clip::Clip(std::string path) : resampler(NULL), reader(NULL), allocated_reader(N
try
{
// Open common video format
- reader = new Timeline(path, true);
+ reader = new openshot::Timeline(path, true);
} catch(...) { }
}
@@ -195,13 +202,13 @@ Clip::Clip(std::string path) : resampler(NULL), reader(NULL), allocated_reader(N
try
{
// Try an image reader
- reader = new QtImageReader(path);
+ reader = new openshot::QtImageReader(path);
} catch(...) {
try
{
// Try a video reader
- reader = new FFmpegReader(path);
+ reader = new openshot::FFmpegReader(path);
} catch(...) { }
}
@@ -210,10 +217,10 @@ Clip::Clip(std::string path) : resampler(NULL), reader(NULL), allocated_reader(N
// Update duration and set parent
if (reader) {
End(reader->info.duration);
- reader->SetParentClip(this);
+ reader->ParentClip(this);
allocated_reader = reader;
- init_reader_rotation();
- }
+ // Init reader info struct and cache size
+ init_reader_settings(); }
}
// Destructor
@@ -239,10 +246,10 @@ void Clip::Reader(ReaderBase* new_reader)
reader = new_reader;
// set parent
- reader->SetParentClip(this);
+ reader->ParentClip(this);
- // Init rotation (if any)
- init_reader_rotation();
+ // Init reader info struct and cache size
+ init_reader_settings();
}
/// Get the current reader
@@ -262,6 +269,10 @@ void Clip::Open()
{
// Open the reader
reader->Open();
+ is_open = true;
+
+ // Copy Reader info to Clip
+ info = reader->info;
// Set some clip properties from the file reader
if (end == 0.0)
@@ -275,6 +286,7 @@ void Clip::Open()
// Close the internal reader
void Clip::Close()
{
+ is_open = false;
if (reader) {
ZmqLogger::Instance()->AppendDebugMethod("Clip::Close");
@@ -308,29 +320,64 @@ float Clip::End() const
return end;
}
-// Get an openshot::Frame object for a specific frame number of this reader.
-std::shared_ptr Clip::GetFrame(int64_t requested_frame)
+// Create an openshot::Frame object for a specific frame number of this reader.
+std::shared_ptr Clip::GetFrame(int64_t frame_number)
+{
+ // Check for open reader (or throw exception)
+ if (!is_open)
+ throw ReaderClosed("The Clip is closed. Call Open() before calling this method", "N/A");
+
+ if (reader)
+ {
+ // Adjust out of bounds frame number
+ frame_number = adjust_frame_number_minimum(frame_number);
+
+ // Get the original frame and pass it to GetFrame overload
+ std::shared_ptr original_frame = GetOrCreateFrame(frame_number);
+ return GetFrame(original_frame, frame_number);
+ }
+ else
+ // Throw error if reader not initialized
+ throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.");
+}
+
+// Use an existing openshot::Frame object and draw this Clip's frame onto it
+std::shared_ptr Clip::GetFrame(std::shared_ptr frame, int64_t frame_number)
{
+ // Check for open reader (or throw exception)
+ if (!is_open)
+ throw ReaderClosed("The Clip is closed. Call Open() before calling this method", "N/A");
+
if (reader)
{
// Adjust out of bounds frame number
- requested_frame = adjust_frame_number_minimum(requested_frame);
+ frame_number = adjust_frame_number_minimum(frame_number);
+
+ // Check the cache for this frame
+ std::shared_ptr cached_frame = cache.GetFrame(frame_number);
+ if (cached_frame) {
+ // Debug output
+ ZmqLogger::Instance()->AppendDebugMethod("Clip::GetFrame", "returned cached frame", frame_number);
+
+ // Return the cached frame
+ return cached_frame;
+ }
// Adjust has_video and has_audio overrides
- int enabled_audio = has_audio.GetInt(requested_frame);
+ int enabled_audio = has_audio.GetInt(frame_number);
if (enabled_audio == -1 && reader && reader->info.has_audio)
enabled_audio = 1;
else if (enabled_audio == -1 && reader && !reader->info.has_audio)
enabled_audio = 0;
- int enabled_video = has_video.GetInt(requested_frame);
+ int enabled_video = has_video.GetInt(frame_number);
if (enabled_video == -1 && reader && reader->info.has_video)
enabled_video = 1;
else if (enabled_video == -1 && reader && !reader->info.has_audio)
enabled_video = 0;
// Is a time map detected
- int64_t new_frame_number = requested_frame;
- int64_t time_mapped_number = adjust_frame_number_minimum(time.GetLong(requested_frame));
+ int64_t new_frame_number = frame_number;
+ int64_t time_mapped_number = adjust_frame_number_minimum(time.GetLong(frame_number));
if (time.GetLength() > 1)
new_frame_number = time_mapped_number;
@@ -338,16 +385,9 @@ std::shared_ptr Clip::GetFrame(int64_t requested_frame)
std::shared_ptr original_frame;
original_frame = GetOrCreateFrame(new_frame_number);
- // Create a new frame
- std::shared_ptr frame(new Frame(new_frame_number, 1, 1, "#000000", original_frame->GetAudioSamplesCount(), original_frame->GetAudioChannelsCount()));
- {
- frame->SampleRate(original_frame->SampleRate());
- frame->ChannelsLayout(original_frame->ChannelsLayout());
- }
-
// Copy the image from the odd field
if (enabled_video)
- frame->AddImage(std::shared_ptr(new QImage(*original_frame->GetImage())));
+ frame->AddImage(std::make_shared(*original_frame->GetImage()));
// Loop through each channel, add audio
if (enabled_audio && reader->info.has_audio)
@@ -355,11 +395,34 @@ std::shared_ptr Clip::GetFrame(int64_t requested_frame)
frame->AddAudio(true, channel, 0, original_frame->GetAudioSamples(channel), original_frame->GetAudioSamplesCount(), 1.0);
// Get time mapped frame number (used to increase speed, change direction, etc...)
- get_time_mapped_frame(frame, requested_frame);
+ // TODO: Handle variable # of samples, since this resamples audio for different speeds (only when time curve is set)
+ get_time_mapped_frame(frame, new_frame_number);
+
+ // Adjust # of samples to match requested (the interaction with time curves will make this tricky)
+ // TODO: Implement move samples to/from next frame
// Apply effects to the frame (if any)
apply_effects(frame);
+ // Determine size of image (from Timeline or Reader)
+ int width = 0;
+ int height = 0;
+ if (timeline) {
+ // Use timeline size (if available)
+ width = timeline->preview_width;
+ height = timeline->preview_height;
+ } else {
+ // Fallback to clip size
+ width = reader->info.width;
+ height = reader->info.height;
+ }
+
+ // Apply keyframe / transforms
+ apply_keyframes(frame, width, height);
+
+ // Cache frame
+ cache.Add(frame);
+
// Return processed 'frame'
return frame;
}
@@ -630,21 +693,26 @@ int64_t Clip::adjust_frame_number_minimum(int64_t frame_number)
// Get or generate a blank frame
std::shared_ptr Clip::GetOrCreateFrame(int64_t number)
{
- std::shared_ptr new_frame;
-
- // Init some basic properties about this frame
- int samples_in_frame = Frame::GetSamplesPerFrame(number, reader->info.fps, reader->info.sample_rate, reader->info.channels);
-
try {
// Debug output
- ZmqLogger::Instance()->AppendDebugMethod("Clip::GetOrCreateFrame (from reader)", "number", number, "samples_in_frame", samples_in_frame);
+ ZmqLogger::Instance()->AppendDebugMethod("Clip::GetOrCreateFrame (from reader)", "number", number);
// Attempt to get a frame (but this could fail if a reader has just been closed)
- new_frame = reader->GetFrame(number);
+ std::shared_ptr reader_frame = reader->GetFrame(number);
// Return real frame
- if (new_frame)
- return new_frame;
+ if (reader_frame) {
+ // Create a new copy of reader frame
+ // This allows a clip to modify the pixels and audio of this frame without
+ // changing the underlying reader's frame data
+ //std::shared_ptr reader_copy(new Frame(number, 1, 1, "#000000", reader_frame->GetAudioSamplesCount(), reader_frame->GetAudioChannelsCount()));
+ std::shared_ptr reader_copy(new Frame(*reader_frame.get()));
+ {
+ reader_copy->SampleRate(reader_frame->SampleRate());
+ reader_copy->ChannelsLayout(reader_frame->ChannelsLayout());
+ }
+ return reader_copy;
+ }
} catch (const ReaderClosed & e) {
// ...
@@ -654,14 +722,17 @@ std::shared_ptr Clip::GetOrCreateFrame(int64_t number)
// ...
}
+ // Estimate # of samples needed for this frame
+ int estimated_samples_in_frame = Frame::GetSamplesPerFrame(number, reader->info.fps, reader->info.sample_rate, reader->info.channels);
+
// Debug output
- ZmqLogger::Instance()->AppendDebugMethod("Clip::GetOrCreateFrame (create blank)", "number", number, "samples_in_frame", samples_in_frame);
+ ZmqLogger::Instance()->AppendDebugMethod("Clip::GetOrCreateFrame (create blank)", "number", number, "estimated_samples_in_frame", estimated_samples_in_frame);
// Create blank frame
- new_frame = std::make_shared(number, reader->info.width, reader->info.height, "#000000", samples_in_frame, reader->info.channels);
+ std::shared_ptr new_frame = std::make_shared(number, reader->info.width, reader->info.height, "#000000", estimated_samples_in_frame, reader->info.channels);
new_frame->SampleRate(reader->info.sample_rate);
new_frame->ChannelsLayout(reader->info.channel_layout);
- new_frame->AddAudioSilence(samples_in_frame);
+ new_frame->AddAudioSilence(estimated_samples_in_frame);
return new_frame;
}
@@ -747,11 +818,6 @@ std::string Clip::PropertiesJSON(int64_t requested_frame) const {
root["has_video"]["choices"].append(add_property_choice_json("Off", 0, has_video.GetValue(requested_frame)));
root["has_video"]["choices"].append(add_property_choice_json("On", 1, has_video.GetValue(requested_frame)));
- root["crop_x"] = add_property_json("Crop X", crop_x.GetValue(requested_frame), "float", "", &crop_x, -1.0, 1.0, false, requested_frame);
- root["crop_y"] = add_property_json("Crop Y", crop_y.GetValue(requested_frame), "float", "", &crop_y, -1.0, 1.0, false, requested_frame);
- root["crop_width"] = add_property_json("Crop Width", crop_width.GetValue(requested_frame), "float", "", &crop_width, 0.0, 1.0, false, requested_frame);
- root["crop_height"] = add_property_json("Crop Height", crop_height.GetValue(requested_frame), "float", "", &crop_height, 0.0, 1.0, false, requested_frame);
-
root["wave_color"] = add_property_json("Wave Color", 0.0, "color", "", &wave_color.red, 0, 255, false, requested_frame);
root["wave_color"]["red"] = add_property_json("Red", wave_color.red.GetValue(requested_frame), "float", "", &wave_color.red, 0, 255, false, requested_frame);
root["wave_color"]["blue"] = add_property_json("Blue", wave_color.blue.GetValue(requested_frame), "float", "", &wave_color.blue, 0, 255, false, requested_frame);
@@ -782,10 +848,6 @@ Json::Value Clip::JsonValue() const {
root["time"] = time.JsonValue();
root["volume"] = volume.JsonValue();
root["wave_color"] = wave_color.JsonValue();
- root["crop_width"] = crop_width.JsonValue();
- root["crop_height"] = crop_height.JsonValue();
- root["crop_x"] = crop_x.JsonValue();
- root["crop_y"] = crop_y.JsonValue();
root["shear_x"] = shear_x.JsonValue();
root["shear_y"] = shear_y.JsonValue();
root["origin_x"] = origin_x.JsonValue();
@@ -844,6 +906,9 @@ void Clip::SetJsonValue(const Json::Value root) {
// Set parent data
ClipBase::SetJsonValue(root);
+ // Clear cache
+ cache.Clear();
+
// Set data from Json (if key is found)
if (!root["gravity"].isNull())
gravity = (GravityType) root["gravity"].asInt();
@@ -875,14 +940,6 @@ void Clip::SetJsonValue(const Json::Value root) {
volume.SetJsonValue(root["volume"]);
if (!root["wave_color"].isNull())
wave_color.SetJsonValue(root["wave_color"]);
- if (!root["crop_width"].isNull())
- crop_width.SetJsonValue(root["crop_width"]);
- if (!root["crop_height"].isNull())
- crop_height.SetJsonValue(root["crop_height"]);
- if (!root["crop_x"].isNull())
- crop_x.SetJsonValue(root["crop_x"]);
- if (!root["crop_y"].isNull())
- crop_y.SetJsonValue(root["crop_y"]);
if (!root["shear_x"].isNull())
shear_x.SetJsonValue(root["shear_x"]);
if (!root["shear_y"].isNull())
@@ -961,13 +1018,13 @@ void Clip::SetJsonValue(const Json::Value root) {
if (type == "FFmpegReader") {
// Create new reader
- reader = new FFmpegReader(root["reader"]["path"].asString(), false);
+ reader = new openshot::FFmpegReader(root["reader"]["path"].asString(), false);
reader->SetJsonValue(root["reader"]);
} else if (type == "QtImageReader") {
// Create new reader
- reader = new QtImageReader(root["reader"]["path"].asString(), false);
+ reader = new openshot::QtImageReader(root["reader"]["path"].asString(), false);
reader->SetJsonValue(root["reader"]);
#ifdef USE_IMAGEMAGICK
@@ -987,25 +1044,25 @@ void Clip::SetJsonValue(const Json::Value root) {
} else if (type == "ChunkReader") {
// Create new reader
- reader = new ChunkReader(root["reader"]["path"].asString(), (ChunkVersion) root["reader"]["chunk_version"].asInt());
+ reader = new openshot::ChunkReader(root["reader"]["path"].asString(), (ChunkVersion) root["reader"]["chunk_version"].asInt());
reader->SetJsonValue(root["reader"]);
} else if (type == "DummyReader") {
// Create new reader
- reader = new DummyReader();
+ reader = new openshot::DummyReader();
reader->SetJsonValue(root["reader"]);
} else if (type == "Timeline") {
// Create new reader (always load from file again)
// This prevents FrameMappers from being loaded on accident
- reader = new Timeline(root["reader"]["path"].asString(), true);
+ reader = new openshot::Timeline(root["reader"]["path"].asString(), true);
}
// mark as managed reader and set parent
if (reader) {
- reader->SetParentClip(this);
+ reader->ParentClip(this);
allocated_reader = reader;
}
@@ -1027,21 +1084,30 @@ void Clip::sort_effects()
// Add an effect to the clip
void Clip::AddEffect(EffectBase* effect)
{
+ // Set parent clip pointer
+ effect->ParentClip(this);
+
// Add effect to list
effects.push_back(effect);
// Sort effects
sort_effects();
+
+ // Clear cache
+ cache.Clear();
}
// Remove an effect from the clip
void Clip::RemoveEffect(EffectBase* effect)
{
effects.remove(effect);
+
+ // Clear cache
+ cache.Clear();
}
// Apply effects to the source frame (if any)
-std::shared_ptr Clip::apply_effects(std::shared_ptr frame)
+void Clip::apply_effects(std::shared_ptr frame)
{
// Find Effects at this position and layer
for (auto effect : effects)
@@ -1050,7 +1116,250 @@ std::shared_ptr Clip::apply_effects(std::shared_ptr frame)
frame = effect->GetFrame(frame, frame->number);
} // end effect loop
+}
+
+// Compare 2 floating point numbers for equality
+bool Clip::isEqual(double a, double b)
+{
+ return fabs(a - b) < 0.000001;
+}
+
+
+// Apply keyframes to the source frame (if any)
+void Clip::apply_keyframes(std::shared_ptr frame, int width, int height)
+{
+ // Get actual frame image data
+ std::shared_ptr source_image = frame->GetImage();
+
+ /* REPLACE IMAGE WITH WAVEFORM IMAGE (IF NEEDED) */
+ if (Waveform())
+ {
+ // Debug output
+ ZmqLogger::Instance()->AppendDebugMethod("Clip::apply_keyframes (Generate Waveform Image)", "frame->number", frame->number, "Waveform()", Waveform());
+
+ // Get the color of the waveform
+ int red = wave_color.red.GetInt(frame->number);
+ int green = wave_color.green.GetInt(frame->number);
+ int blue = wave_color.blue.GetInt(frame->number);
+ int alpha = wave_color.alpha.GetInt(frame->number);
+
+ // Generate Waveform Dynamically (the size of the timeline)
+ source_image = frame->GetWaveform(width, height, red, green, blue, alpha);
+ frame->AddImage(std::shared_ptr(source_image));
+ }
+
+ /* ALPHA & OPACITY */
+ if (alpha.GetValue(frame->number) != 1.0)
+ {
+ float alpha_value = alpha.GetValue(frame->number);
+
+ // Get source image's pixels
+ unsigned char *pixels = source_image->bits();
+
+ // Loop through pixels
+ for (int pixel = 0, byte_index=0; pixel < source_image->width() * source_image->height(); pixel++, byte_index+=4)
+ {
+ // Apply alpha to pixel values (since we use a premultiplied value, we must
+ // multiply the alpha with all colors).
+ pixels[byte_index + 0] *= alpha_value;
+ pixels[byte_index + 1] *= alpha_value;
+ pixels[byte_index + 2] *= alpha_value;
+ pixels[byte_index + 3] *= alpha_value;
+ }
+
+ // Debug output
+ ZmqLogger::Instance()->AppendDebugMethod("Clip::apply_keyframes (Set Alpha & Opacity)", "alpha_value", alpha_value, "frame->number", frame->number);
+ }
+
+ /* RESIZE SOURCE IMAGE - based on scale type */
+ QSize source_size = source_image->size();
+ switch (scale)
+ {
+ case (SCALE_FIT): {
+ // keep aspect ratio
+ source_size.scale(width, height, Qt::KeepAspectRatio);
+
+ // Debug output
+ ZmqLogger::Instance()->AppendDebugMethod("Clip::apply_keyframes (Scale: SCALE_FIT)", "frame->number", frame->number, "source_width", source_size.width(), "source_height", source_size.height());
+ break;
+ }
+ case (SCALE_STRETCH): {
+ // ignore aspect ratio
+ source_size.scale(width, height, Qt::IgnoreAspectRatio);
+
+ // Debug output
+ ZmqLogger::Instance()->AppendDebugMethod("Clip::apply_keyframes (Scale: SCALE_STRETCH)", "frame->number", frame->number, "source_width", source_size.width(), "source_height", source_size.height());
+ break;
+ }
+ case (SCALE_CROP): {
+ QSize width_size(width, round(width / (float(source_size.width()) / float(source_size.height()))));
+ QSize height_size(round(height / (float(source_size.height()) / float(source_size.width()))), height);
+
+ // respect aspect ratio
+ if (width_size.width() >= width && width_size.height() >= height)
+ source_size.scale(width_size.width(), width_size.height(), Qt::KeepAspectRatio);
+ else
+ source_size.scale(height_size.width(), height_size.height(), Qt::KeepAspectRatio);
+
+ // Debug output
+ ZmqLogger::Instance()->AppendDebugMethod("Clip::apply_keyframes (Scale: SCALE_CROP)", "frame->number", frame->number, "source_width", source_size.width(), "source_height", source_size.height());
+ break;
+ }
+ case (SCALE_NONE): {
+ // Calculate ratio of source size to project size
+ // Even with no scaling, previews need to be adjusted correctly
+ // (otherwise NONE scaling draws the frame image outside of the preview)
+ float source_width_ratio = source_size.width() / float(width);
+ float source_height_ratio = source_size.height() / float(height);
+ source_size.scale(width * source_width_ratio, height * source_height_ratio, Qt::KeepAspectRatio);
+
+ // Debug output
+ ZmqLogger::Instance()->AppendDebugMethod("Clip::apply_keyframes (Scale: SCALE_NONE)", "frame->number", frame->number, "source_width", source_size.width(), "source_height", source_size.height());
+ break;
+ }
+ }
+
+ /* GRAVITY LOCATION - Initialize X & Y to the correct values (before applying location curves) */
+ float x = 0.0; // left
+ float y = 0.0; // top
+
+ // Adjust size for scale x and scale y
+ float sx = scale_x.GetValue(frame->number); // percentage X scale
+ float sy = scale_y.GetValue(frame->number); // percentage Y scale
+ float scaled_source_width = source_size.width() * sx;
+ float scaled_source_height = source_size.height() * sy;
+
+ switch (gravity)
+ {
+ case (GRAVITY_TOP_LEFT):
+ // This is only here to prevent unused-enum warnings
+ break;
+ case (GRAVITY_TOP):
+ x = (width - scaled_source_width) / 2.0; // center
+ break;
+ case (GRAVITY_TOP_RIGHT):
+ x = width - scaled_source_width; // right
+ break;
+ case (GRAVITY_LEFT):
+ y = (height - scaled_source_height) / 2.0; // center
+ break;
+ case (GRAVITY_CENTER):
+ x = (width - scaled_source_width) / 2.0; // center
+ y = (height - scaled_source_height) / 2.0; // center
+ break;
+ case (GRAVITY_RIGHT):
+ x = width - scaled_source_width; // right
+ y = (height - scaled_source_height) / 2.0; // center
+ break;
+ case (GRAVITY_BOTTOM_LEFT):
+ y = (height - scaled_source_height); // bottom
+ break;
+ case (GRAVITY_BOTTOM):
+ x = (width - scaled_source_width) / 2.0; // center
+ y = (height - scaled_source_height); // bottom
+ break;
+ case (GRAVITY_BOTTOM_RIGHT):
+ x = width - scaled_source_width; // right
+ y = (height - scaled_source_height); // bottom
+ break;
+ }
+
+ // Debug output
+ ZmqLogger::Instance()->AppendDebugMethod("Clip::apply_keyframes (Gravity)", "frame->number", frame->number, "source_clip->gravity", gravity, "scaled_source_width", scaled_source_width, "scaled_source_height", scaled_source_height);
+
+ /* LOCATION, ROTATION, AND SCALE */
+ float r = rotation.GetValue(frame->number); // rotate in degrees
+ x += (width * location_x.GetValue(frame->number)); // move in percentage of final width
+ y += (height * location_y.GetValue(frame->number)); // move in percentage of final height
+ float shear_x_value = shear_x.GetValue(frame->number);
+ float shear_y_value = shear_y.GetValue(frame->number);
+ float origin_x_value = origin_x.GetValue(frame->number);
+ float origin_y_value = origin_y.GetValue(frame->number);
+
+ bool transformed = false;
+ QTransform transform;
+
+ // Transform source image (if needed)
+ ZmqLogger::Instance()->AppendDebugMethod("Clip::apply_keyframes (Build QTransform - if needed)", "frame->number", frame->number, "x", x, "y", y, "r", r, "sx", sx, "sy", sy);
+
+ if (!isEqual(x, 0) || !isEqual(y, 0)) {
+ // TRANSLATE/MOVE CLIP
+ transform.translate(x, y);
+ transformed = true;
+ }
+
+ if (!isEqual(r, 0) || !isEqual(shear_x_value, 0) || !isEqual(shear_y_value, 0)) {
+ // ROTATE CLIP (around origin_x, origin_y)
+ float origin_x_offset = (scaled_source_width * origin_x_value);
+ float origin_y_offset = (scaled_source_height * origin_y_value);
+ transform.translate(origin_x_offset, origin_y_offset);
+ transform.rotate(r);
+ transform.shear(shear_x_value, shear_y_value);
+ transform.translate(-origin_x_offset,-origin_y_offset);
+ transformed = true;
+ }
+
+ // SCALE CLIP (if needed)
+ float source_width_scale = (float(source_size.width()) / float(source_image->width())) * sx;
+ float source_height_scale = (float(source_size.height()) / float(source_image->height())) * sy;
+
+ if (!isEqual(source_width_scale, 1.0) || !isEqual(source_height_scale, 1.0)) {
+ transform.scale(source_width_scale, source_height_scale);
+ transformed = true;
+ }
+
+ // Debug output
+ ZmqLogger::Instance()->AppendDebugMethod("Clip::apply_keyframes (Transform: Composite Image Layer: Prepare)", "frame->number", frame->number, "transformed", transformed);
+
+ /* COMPOSITE SOURCE IMAGE (LAYER) ONTO FINAL IMAGE */
+ std::shared_ptr new_image;
+ new_image = std::shared_ptr(new QImage(QSize(width, height), source_image->format()));
+ new_image->fill(QColor(QString::fromStdString("#00000000")));
+
+ // Load timeline's new frame image into a QPainter
+ QPainter painter(new_image.get());
+ painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing, true);
+
+ // Apply transform (translate, rotate, scale)... if any
+ if (transformed)
+ painter.setTransform(transform);
+
+ // Composite a new layer onto the image
+ painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+ painter.drawImage(0, 0, *source_image);
+
+ if (timeline) {
+ Timeline *t = (Timeline *) timeline;
+
+ // Draw frame #'s on top of image (if needed)
+ if (display != FRAME_DISPLAY_NONE) {
+ std::stringstream frame_number_str;
+ switch (display) {
+ case (FRAME_DISPLAY_NONE):
+ // This is only here to prevent unused-enum warnings
+ break;
+
+ case (FRAME_DISPLAY_CLIP):
+ frame_number_str << frame->number;
+ break;
+
+ case (FRAME_DISPLAY_TIMELINE):
+ frame_number_str << (position * t->info.fps.ToFloat()) + frame->number;
+ break;
+
+ case (FRAME_DISPLAY_BOTH):
+ frame_number_str << (position * t->info.fps.ToFloat()) + frame->number << " (" << frame->number << ")";
+ break;
+ }
+
+ // Draw frame number on top of image
+ painter.setPen(QColor("#ffffff"));
+ painter.drawText(20, 20, QString(frame_number_str.str().c_str()));
+ }
+ }
+
+ painter.end();
- // Return modified frame
- return frame;
+ // Add new QImage to frame
+ frame->AddImage(new_image);
}
diff --git a/include/Clip.h b/src/Clip.h
similarity index 86%
rename from include/Clip.h
rename to src/Clip.h
index 3799ff966..373f2db0c 100644
--- a/include/Clip.h
+++ b/src/Clip.h
@@ -52,6 +52,7 @@
#include "Effects.h"
#include "EffectInfo.h"
#include "Fraction.h"
+#include "Frame.h"
#include "KeyFrame.h"
#include "ReaderBase.h"
#include "JuceHeader.h"
@@ -105,14 +106,24 @@ namespace openshot {
* c2.alpha.AddPoint(384, 1.0); // Animate the alpha to visible (between frame #360 and frame #384)
* @endcode
*/
- class Clip : public openshot::ClipBase {
+ class Clip : public openshot::ClipBase, public openshot::ReaderBase {
protected:
/// Section lock for multiple threads
juce::CriticalSection getFrameCriticalSection;
+ /// Init default settings for a clip
+ void init_settings();
+
+ /// Init reader info details
+ void init_reader_settings();
+
+ /// Update default rotation from reader
+ void init_reader_rotation();
+
private:
bool waveform; ///< Should a waveform be used instead of the clip's image
std::list effects; ///
Is Reader opened
// Audio resampler (if time mapping)
openshot::AudioResampler *resampler;
@@ -128,7 +139,10 @@ namespace openshot {
int64_t adjust_frame_number_minimum(int64_t frame_number);
/// Apply effects to the source frame (if any)
- std::shared_ptr apply_effects(std::shared_ptr frame);
+ void apply_effects(std::shared_ptr frame);
+
+ /// Apply keyframes to the source frame (if any)
+ void apply_keyframes(std::shared_ptr frame, int width, int height);
/// Get file extension
std::string get_file_extension(std::string path);
@@ -139,11 +153,8 @@ namespace openshot {
/// Adjust the audio and image of a time mapped frame
void get_time_mapped_frame(std::shared_ptr frame, int64_t frame_number);
- /// Init default settings for a clip
- void init_settings();
-
- /// Update default rotation from reader
- void init_reader_rotation();
+ /// Compare 2 floating point numbers
+ bool isEqual(double a, double b);
/// Sort effects by order
void sort_effects();
@@ -180,6 +191,17 @@ namespace openshot {
/// Destructor
virtual ~Clip();
+ /// Get the cache object used by this clip
+ CacheMemory* GetCache() { return &cache; };
+
+ /// Determine if reader is open or closed
+ bool IsOpen() override { return is_open; };
+
+ /// Return the type name of the class
+ std::string Name() override { return "Clip"; };
+
+
+
/// @brief Add an effect to the clip
/// @param effect Add an effect to the clip. An effect can modify the audio or video of an openshot::Frame.
void AddEffect(openshot::EffectBase* effect);
@@ -193,11 +215,24 @@ namespace openshot {
/// Look up an effect by ID
openshot::EffectBase* GetEffect(const std::string& id);
- /// @brief Get an openshot::Frame object for a specific frame number of this timeline.
+ /// @brief Get an openshot::Frame object for a specific frame number of this timeline. The image size and number
+ /// of samples match the source reader.
///
- /// @returns The requested frame (containing the image)
- /// @param requested_frame The frame number that is requested
- std::shared_ptr GetFrame(int64_t requested_frame);
+ /// @returns A new openshot::Frame object
+ /// @param frame_number The frame number (starting at 1) of the clip or effect on the timeline.
+ std::shared_ptr GetFrame(int64_t frame_number);
+
+ /// @brief Get an openshot::Frame object for a specific frame number of this timeline. The image size and number
+ /// of samples can be customized to match the Timeline, or any custom output. Extra samples will be moved to the
+ /// next Frame. Missing samples will be moved from the next Frame.
+ ///
+ /// A new openshot::Frame objects is returned, based on a copy from the source image, with all keyframes and clip effects
+ /// rendered.
+ ///
+ /// @returns The modified openshot::Frame object
+ /// @param frame This is ignored on Clip, due to caching optimizations. This frame instance is clobbered with the source frame.
+ /// @param frame_number The frame number (starting at 1) of the clip or effect on the timeline.
+ std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number);
/// Open the internal reader
void Open();
@@ -255,13 +290,6 @@ namespace openshot {
/// Curve representing the color of the audio wave form
openshot::Color wave_color;
- // Crop settings and curves
- openshot::GravityType crop_gravity; ///< Cropping needs to have a gravity to determine what side we are cropping
- openshot::Keyframe crop_width; ///< Curve representing width in percent (0.0=0%, 1.0=100%)
- openshot::Keyframe crop_height; ///< Curve representing height in percent (0.0=0%, 1.0=100%)
- openshot::Keyframe crop_x; ///< Curve representing X offset in percent (-1.0=-100%, 0.0=0%, 1.0=100%)
- openshot::Keyframe crop_y; ///< Curve representing Y offset in percent (-1.0=-100%, 0.0=0%, 1.0=100%)
-
// Perspective curves
openshot::Keyframe perspective_c1_x; ///< Curves representing X for coordinate 1
openshot::Keyframe perspective_c1_y; ///< Curves representing Y for coordinate 1
diff --git a/src/ClipBase.cpp b/src/ClipBase.cpp
index a51c65735..f76959046 100644
--- a/src/ClipBase.cpp
+++ b/src/ClipBase.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/ClipBase.h"
+#include "ClipBase.h"
using namespace openshot;
diff --git a/include/ClipBase.h b/src/ClipBase.h
similarity index 74%
rename from include/ClipBase.h
rename to src/ClipBase.h
index 1f7f55c47..11d2271fa 100644
--- a/include/ClipBase.h
+++ b/src/ClipBase.h
@@ -33,10 +33,13 @@
#include
#include
+#include "CacheMemory.h"
#include "Exceptions.h"
+#include "Frame.h"
#include "Point.h"
#include "KeyFrame.h"
#include "Json.h"
+#include "TimelineBase.h"
namespace openshot {
@@ -54,6 +57,7 @@ namespace openshot {
float start; ///< The position in seconds to start playing (used to trim the beginning of a clip)
float end; ///< The position in seconds to end playing (used to trim the ending of a clip)
std::string previous_properties; ///< This string contains the previous JSON properties
+ openshot::TimelineBase* timeline; ///< Pointer to the parent timeline instance (if any)
/// Generate JSON for a property
Json::Value add_property_json(std::string name, float value, std::string type, std::string memo, const Keyframe* keyframe, float min_value, float max_value, bool readonly, int64_t requested_frame) const;
@@ -62,9 +66,18 @@ namespace openshot {
Json::Value add_property_choice_json(std::string name, int value, int selected_value) const;
public:
+ CacheMemory cache;
/// Constructor for the base clip
- ClipBase() { };
+ ClipBase() {
+ // Initialize values
+ position = 0.0;
+ layer = 0;
+ start = 0.0;
+ end = 0.0;
+ previous_properties = "";
+ timeline = NULL;
+ };
// Compare a clip using the Position() property
bool operator< ( ClipBase& a) { return (Position() < a.Position()); }
@@ -72,6 +85,25 @@ namespace openshot {
bool operator> ( ClipBase& a) { return (Position() > a.Position()); }
bool operator>= ( ClipBase& a) { return (Position() >= a.Position()); }
+ /// @brief This method is required for all derived classes of ClipBase, and returns a
+ /// new openshot::Frame object. All Clip keyframes and effects are resolved into
+ /// pixels.
+ ///
+ /// @returns A new openshot::Frame object
+ /// @param frame_number The frame number (starting at 1) of the clip or effect on the timeline.
+ virtual std::shared_ptr GetFrame(int64_t frame_number) = 0;
+
+ /// @brief This method is required for all derived classes of ClipBase, and returns a
+ /// modified openshot::Frame object
+ ///
+ /// The frame object is passed into this method and used as a starting point (pixels and audio).
+ /// All Clip keyframes and effects are resolved into pixels.
+ ///
+ /// @returns The modified openshot::Frame object
+ /// @param frame The frame object that needs the clip or effect applied to it
+ /// @param frame_number The frame number (starting at 1) of the clip or effect on the timeline.
+ virtual std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) = 0;
+
/// Get basic properties
std::string Id() const { return id; } ///< Get the Id of this clip object
float Position() const { return position; } ///< Get position on timeline (in seconds)
@@ -79,6 +111,7 @@ namespace openshot {
float Start() const { return start; } ///< Get start position (in seconds) of clip (trim start of video)
float End() const { return end; } ///< Get end position (in seconds) of clip (trim end of video)
float Duration() const { return end - start; } ///< Get the length of this clip (in seconds)
+ openshot::TimelineBase* ParentTimeline() { return timeline; } ///< Get the associated Timeline pointer (if any)
/// Set basic properties
void Id(std::string value) { id = value; } ///> Set the Id of this clip object
@@ -86,6 +119,7 @@ namespace openshot {
void Layer(int value) { layer = value; } ///< Set layer of clip on timeline (lower number is covered by higher numbers)
void Start(float value) { start = value; } ///< Set start position (in seconds) of clip (trim start of video)
void End(float value) { end = value; } ///< Set end position (in seconds) of clip (trim end of video)
+ void ParentTimeline(openshot::TimelineBase* new_timeline) { timeline = new_timeline; } ///< Set associated Timeline pointer
/// Get and Set JSON methods
virtual std::string Json() const = 0; ///< Generate JSON string of this object
diff --git a/src/Color.cpp b/src/Color.cpp
index 705ece4a1..622a912ca 100644
--- a/src/Color.cpp
+++ b/src/Color.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/Color.h"
+#include "Color.h"
using namespace openshot;
diff --git a/include/Color.h b/src/Color.h
similarity index 100%
rename from include/Color.h
rename to src/Color.h
diff --git a/src/Coordinate.cpp b/src/Coordinate.cpp
index f87fb7a0e..0d4f577a6 100644
--- a/src/Coordinate.cpp
+++ b/src/Coordinate.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/Coordinate.h"
+#include "Coordinate.h"
using namespace std;
using namespace openshot;
diff --git a/include/Coordinate.h b/src/Coordinate.h
similarity index 100%
rename from include/Coordinate.h
rename to src/Coordinate.h
diff --git a/src/CrashHandler.cpp b/src/CrashHandler.cpp
index 1782f5bab..7b6c4e7e6 100644
--- a/src/CrashHandler.cpp
+++ b/src/CrashHandler.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/CrashHandler.h"
+#include "CrashHandler.h"
using namespace std;
using namespace openshot;
diff --git a/include/CrashHandler.h b/src/CrashHandler.h
similarity index 100%
rename from include/CrashHandler.h
rename to src/CrashHandler.h
diff --git a/src/DecklinkInput.cpp b/src/DecklinkInput.cpp
index da5a8d00e..21c4f7bb6 100644
--- a/src/DecklinkInput.cpp
+++ b/src/DecklinkInput.cpp
@@ -53,7 +53,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/DecklinkInput.h"
+#include "DecklinkInput.h"
using namespace std;
@@ -139,7 +139,7 @@ HRESULT DeckLinkInputDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame*
{
// Handle Video Frame
if(videoFrame)
- {
+ {
if (videoFrame->GetFlags() & bmdFrameHasNoInputSource)
{
@@ -245,7 +245,8 @@ omp_set_nested(true);
m_rgbFrame->GetBytes(&frameBytes);
// *********** CREATE OPENSHOT FRAME **********
- std::shared_ptr f(new openshot::Frame(copy_frameCount, width, height, "#000000", 2048, 2));
+ auto f = std::make_shared(
+ copy_frameCount, width, height, "#000000", 2048, 2);
// Add Image data to openshot frame
// TODO: Fix Decklink support with QImage Upgrade
@@ -289,6 +290,3 @@ HRESULT DeckLinkInputDelegate::VideoInputFormatChanged(BMDVideoInputFormatChange
{
return S_OK;
}
-
-
-
diff --git a/include/DecklinkInput.h b/src/DecklinkInput.h
similarity index 100%
rename from include/DecklinkInput.h
rename to src/DecklinkInput.h
diff --git a/src/DecklinkOutput.cpp b/src/DecklinkOutput.cpp
index 2dee7e9e3..13da185f4 100644
--- a/src/DecklinkOutput.cpp
+++ b/src/DecklinkOutput.cpp
@@ -53,7 +53,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/DecklinkOutput.h"
+#include "DecklinkOutput.h"
using namespace std;
diff --git a/include/DecklinkOutput.h b/src/DecklinkOutput.h
similarity index 100%
rename from include/DecklinkOutput.h
rename to src/DecklinkOutput.h
diff --git a/src/DecklinkReader.cpp b/src/DecklinkReader.cpp
index 14c2f87ca..bb31f316d 100644
--- a/src/DecklinkReader.cpp
+++ b/src/DecklinkReader.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/DecklinkReader.h"
+#include "DecklinkReader.h"
using namespace openshot;
diff --git a/include/DecklinkReader.h b/src/DecklinkReader.h
similarity index 100%
rename from include/DecklinkReader.h
rename to src/DecklinkReader.h
diff --git a/src/DecklinkWriter.cpp b/src/DecklinkWriter.cpp
index 4ebbd1f02..1bfb59a8d 100644
--- a/src/DecklinkWriter.cpp
+++ b/src/DecklinkWriter.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/DecklinkWriter.h"
+#include "DecklinkWriter.h"
using namespace openshot;
@@ -142,7 +142,7 @@ void DecklinkWriter::Open()
// throw DecklinkError("Failed to enable audio output. Is another application using the card?");
// Begin video preroll by scheduling a second of frames in hardware
- //std::shared_ptr f(new Frame(1, displayMode->GetWidth(), displayMode->GetHeight(), "Blue"));
+ //auto f = std::make_shared(1, displayMode->GetWidth(), displayMode->GetHeight(), "Blue");
//f->AddColor(displayMode->GetWidth(), displayMode->GetHeight(), "Blue");
// Preroll 1 second of video
diff --git a/include/DecklinkWriter.h b/src/DecklinkWriter.h
similarity index 100%
rename from include/DecklinkWriter.h
rename to src/DecklinkWriter.h
diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp
index 8b6f752f7..c295c2985 100644
--- a/src/DummyReader.cpp
+++ b/src/DummyReader.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/DummyReader.h"
+#include "DummyReader.h"
using namespace openshot;
diff --git a/include/DummyReader.h b/src/DummyReader.h
similarity index 98%
rename from include/DummyReader.h
rename to src/DummyReader.h
index 9a75751d0..af06656d8 100644
--- a/include/DummyReader.h
+++ b/src/DummyReader.h
@@ -69,7 +69,7 @@ namespace openshot
* // Create blank frame (with specific frame #, samples, and channels)
* // Sample count should be 44100 / 30 fps = 1470 samples per frame
* int sample_count = 1470;
- * std::shared_ptr f(new openshot::Frame(frame_number, sample_count, 2));
+ * auto f = std::make_shared(frame_number, sample_count, 2);
*
* // Create test samples with incrementing value
* float *audio_buffer = new float[sample_count];
diff --git a/src/EffectBase.cpp b/src/EffectBase.cpp
index 05ed97c2a..458381ced 100644
--- a/src/EffectBase.cpp
+++ b/src/EffectBase.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/EffectBase.h"
+#include "EffectBase.h"
using namespace openshot;
@@ -41,6 +41,7 @@ void EffectBase::InitEffectInfo()
Start(0.0);
End(0.0);
Order(0);
+ ParentClip(NULL);
info.has_video = false;
info.has_audio = false;
@@ -138,3 +139,13 @@ Json::Value EffectBase::JsonInfo() const {
// return JsonValue
return root;
}
+
+/// Parent clip object of this reader (which can be unparented and NULL)
+openshot::ClipBase* EffectBase::ParentClip() {
+ return clip;
+}
+
+/// Set parent clip object of this reader
+void EffectBase::ParentClip(openshot::ClipBase* new_clip) {
+ clip = new_clip;
+}
\ No newline at end of file
diff --git a/include/EffectBase.h b/src/EffectBase.h
similarity index 85%
rename from include/EffectBase.h
rename to src/EffectBase.h
index 1f967a021..353e18177 100644
--- a/include/EffectBase.h
+++ b/src/EffectBase.h
@@ -67,6 +67,10 @@ namespace openshot
{
private:
int order; ///< The order to evaluate this effect. Effects are processed in this order (when more than one overlap).
+
+ protected:
+ openshot::ClipBase* clip; ///< Pointer to the parent clip instance (if any)
+
public:
/// Information about the current effect
@@ -78,21 +82,16 @@ namespace openshot
/// Constrain a color value from 0 to 255
int constrain(int color_value);
- /// @brief This method is required for all derived classes of EffectBase, and returns a
- /// modified openshot::Frame object
- ///
- /// The frame object is passed into this method, and a frame_number is passed in which
- /// tells the effect which settings to use from its keyframes (starting at 1).
- ///
- /// @returns The modified openshot::Frame object
- /// @param frame The frame object that needs the effect applied to it
- /// @param frame_number The frame number (starting at 1) of the effect on the timeline.
- virtual std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) = 0;
-
/// Initialize the values of the EffectInfo struct. It is important for derived classes to call
/// this method, or the EffectInfo struct values will not be initialized.
void InitEffectInfo();
+ /// Parent clip object of this effect (which can be unparented and NULL)
+ openshot::ClipBase* ParentClip();
+
+ /// Set parent clip object of this effect
+ void ParentClip(openshot::ClipBase* new_clip);
+
/// Get and Set JSON methods
virtual std::string Json() const = 0; ///< Generate JSON string of this object
virtual void SetJson(const std::string value) = 0; ///< Load JSON string into this object
diff --git a/src/EffectInfo.cpp b/src/EffectInfo.cpp
index e9ebc9516..2bbb3acab 100644
--- a/src/EffectInfo.cpp
+++ b/src/EffectInfo.cpp
@@ -28,8 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/EffectInfo.h"
-
+#include "EffectInfo.h"
using namespace openshot;
diff --git a/include/EffectInfo.h b/src/EffectInfo.h
similarity index 100%
rename from include/EffectInfo.h
rename to src/EffectInfo.h
diff --git a/include/Effects.h b/src/Effects.h
similarity index 100%
rename from include/Effects.h
rename to src/Effects.h
diff --git a/include/Enums.h b/src/Enums.h
similarity index 100%
rename from include/Enums.h
rename to src/Enums.h
diff --git a/include/Exceptions.h b/src/Exceptions.h
similarity index 100%
rename from include/Exceptions.h
rename to src/Exceptions.h
diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp
index 78a39c212..a647c5f86 100644
--- a/src/FFmpegReader.cpp
+++ b/src/FFmpegReader.cpp
@@ -31,7 +31,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/FFmpegReader.h"
+#include "FFmpegReader.h"
#include // for std::this_thread::sleep_for
#include // for std::chrono::milliseconds
@@ -86,7 +86,7 @@ int hw_de_on = 0;
AVHWDeviceType hw_de_av_device_type_global = AV_HWDEVICE_TYPE_NONE;
#endif
-FFmpegReader::FFmpegReader(std::string path)
+FFmpegReader::FFmpegReader(const std::string& path, bool inspect_reader)
: last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), seek_count(0),
audio_pts_offset(99999), video_pts_offset(99999), path(path), is_video_seek(true), check_interlace(false),
check_fps(false), enable_seek(true), is_open(false), seek_audio_frame_found(0), seek_video_frame_found(0),
@@ -94,27 +94,11 @@ FFmpegReader::FFmpegReader(std::string path)
current_video_frame(0), has_missing_frames(false), num_packets_since_video_frame(0), num_checks_since_final(0),
packet(NULL) {
- // Initialize FFMpeg, and register all formats and codecs
- AV_REGISTER_ALL
- AVCODEC_REGISTER_ALL
-
- // Init cache
- working_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * info.fps.ToDouble() * 2, info.width, info.height, info.sample_rate, info.channels);
- missing_frames.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels);
- final_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels);
-
- // Open and Close the reader, to populate its attributes (such as height, width, etc...)
- Open();
- Close();
-}
-
-FFmpegReader::FFmpegReader(std::string path, bool inspect_reader)
- : last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), seek_count(0),
- audio_pts_offset(99999), video_pts_offset(99999), path(path), is_video_seek(true), check_interlace(false),
- check_fps(false), enable_seek(true), is_open(false), seek_audio_frame_found(0), seek_video_frame_found(0),
- prev_samples(0), prev_pts(0), pts_total(0), pts_counter(0), is_duration_known(false), largest_frame_processed(0),
- current_video_frame(0), has_missing_frames(false), num_packets_since_video_frame(0), num_checks_since_final(0),
- packet(NULL) {
+ // Configure OpenMP parallelism
+ // Default number of threads per section
+ omp_set_num_threads(OPEN_MP_NUM_PROCESSORS);
+ // Allow nested parallel sections as deeply as supported
+ omp_set_max_active_levels(OPEN_MP_MAX_ACTIVE);
// Initialize FFMpeg, and register all formats and codecs
AV_REGISTER_ALL
@@ -904,11 +888,6 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) {
int minimum_packets = OPEN_MP_NUM_PROCESSORS;
int max_packets = 4096;
- // Set the number of threads in OpenMP
- omp_set_num_threads(OPEN_MP_NUM_PROCESSORS);
- // Allow nested OpenMP sections
- omp_set_nested(true);
-
// Debug output
ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream", "requested_frame", requested_frame, "OPEN_MP_NUM_PROCESSORS", OPEN_MP_NUM_PROCESSORS);
@@ -1292,15 +1271,16 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) {
// without losing quality. NOTE: We cannot go smaller than the timeline itself, or the add_layer timeline
// method will scale it back to timeline size before scaling it smaller again. This needs to be fixed in
// the future.
- int max_width = openshot::Settings::Instance()->MAX_WIDTH;
- if (max_width <= 0)
- max_width = info.width;
- int max_height = openshot::Settings::Instance()->MAX_HEIGHT;
- if (max_height <= 0)
- max_height = info.height;
-
- Clip *parent = (Clip *) GetParentClip();
+ int max_width = info.width;
+ int max_height = info.height;
+
+ Clip *parent = (Clip *) ParentClip();
if (parent) {
+ if (parent->ParentTimeline()) {
+ // Set max width/height based on parent clip's timeline (if attached to a timeline)
+ max_width = parent->ParentTimeline()->preview_width;
+ max_height = parent->ParentTimeline()->preview_height;
+ }
if (parent->scale == SCALE_FIT || parent->scale == SCALE_STRETCH) {
// Best fit or Stretch scaling (based on max timeline size * scaling keyframes)
float max_scale_x = parent->scale_x.GetMaxPoint().co.Y;
@@ -1375,7 +1355,7 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) {
std::shared_ptr f = CreateFrame(current_frame);
// Add Image data to frame
- f->AddImage(width, height, 4, QImage::Format_RGBA8888, buffer);
+ f->AddImage(width, height, 4, QImage::Format_RGBA8888_Premultiplied, buffer);
// Update working cache
working_cache.Add(f);
@@ -2162,7 +2142,7 @@ bool FFmpegReader::CheckMissingFrame(int64_t requested_frame) {
// Add this frame to the processed map (since it's already done)
std::shared_ptr parent_image = parent_frame->GetImage();
if (parent_image) {
- missing_frame->AddImage(std::shared_ptr(new QImage(*parent_image)));
+ missing_frame->AddImage(std::make_shared(*parent_image));
processed_video_frames[missing_frame->number] = missing_frame->number;
}
}
@@ -2252,7 +2232,7 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram
if (info.has_video && !is_video_ready && last_video_frame) {
// Copy image from last frame
- f->AddImage(std::shared_ptr(new QImage(*last_video_frame->GetImage())));
+ f->AddImage(std::make_shared(*last_video_frame->GetImage()));
is_video_ready = true;
}
@@ -2274,7 +2254,7 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram
// Add missing image (if needed - sometimes end_of_stream causes frames with only audio)
if (info.has_video && !is_video_ready && last_video_frame)
// Copy image from last frame
- f->AddImage(std::shared_ptr(new QImage(*last_video_frame->GetImage())));
+ f->AddImage(std::make_shared(*last_video_frame->GetImage()));
// Reset counter since last 'final' frame
num_checks_since_final = 0;
diff --git a/include/FFmpegReader.h b/src/FFmpegReader.h
similarity index 94%
rename from include/FFmpegReader.h
rename to src/FFmpegReader.h
index 633593269..9cd454349 100644
--- a/include/FFmpegReader.h
+++ b/src/FFmpegReader.h
@@ -233,14 +233,13 @@ namespace openshot {
/// codecs have trouble seeking, and can introduce artifacts or blank images into the video.
bool enable_seek;
- /// Constructor for FFmpegReader. This automatically opens the media file and loads
- /// frame 1, or it throws one of the following exceptions.
- FFmpegReader(std::string path);
-
- /// Constructor for FFmpegReader. This only opens the media file to inspect its properties
- /// if inspect_reader=true. When not inspecting the media file, it's much faster, and useful
- /// when you are inflating the object using JSON after instantiating it.
- FFmpegReader(std::string path, bool inspect_reader);
+ /// @brief Constructor for FFmpegReader.
+ ///
+ /// Sets (and possibly opens) the media file path,
+ /// or throws an exception.
+ /// @param path The filesystem location to load
+ /// @param inspect_reader if true (the default), automatically open the media file and loads frame 1.
+ FFmpegReader(const std::string& path, bool inspect_reader=true);
/// Destructor
virtual ~FFmpegReader();
diff --git a/include/FFmpegUtilities.h b/src/FFmpegUtilities.h
similarity index 100%
rename from include/FFmpegUtilities.h
rename to src/FFmpegUtilities.h
diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp
index b2aec5f1e..e5e92fd4f 100644
--- a/src/FFmpegWriter.cpp
+++ b/src/FFmpegWriter.cpp
@@ -31,7 +31,9 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/FFmpegWriter.h"
+#include "FFmpegWriter.h"
+
+#include
using namespace openshot;
@@ -59,7 +61,7 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6
int err = 0;
if (!(hw_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx))) {
- fprintf(stderr, "Failed to create HW frame context.\n");
+ std::clog << "Failed to create HW frame context.\n";
return -1;
}
frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data);
@@ -69,8 +71,8 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6
frames_ctx->height = height;
frames_ctx->initial_pool_size = 20;
if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0) {
- fprintf(stderr, "Failed to initialize HW frame context."
- "Error code: %s\n",av_err2str(err));
+ std::clog << "Failed to initialize HW frame context. " <<
+ "Error code: " << av_err2str(err) << "\n";
av_buffer_unref(&hw_frames_ref);
return err;
}
@@ -83,7 +85,7 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6
}
#endif // HAVE_HW_ACCEL
-FFmpegWriter::FFmpegWriter(std::string path) :
+FFmpegWriter::FFmpegWriter(const std::string& path) :
path(path), fmt(NULL), oc(NULL), audio_st(NULL), video_st(NULL), samples(NULL),
audio_outbuf(NULL), audio_outbuf_size(0), audio_input_frame_size(0), audio_input_position(0),
initial_audio_input_frame_size(0), img_convert_ctx(NULL), cache_size(8), num_of_rescalers(32),
@@ -95,6 +97,12 @@ FFmpegWriter::FFmpegWriter(std::string path) :
info.has_audio = false;
info.has_video = false;
+ // Configure OpenMP parallelism
+ // Default number of threads per block
+ omp_set_num_threads(OPEN_MP_NUM_PROCESSORS);
+ // Allow nested parallel sections as deeply as supported
+ omp_set_max_active_levels(OPEN_MP_MAX_ACTIVE);
+
// Initialize FFMpeg, and register all formats and codecs
AV_REGISTER_ALL
@@ -220,10 +228,10 @@ 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 // unknown OS
new_codec = avcodec_find_encoder_by_name(codec.c_str());
- #endif //__linux__
-#else // not ffmpeg 3
+#endif //__linux__/_WIN32/__APPLE__
+#else // HAVE_HW_ACCEL
new_codec = avcodec_find_encoder_by_name(codec.c_str());
#endif // HAVE_HW_ACCEL
if (new_codec == NULL)
@@ -253,9 +261,9 @@ void FFmpegWriter::SetVideoOptions(bool has_video, std::string codec, Fraction f
info.pixel_ratio.num = pixel_ratio.num;
info.pixel_ratio.den = pixel_ratio.den;
}
- if (bit_rate >= 1000) // bit_rate is the bitrate in b/s
+ if (bit_rate >= 1000) // bit_rate is the bitrate in b/s
info.video_bit_rate = bit_rate;
- if ((bit_rate >= 0) && (bit_rate < 256)) // bit_rate is the bitrate in crf
+ if ((bit_rate >= 0) && (bit_rate < 256)) // bit_rate is the bitrate in crf
info.video_bit_rate = bit_rate;
info.interlaced_frame = interlaced;
@@ -280,8 +288,10 @@ void FFmpegWriter::SetVideoOptions(bool has_video, std::string codec, Fraction f
// Set video export options (overloaded function)
void FFmpegWriter::SetVideoOptions(std::string codec, int width, int height, Fraction fps, int bit_rate) {
// Call full signature with some default parameters
- FFmpegWriter::SetVideoOptions(true, codec, fps, width, height,
- openshot::Fraction(1, 1), false, true, bit_rate);
+ FFmpegWriter::SetVideoOptions(
+ true, codec, fps, width, height,
+ openshot::Fraction(1, 1), false, true, bit_rate
+ );
}
@@ -314,7 +324,11 @@ void FFmpegWriter::SetAudioOptions(bool has_audio, std::string codec, int sample
if (original_channels == 0)
original_channels = info.channels;
- ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::SetAudioOptions (" + codec + ")", "sample_rate", sample_rate, "channels", channels, "bit_rate", bit_rate);
+ ZmqLogger::Instance()->AppendDebugMethod(
+ "FFmpegWriter::SetAudioOptions (" + codec + ")",
+ "sample_rate", sample_rate,
+ "channels", channels,
+ "bit_rate", bit_rate);
// Enable / Disable audio
info.has_audio = has_audio;
@@ -324,8 +338,10 @@ void FFmpegWriter::SetAudioOptions(bool has_audio, std::string codec, int sample
// Set audio export options (overloaded function)
void FFmpegWriter::SetAudioOptions(std::string codec, int sample_rate, int bit_rate) {
// Call full signature with some default parameters
- FFmpegWriter::SetAudioOptions(true, codec, sample_rate, 2,
- openshot::LAYOUT_STEREO, bit_rate);
+ FFmpegWriter::SetAudioOptions(
+ true, codec, sample_rate, 2,
+ openshot::LAYOUT_STEREO, bit_rate
+ );
}
@@ -340,6 +356,14 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
st = video_st;
// Get codec context
c = AV_GET_CODEC_PAR_CONTEXT(st, video_codec_ctx);
+ // Was a codec / stream found?
+ if (c) {
+ if (info.interlaced_frame) {
+ c->field_order = info.top_field_first ? AV_FIELD_TT : AV_FIELD_BB;
+ // We only use these two version and ignore AV_FIELD_TB and AV_FIELD_BT
+ // Otherwise we would need to change the whole export window
+ }
+ }
} else if (info.has_audio && stream == AUDIO_STREAM && audio_st) {
st = audio_st;
// Get codec context
@@ -408,58 +432,56 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
// 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 HAVE_HW_ACCEL
- if (hw_en_on) {
- av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); // 0-63
- } else
- #endif // HAVE_HW_ACCEL
- {
+#if HAVE_HW_ACCEL
+ if (hw_en_on) {
+ av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); // 0-63
+ } else
+#endif // HAVE_HW_ACCEL
+ {
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", std::min(std::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", std::max(std::min(std::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", std::min(std::stoi(value), 63), 0); // 0-63
- if (std::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", std::min(std::stoi(value), 51), 0); // 0-51
- if (std::stoi(value) == 0) {
- av_opt_set(c->priv_data, "preset", "veryslow", 0);
+#if (LIBAVCODEC_VERSION_MAJOR >= 58)
+ // FFmpeg 4.0+
+ case AV_CODEC_ID_AV1 :
+ c->bit_rate = 0;
+ av_opt_set_int(c->priv_data, "qp", std::min(std::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", std::max(std::min(std::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", std::min(std::stoi(value), 63), 0); // 0-63
+ if (std::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", std::min(std::stoi(value), 51), 0); // 0-51
+ if (std::stoi(value) == 0) {
+ av_opt_set(c->priv_data, "preset", "veryslow", 0);
c->pix_fmt = PIX_FMT_YUV444P; // no chroma subsampling
- }
- break;
- case AV_CODEC_ID_HEVC :
- av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value), 51), 0); // 0-51
- if (std::stoi(value) == 0) {
- av_opt_set(c->priv_data, "preset", "veryslow", 0);
- 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", std::min(std::stoi(value), 63), 0); // 0-63
- c->bit_rate = 0;
+ }
+ break;
+ case AV_CODEC_ID_HEVC :
+ av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value), 51), 0); // 0-51
+ if (std::stoi(value) == 0) {
+ av_opt_set(c->priv_data, "preset", "veryslow", 0);
+ 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", std::min(std::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
-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101)
#if HAVE_HW_ACCEL
if (hw_en_on) {
double mbs = 15000000.0;
@@ -477,6 +499,7 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
{
switch (c->codec_id) {
#if (LIBAVCODEC_VERSION_MAJOR >= 58)
+ // FFmpeg 4.0+
case AV_CODEC_ID_AV1 :
c->bit_rate = 0;
// AV1 only supports "crf" quality values
@@ -530,12 +553,12 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
c->bit_rate = (int) (mbs);
}
}
-#endif
} else if (name == "qp") {
// encode quality and special settings like lossless
// This might be better in an extra methods as more options
// and way to set quality are possible
#if (LIBAVCODEC_VERSION_MAJOR >= 58)
+ // FFmpeg 4.0+
switch (c->codec_id) {
case AV_CODEC_ID_AV1 :
c->bit_rate = 0;
@@ -565,7 +588,7 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
}
break;
}
-#endif
+#endif // FFmpeg 4.0+
} else {
// Set AVOption
AV_OPTION_SET(st, c->priv_data, name.c_str(), value.c_str(), c);
@@ -678,15 +701,8 @@ void FFmpegWriter::WriteFrame(std::shared_ptr frame) {
// Write the frames once it reaches the correct cache size
if ((int)spooled_video_frames.size() == cache_size || (int)spooled_audio_frames.size() == cache_size) {
- // Is writer currently writing?
- if (!is_writing)
- // Write frames to video file
- write_queued_frames();
-
- else {
- // Write frames to video file
- write_queued_frames();
- }
+ // Write frames to video file
+ write_queued_frames();
}
// Keep track of the last frame added
@@ -708,11 +724,6 @@ void FFmpegWriter::write_queued_frames() {
spooled_video_frames.clear();
spooled_audio_frames.clear();
- // Set the number of threads in OpenMP
- omp_set_num_threads(OPEN_MP_NUM_PROCESSORS);
- // Allow nested OpenMP sections
- omp_set_nested(true);
-
// Create blank exception
bool has_error_encoding_video = false;
@@ -844,6 +855,7 @@ void FFmpegWriter::flush_encoders() {
if (info.has_audio && audio_codec_ctx && AV_GET_CODEC_TYPE(audio_st) == AVMEDIA_TYPE_AUDIO && AV_GET_CODEC_ATTRIBUTES(audio_st, audio_codec_ctx)->frame_size <= 1)
return;
#if (LIBAVFORMAT_VERSION_MAJOR < 58)
+ // FFmpeg < 4.0
if (info.has_video && video_codec_ctx && AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && (oc->oformat->flags & AVFMT_RAWPICTURE) && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO)
return;
#else
@@ -863,9 +875,6 @@ void FFmpegWriter::flush_encoders() {
pkt.data = NULL;
pkt.size = 0;
- // Pointer for video buffer (if using old FFmpeg version)
- uint8_t *video_outbuf = NULL;
-
/* encode the image */
int got_packet = 0;
int error_code = 0;
@@ -896,28 +905,9 @@ void FFmpegWriter::flush_encoders() {
}
#else // IS_FFMPEG_3_2
-#if LIBAVFORMAT_VERSION_MAJOR >= 54
// Encode video packet (older than FFmpeg 3.2)
error_code = avcodec_encode_video2(video_codec_ctx, &pkt, NULL, &got_packet);
-#else
- // Encode video packet (even older version of FFmpeg)
- int video_outbuf_size = 0;
-
- /* encode the image */
- int out_size = avcodec_encode_video(video_codec_ctx, NULL, video_outbuf_size, NULL);
-
- /* if zero size, it means the image was buffered */
- if (out_size > 0) {
- if(video_codec_ctx->coded_frame->key_frame)
- pkt.flags |= AV_PKT_FLAG_KEY;
- pkt.data= video_outbuf;
- pkt.size= out_size;
-
- // got data back (so encode this frame)
- got_packet = 1;
- }
-#endif // LIBAVFORMAT_VERSION_MAJOR >= 54
#endif // IS_FFMPEG_3_2
if (error_code < 0) {
@@ -948,12 +938,8 @@ void FFmpegWriter::flush_encoders() {
for (;;) {
// Increment PTS (in samples and scaled to the codec's timebase)
-#if LIBAVFORMAT_VERSION_MAJOR >= 54
// for some reason, it requires me to multiply channels X 2
write_audio_count += av_rescale_q(audio_input_position / (audio_codec_ctx->channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)), av_make_q(1, info.sample_rate), audio_codec_ctx->time_base);
-#else
- write_audio_count += av_rescale_q(audio_input_position / audio_codec_ctx->channels, av_make_q(1, info.sample_rate), audio_codec_ctx->time_base);
-#endif
AVPacket pkt;
av_init_packet(&pkt);
@@ -1112,11 +1098,7 @@ AVStream *FFmpegWriter::add_audio_stream() {
AV_FORMAT_NEW_STREAM(oc, audio_codec_ctx, codec, st)
c->codec_id = codec->id;
-#if LIBAVFORMAT_VERSION_MAJOR >= 53
c->codec_type = AVMEDIA_TYPE_AUDIO;
-#else
- c->codec_type = CODEC_TYPE_AUDIO;
-#endif
// Set the sample parameters
c->bit_rate = info.audio_bit_rate;
@@ -1170,6 +1152,7 @@ AVStream *FFmpegWriter::add_audio_stream() {
// some formats want stream headers to be separate
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
#if (LIBAVCODEC_VERSION_MAJOR >= 57)
+ // FFmpeg 3.0+
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
#else
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
@@ -1195,11 +1178,7 @@ AVStream *FFmpegWriter::add_video_stream() {
AV_FORMAT_NEW_STREAM(oc, video_codec_ctx, codec, st)
c->codec_id = codec->id;
-#if LIBAVFORMAT_VERSION_MAJOR >= 53
c->codec_type = AVMEDIA_TYPE_VIDEO;
-#else
- c->codec_type = CODEC_TYPE_VIDEO;
-#endif
/* Init video encoder options */
if (info.video_bit_rate >= 1000
@@ -1219,8 +1198,8 @@ AVStream *FFmpegWriter::add_video_stream() {
} else {
// Check if codec supports crf or qp
switch (c->codec_id) {
-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101)
#if (LIBAVCODEC_VERSION_MAJOR >= 58)
+ // FFmpeg 4.0+
case AV_CODEC_ID_AV1 :
// TODO: Set `crf` or `qp` according to bitrate, as bitrate is not supported by these encoders yet.
if (info.video_bit_rate >= 1000) {
@@ -1260,7 +1239,6 @@ AVStream *FFmpegWriter::add_video_stream() {
#endif
case AV_CODEC_ID_VP9 :
case AV_CODEC_ID_HEVC :
-#endif
case AV_CODEC_ID_VP8 :
case AV_CODEC_ID_H264 :
if (info.video_bit_rate < 40) {
@@ -1297,7 +1275,7 @@ AVStream *FFmpegWriter::add_video_stream() {
identically 1. */
c->time_base.num = info.video_timebase.num;
c->time_base.den = info.video_timebase.den;
-// AVCodecContext->framerate was added in FFmpeg 2.2
+// AVCodecContext->framerate was added in FFmpeg 2.6
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 26, 0)
c->framerate = av_inv_q(c->time_base);
#endif
@@ -1325,6 +1303,7 @@ AVStream *FFmpegWriter::add_video_stream() {
// some formats want stream headers to be separate
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
#if (LIBAVCODEC_VERSION_MAJOR >= 57)
+ // FFmpeg 3.0+
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
#else
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
@@ -1346,6 +1325,7 @@ AVStream *FFmpegWriter::add_video_stream() {
c->pix_fmt = PIX_FMT_RGB24;
#if (LIBAVFORMAT_VERSION_MAJOR < 58)
+ // FFmpeg < 4.0
if (strcmp(fmt->name, "gif") != 0)
// If not GIF format, skip the encoding process
// Set raw picture flag (so we don't encode this video)
@@ -1359,6 +1339,7 @@ AVStream *FFmpegWriter::add_video_stream() {
AV_COPY_PARAMS_FROM_CONTEXT(st, c);
#if (LIBAVFORMAT_VERSION_MAJOR < 58)
+ // FFmpeg < 4.0
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::add_video_stream (" + (std::string)fmt->name + " : " + (std::string)av_get_pix_fmt_name(c->pix_fmt) + ")", "c->codec_id", c->codec_id, "c->bit_rate", c->bit_rate, "c->pix_fmt", c->pix_fmt, "oc->oformat->flags", oc->oformat->flags, "AVFMT_RAWPICTURE", AVFMT_RAWPICTURE);
#else
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::add_video_stream (" + (std::string)fmt->name + " : " + (std::string)av_get_pix_fmt_name(c->pix_fmt) + ")", "c->codec_id", c->codec_id, "c->bit_rate", c->bit_rate, "c->pix_fmt", c->pix_fmt, "oc->oformat->flags", oc->oformat->flags);
@@ -1454,15 +1435,13 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) {
int adapter_num;
// Use the hw device given in the environment variable HW_EN_DEVICE_SET or the default if not set
adapter_num = openshot::Settings::Instance()->HW_EN_DEVICE_SET;
- fprintf(stderr, "\n\nEncodiing Device Nr: %d\n", adapter_num);
+ std::clog << "Encoding Device Nr: " << adapter_num << "\n";
if (adapter_num < 3 && adapter_num >=0) {
#if defined(__linux__)
snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128);
// Maybe 127 is better because the first card would be 1?!
adapter_ptr = adapter;
-#elif defined(_WIN32)
- adapter_ptr = NULL;
-#elif defined(__APPLE__)
+#elif defined(_WIN32) || defined(__APPLE__)
adapter_ptr = NULL;
#endif
}
@@ -1472,20 +1451,18 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) {
// Check if it is there and writable
#if defined(__linux__)
if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == 0 ) {
-#elif defined(_WIN32)
- if( adapter_ptr != NULL ) {
-#elif defined(__APPLE__)
+#elif defined(_WIN32) || defined(__APPLE__)
if( adapter_ptr != NULL ) {
#endif
ZmqLogger::Instance()->AppendDebugMethod("Encode Device present using device", "adapter", adapter_num);
}
else {
adapter_ptr = NULL; // use default
- ZmqLogger::Instance()->AppendDebugMethod("Encode Device not present using default");
+ ZmqLogger::Instance()->AppendDebugMethod("Encode Device not present, using default");
}
if (av_hwdevice_ctx_create(&hw_device_ctx, hw_en_av_device_type,
adapter_ptr, NULL, 0) < 0) {
- ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_video : Codec name: ", info.vcodec.c_str(), -1, " ERROR creating\n", -1);
+ ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_video ERROR creating hwdevice, Codec name:", info.vcodec.c_str(), -1);
throw InvalidCodec("Could not create hwdevice", path);
}
}
@@ -1715,20 +1692,25 @@ void FFmpegWriter::write_audio_packets(bool is_final) {
int nb_samples = 0;
// Convert audio samples
- nb_samples = SWR_CONVERT(avr, // audio resample context
- audio_converted->data, // output data pointers
- audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown)
- audio_converted->nb_samples, // maximum number of samples that the output buffer can hold
- audio_frame->data, // input data pointers
- audio_frame->linesize[0], // input plane size, in bytes (0 if unknown)
- audio_frame->nb_samples); // number of input samples to convert
+ nb_samples = SWR_CONVERT(
+ avr, // audio resample context
+ audio_converted->data, // output data pointers
+ audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown)
+ audio_converted->nb_samples, // maximum number of samples that the output buffer can hold
+ audio_frame->data, // input data pointers
+ audio_frame->linesize[0], // input plane size, in bytes (0 if unknown)
+ audio_frame->nb_samples // number of input samples to convert
+ );
// Set remaining samples
remaining_frame_samples = nb_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
// Create a new array (to hold all resampled S16 audio samples)
all_resampled_samples = (int16_t *) av_malloc(
- sizeof(int16_t) * nb_samples * info.channels * (av_get_bytes_per_sample(output_sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)));
+ sizeof(int16_t) * nb_samples * info.channels
+ * (av_get_bytes_per_sample(output_sample_fmt) /
+ av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) )
+ );
// Copy audio samples over original samples
memcpy(all_resampled_samples, audio_converted->data[0], nb_samples * info.channels * av_get_bytes_per_sample(output_sample_fmt));
@@ -1759,8 +1741,14 @@ void FFmpegWriter::write_audio_packets(bool is_final) {
// Copy frame samples into the packet samples array
if (!is_final)
//TODO: Make this more sane
- memcpy(samples + (audio_input_position * (av_get_bytes_per_sample(output_sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16))),
- all_resampled_samples + samples_position, diff * av_get_bytes_per_sample(output_sample_fmt));
+ memcpy(
+ samples + (audio_input_position
+ * (av_get_bytes_per_sample(output_sample_fmt) /
+ av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) )
+ ),
+ all_resampled_samples + samples_position,
+ diff * av_get_bytes_per_sample(output_sample_fmt)
+ );
// Increment counters
audio_input_position += diff;
@@ -1775,8 +1763,16 @@ void FFmpegWriter::write_audio_packets(bool is_final) {
// Convert to planar (if needed by audio codec)
AVFrame *frame_final = AV_ALLOCATE_FRAME();
AV_RESET_FRAME(frame_final);
- if (av_sample_fmt_is_planar(audio_codec_ctx->sample_fmt)) {
- ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets (2nd resampling for Planar formats)", "in_sample_fmt", output_sample_fmt, "out_sample_fmt", audio_codec_ctx->sample_fmt, "in_sample_rate", info.sample_rate, "out_sample_rate", info.sample_rate, "in_channels", info.channels, "out_channels", info.channels);
+ if (av_sample_fmt_is_planar(audio_codec_ctx->sample_fmt)) {
+ ZmqLogger::Instance()->AppendDebugMethod(
+ "FFmpegWriter::write_audio_packets (2nd resampling for Planar formats)",
+ "in_sample_fmt", output_sample_fmt,
+ "out_sample_fmt", audio_codec_ctx->sample_fmt,
+ "in_sample_rate", info.sample_rate,
+ "out_sample_rate", info.sample_rate,
+ "in_channels", info.channels,
+ "out_channels", info.channels
+ );
// setup resample context
if (!avr_planar) {
@@ -1799,31 +1795,39 @@ void FFmpegWriter::write_audio_packets(bool is_final) {
// Create a new array
final_samples_planar = (int16_t *) av_malloc(
- sizeof(int16_t) * audio_frame->nb_samples * info.channels * (av_get_bytes_per_sample(output_sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)));
+ sizeof(int16_t) * audio_frame->nb_samples * info.channels
+ * (av_get_bytes_per_sample(output_sample_fmt) /
+ av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) )
+ );
// Copy audio into buffer for frame
memcpy(final_samples_planar, samples, audio_frame->nb_samples * info.channels * av_get_bytes_per_sample(output_sample_fmt));
// Fill input frame with sample data
- avcodec_fill_audio_frame(audio_frame, info.channels, output_sample_fmt, (uint8_t *) final_samples_planar,
- audio_encoder_buffer_size, 0);
+ avcodec_fill_audio_frame(audio_frame, info.channels, output_sample_fmt,
+ (uint8_t *) final_samples_planar, audio_encoder_buffer_size, 0);
// Create output frame (and allocate arrays)
frame_final->nb_samples = audio_input_frame_size;
- av_samples_alloc(frame_final->data, frame_final->linesize, info.channels, frame_final->nb_samples, audio_codec_ctx->sample_fmt, 0);
+ av_samples_alloc(frame_final->data, frame_final->linesize, info.channels,
+ frame_final->nb_samples, audio_codec_ctx->sample_fmt, 0);
// Convert audio samples
- int nb_samples = SWR_CONVERT(avr_planar, // audio resample context
- frame_final->data, // output data pointers
- frame_final->linesize[0], // output plane size, in bytes. (0 if unknown)
- frame_final->nb_samples, // maximum number of samples that the output buffer can hold
- audio_frame->data, // input data pointers
- audio_frame->linesize[0], // input plane size, in bytes (0 if unknown)
- audio_frame->nb_samples); // number of input samples to convert
+ int nb_samples = SWR_CONVERT(
+ avr_planar, // audio resample context
+ frame_final->data, // output data pointers
+ frame_final->linesize[0], // output plane size, in bytes. (0 if unknown)
+ frame_final->nb_samples, // maximum number of samples that the output buffer can hold
+ audio_frame->data, // input data pointers
+ audio_frame->linesize[0], // input plane size, in bytes (0 if unknown)
+ audio_frame->nb_samples // number of input samples to convert
+ );
// Copy audio samples over original samples
- if (nb_samples > 0)
- memcpy(samples, frame_final->data[0], nb_samples * av_get_bytes_per_sample(audio_codec_ctx->sample_fmt) * info.channels);
+ if (nb_samples > 0) {
+ memcpy(samples, frame_final->data[0],
+ nb_samples * av_get_bytes_per_sample(audio_codec_ctx->sample_fmt) * info.channels);
+ }
// deallocate AVFrame
av_freep(&(audio_frame->data[0]));
@@ -1835,17 +1839,22 @@ void FFmpegWriter::write_audio_packets(bool is_final) {
} else {
// Create a new array
final_samples = (int16_t *) av_malloc(
- sizeof(int16_t) * audio_input_position * (av_get_bytes_per_sample(audio_codec_ctx->sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)));
+ sizeof(int16_t) * audio_input_position
+ * (av_get_bytes_per_sample(audio_codec_ctx->sample_fmt) /
+ av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) )
+ );
// Copy audio into buffer for frame
- memcpy(final_samples, samples, audio_input_position * av_get_bytes_per_sample(audio_codec_ctx->sample_fmt));
+ memcpy(final_samples, samples,
+ audio_input_position * av_get_bytes_per_sample(audio_codec_ctx->sample_fmt));
// Init the nb_samples property
frame_final->nb_samples = audio_input_frame_size;
// Fill the final_frame AVFrame with audio (non planar)
- avcodec_fill_audio_frame(frame_final, audio_codec_ctx->channels, audio_codec_ctx->sample_fmt, (uint8_t *) final_samples,
- audio_encoder_buffer_size, 0);
+ avcodec_fill_audio_frame(frame_final, audio_codec_ctx->channels,
+ audio_codec_ctx->sample_fmt, (uint8_t *) final_samples,
+ audio_encoder_buffer_size, 0);
}
// Increment PTS (in samples)
@@ -1916,10 +1925,7 @@ void FFmpegWriter::write_audio_packets(bool is_final) {
pkt.flags |= AV_PKT_FLAG_KEY;
/* write the compressed frame in the media file */
- int error_code = av_interleaved_write_frame(oc, &pkt);
- if (error_code < 0) {
- ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets ERROR [" + (std::string) av_err2str(error_code) + "]", "error_code", error_code);
- }
+ error_code = av_interleaved_write_frame(oc, &pkt);
}
if (error_code < 0) {
@@ -2020,7 +2026,10 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) {
} else
#endif // HAVE_HW_ACCEL
{
- frame_final = allocate_avframe((AVPixelFormat)(video_st->codecpar->format), info.width, info.height, &bytes_final, NULL);
+ frame_final = allocate_avframe(
+ (AVPixelFormat)(video_st->codecpar->format),
+ info.width, info.height, &bytes_final, NULL
+ );
}
#else
AVFrame *frame_final = allocate_avframe(video_codec_ctx->pix_fmt, info.width, info.height, &bytes_final, NULL);
@@ -2032,7 +2041,7 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) {
// Resize & convert pixel format
sws_scale(scaler, frame_source->data, frame_source->linesize, 0,
- source_image_height, frame_final->data, frame_final->linesize);
+ source_image_height, frame_final->data, frame_final->linesize);
// Add resized AVFrame to av_frames map
#pragma omp critical (av_frames_section)
@@ -2048,11 +2057,15 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) {
// write video frame
bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *frame_final) {
#if (LIBAVFORMAT_VERSION_MAJOR >= 58)
- ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags", oc->oformat->flags);
+ // FFmpeg 4.0+
+ ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet",
+ "frame->number", frame->number, "oc->oformat->flags", oc->oformat->flags);
if (AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO) {
#else
- ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags & AVFMT_RAWPICTURE", oc->oformat->flags & AVFMT_RAWPICTURE);
+ ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet",
+ "frame->number", frame->number,
+ "oc->oformat->flags & AVFMT_RAWPICTURE", oc->oformat->flags & AVFMT_RAWPICTURE);
if (oc->oformat->flags & AVFMT_RAWPICTURE) {
#endif
@@ -2088,9 +2101,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
pkt.size = 0;
pkt.pts = pkt.dts = AV_NOPTS_VALUE;
- // Pointer for video buffer (if using old FFmpeg version)
- uint8_t *video_outbuf = NULL;
-
// Increment PTS (in frames and scaled to the codec's timebase)
write_video_count += av_rescale_q(1, av_make_q(info.fps.den, info.fps.num), video_codec_ctx->time_base);
@@ -2099,17 +2109,17 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
#if HAVE_HW_ACCEL
if (hw_en_on && hw_en_supported) {
if (!(hw_frame = av_frame_alloc())) {
- fprintf(stderr, "Error code: av_hwframe_alloc\n");
+ std::clog << "Error code: av_hwframe_alloc\n";
}
if (av_hwframe_get_buffer(video_codec_ctx->hw_frames_ctx, hw_frame, 0) < 0) {
- fprintf(stderr, "Error code: av_hwframe_get_buffer\n");
+ std::clog << "Error code: av_hwframe_get_buffer\n";
}
if (!hw_frame->hw_frames_ctx) {
- fprintf(stderr, "Error hw_frames_ctx.\n");
+ std::clog << "Error hw_frames_ctx.\n";
}
hw_frame->format = AV_PIX_FMT_NV12;
if ( av_hwframe_transfer_data(hw_frame, frame_final, 0) < 0) {
- fprintf(stderr, "Error while transferring frame data to surface.\n");
+ std::clog << "Error while transferring frame data to surface.\n";
}
av_frame_copy_props(hw_frame, frame_final);
}
@@ -2133,10 +2143,10 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
if (ret < 0 ) {
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet (Frame not sent)");
if (ret == AVERROR(EAGAIN) ) {
- std::cerr << "Frame EAGAIN" << "\n";
+ std::clog << "Frame EAGAIN\n";
}
if (ret == AVERROR_EOF ) {
- std::cerr << "Frame AVERROR_EOF" << "\n";
+ std::clog << "Frame AVERROR_EOF\n";
}
avcodec_send_frame(video_codec_ctx, NULL);
}
@@ -2156,34 +2166,14 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
}
}
#else
-#if LIBAVFORMAT_VERSION_MAJOR >= 54
// Write video packet (older than FFmpeg 3.2)
error_code = avcodec_encode_video2(video_codec_ctx, &pkt, frame_final, &got_packet_ptr);
if (error_code != 0) {
- std::cerr << "Frame AVERROR_EOF" << "\n";
+ ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet ERROR [" + (std::string) av_err2str(error_code) + "]", "error_code", error_code);
}
if (got_packet_ptr == 0) {
- std::cerr << "Frame gotpacket error" << "\n";
+ ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet (Frame gotpacket error)");
}
-#else
- // Write video packet (even older versions of FFmpeg)
- int video_outbuf_size = 200000;
- video_outbuf = (uint8_t*) av_malloc(200000);
-
- /* encode the image */
- int out_size = avcodec_encode_video(video_codec_ctx, video_outbuf, video_outbuf_size, frame_final);
-
- /* if zero size, it means the image was buffered */
- if (out_size > 0) {
- if(video_codec_ctx->coded_frame->key_frame)
- pkt.flags |= AV_PKT_FLAG_KEY;
- pkt.data= video_outbuf;
- pkt.size= out_size;
-
- // got data back (so encode this frame)
- got_packet_ptr = 1;
- }
-#endif // LIBAVFORMAT_VERSION_MAJOR >= 54
#endif // IS_FFMPEG_3_2
/* if zero size, it means the image was buffered */
@@ -2203,17 +2193,13 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
pkt.stream_index = video_st->index;
/* write the compressed frame in the media file */
- int error_code = av_interleaved_write_frame(oc, &pkt);
- if (error_code < 0) {
- ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet ERROR [" + (std::string) av_err2str(error_code) + "]", "error_code", error_code);
+ int result = av_interleaved_write_frame(oc, &pkt);
+ if (result < 0) {
+ ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet ERROR [" + (std::string) av_err2str(result) + "]", "result", result);
return false;
}
}
- // Deallocate memory (if needed)
- if (video_outbuf)
- delete[] video_outbuf;
-
// Deallocate packet
AV_FREE_PACKET(&pkt);
#if HAVE_HW_ACCEL
@@ -2248,12 +2234,14 @@ void FFmpegWriter::InitScalers(int source_width, int source_height) {
// Init the software scaler from FFMpeg
#if HAVE_HW_ACCEL
if (hw_en_on && hw_en_supported) {
- img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_PIX_FMT_NV12, scale_mode, NULL, NULL, NULL);
+ img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA,
+ info.width, info.height, AV_PIX_FMT_NV12, scale_mode, NULL, NULL, NULL);
} else
#endif // HAVE_HW_ACCEL
{
- img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_GET_CODEC_PIXEL_FORMAT(video_st, video_st->codec), scale_mode,
- NULL, NULL, NULL);
+ img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA,
+ info.width, info.height, AV_GET_CODEC_PIXEL_FORMAT(video_st, video_st->codec),
+ scale_mode, NULL, NULL, NULL);
}
// Add rescaler to vector
diff --git a/include/FFmpegWriter.h b/src/FFmpegWriter.h
similarity index 98%
rename from include/FFmpegWriter.h
rename to src/FFmpegWriter.h
index 98fbbb590..6d9da6e53 100644
--- a/include/FFmpegWriter.h
+++ b/src/FFmpegWriter.h
@@ -47,8 +47,6 @@
#include
#include
-#include
-#include
#include
#include "CacheMemory.h"
#include "Exceptions.h"
@@ -251,9 +249,11 @@ namespace openshot {
public:
- /// @brief Constructor for FFmpegWriter. Throws one of the following exceptions.
+ /// @brief Constructor for FFmpegWriter.
+ /// Throws an exception on failure to open path.
+ ///
/// @param path The file path of the video file you want to open and read
- FFmpegWriter(std::string path);
+ FFmpegWriter(const std::string& path);
/// Close the writer
void Close();
diff --git a/src/Fraction.cpp b/src/Fraction.cpp
index c9cdad55d..869ef35ff 100644
--- a/src/Fraction.cpp
+++ b/src/Fraction.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/Fraction.h"
+#include "Fraction.h"
using namespace openshot;
diff --git a/include/Fraction.h b/src/Fraction.h
similarity index 100%
rename from include/Fraction.h
rename to src/Fraction.h
diff --git a/src/Frame.cpp b/src/Frame.cpp
index 4bd8f03f7..0673b6379 100644
--- a/src/Frame.cpp
+++ b/src/Frame.cpp
@@ -28,7 +28,22 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/Frame.h"
+#include "Frame.h"
+#include "JuceHeader.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include // for std::this_thread::sleep_for
#include // for std::chrono::milliseconds
@@ -36,56 +51,30 @@
using namespace std;
using namespace openshot;
-// Constructor - blank frame (300x200 blank image, 48kHz audio silence)
-Frame::Frame() : number(1), pixel_ratio(1,1), channels(2), width(1), height(1), color("#000000"),
- channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL), has_audio_data(false), has_image_data(false),
- max_audio_sample(0)
-{
- // Init the image magic and audio buffer
- audio = std::shared_ptr(new juce::AudioSampleBuffer(channels, 0));
-
- // initialize the audio samples to zero (silence)
- audio->clear();
-}
-
-// Constructor - image only (48kHz audio silence)
-Frame::Frame(int64_t number, int width, int height, std::string color)
- : number(number), pixel_ratio(1,1), channels(2), width(width), height(height), color(color),
- channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL), has_audio_data(false), has_image_data(false),
+// Constructor - image & audio
+Frame::Frame(int64_t number, int width, int height, std::string color, int samples, int channels)
+ : audio(std::make_shared(channels, samples)),
+ number(number), width(width), height(height),
+ pixel_ratio(1,1), color(color), qbuffer(NULL),
+ channels(channels), channel_layout(LAYOUT_STEREO),
+ sample_rate(44100),
+ has_audio_data(false), has_image_data(false),
max_audio_sample(0)
{
- // Init the image magic and audio buffer
- audio = std::shared_ptr(new juce::AudioSampleBuffer(channels, 0));
-
- // initialize the audio samples to zero (silence)
+ // zero (fill with silence) the audio buffer
audio->clear();
}
-// Constructor - audio only (300x200 blank image)
-Frame::Frame(int64_t number, int samples, int channels) :
- number(number), pixel_ratio(1,1), channels(channels), width(1), height(1), color("#000000"),
- channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL), has_audio_data(false), has_image_data(false),
- max_audio_sample(0)
-{
- // Init the image magic and audio buffer
- audio = std::shared_ptr(new juce::AudioSampleBuffer(channels, samples));
-
- // initialize the audio samples to zero (silence)
- audio->clear();
-}
+// Delegating Constructor - blank frame
+Frame::Frame() : Frame::Frame(1, 1, 1, "#000000", 0, 2) {};
-// Constructor - image & audio
-Frame::Frame(int64_t number, int width, int height, std::string color, int samples, int channels)
- : number(number), pixel_ratio(1,1), channels(channels), width(width), height(height), color(color),
- channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL), has_audio_data(false), has_image_data(false),
- max_audio_sample(0)
-{
- // Init the image magic and audio buffer
- audio = std::shared_ptr(new juce::AudioSampleBuffer(channels, samples));
+// Delegating Constructor - image only
+Frame::Frame(int64_t number, int width, int height, std::string color)
+ : Frame::Frame(number, width, height, color, 0, 2) {};
- // initialize the audio samples to zero (silence)
- audio->clear();
-}
+// Delegating Constructor - audio only
+Frame::Frame(int64_t number, int samples, int channels)
+ : Frame::Frame(number, 1, 1, "#000000", samples, channels) {};
// Copy constructor
@@ -120,11 +109,11 @@ void Frame::DeepCopy(const Frame& other)
max_audio_sample = other.max_audio_sample;
if (other.image)
- image = std::shared_ptr(new QImage(*(other.image)));
+ image = std::make_shared(*(other.image));
if (other.audio)
- audio = std::shared_ptr(new juce::AudioSampleBuffer(*(other.audio)));
+ audio = std::make_shared(*(other.audio));
if (other.wave_image)
- wave_image = std::shared_ptr(new QImage(*(other.wave_image)));
+ wave_image = std::make_shared(*(other.wave_image));
}
// Destructor
@@ -144,7 +133,7 @@ void Frame::Display()
// Only create the QApplication once
static int argc = 1;
static char* argv[1] = {NULL};
- previewApp = std::shared_ptr(new QApplication(argc, argv));
+ previewApp = std::make_shared(argc, argv);
}
// Get preview image
@@ -158,7 +147,8 @@ void Frame::Display()
int new_height = previewImage->size().height() * pixel_ratio.Reciprocal().ToDouble();
// Resize to fix DAR
- previewImage = std::shared_ptr(new QImage(previewImage->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
+ previewImage = std::make_shared(previewImage->scaled(
+ new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
// Create window
@@ -234,7 +224,8 @@ std::shared_ptr Frame::GetWaveform(int width, int height, int Red, int G
}
// Create blank image
- wave_image = std::shared_ptr(new QImage(total_width, total_height, QImage::Format_RGBA8888));
+ wave_image = std::make_shared(
+ total_width, total_height, QImage::Format_RGBA8888_Premultiplied);
wave_image->fill(QColor(0,0,0,0));
// Load QPainter with wave_image device
@@ -259,13 +250,13 @@ std::shared_ptr Frame::GetWaveform(int width, int height, int Red, int G
// Resize Image (if requested)
if (width != total_width || height != total_height) {
QImage scaled_wave_image = wave_image->scaled(width, height, Qt::IgnoreAspectRatio, Qt::FastTransformation);
- wave_image = std::shared_ptr(new QImage(scaled_wave_image));
+ wave_image = std::make_shared(scaled_wave_image);
}
}
else
{
// No audio samples present
- wave_image = std::shared_ptr(new QImage(width, height, QImage::Format_RGBA8888));
+ wave_image = std::make_shared(width, height, QImage::Format_RGBA8888_Premultiplied);
wave_image->fill(QColor(QString::fromStdString("#000000")));
}
@@ -300,7 +291,7 @@ void Frame::DisplayWaveform()
// Only create the QApplication once
static int argc = 1;
static char* argv[1] = {NULL};
- previewApp = std::shared_ptr(new QApplication(argc, argv));
+ previewApp = std::make_shared(argc, argv);
}
// Create window
@@ -605,11 +596,15 @@ void Frame::Save(std::string path, float scale, std::string format, int quality)
int new_height = previewImage->size().height() * pixel_ratio.Reciprocal().ToDouble();
// Resize to fix DAR
- previewImage = std::shared_ptr(new QImage(previewImage->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
+ previewImage = std::make_shared(previewImage->scaled(
+ new_width, new_height,
+ Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
// Resize image
- previewImage = std::shared_ptr(new QImage(previewImage->scaled(new_width * scale, new_height * scale, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
+ previewImage = std::make_shared(previewImage->scaled(
+ new_width * scale, new_height * scale,
+ Qt::KeepAspectRatio, Qt::SmoothTransformation));
}
// Save image
@@ -621,7 +616,8 @@ void Frame::Thumbnail(std::string path, int new_width, int new_height, std::stri
std::string background_color, bool ignore_aspect, std::string format, int quality, float rotate) {
// Create blank thumbnail image & fill background color
- std::shared_ptr thumbnail = std::shared_ptr(new QImage(new_width, new_height, QImage::Format_RGBA8888));
+ auto thumbnail = std::make_shared(
+ new_width, new_height, QImage::Format_RGBA8888_Premultiplied);
thumbnail->fill(QColor(QString::fromStdString(background_color)));
// Create painter
@@ -639,16 +635,22 @@ void Frame::Thumbnail(std::string path, int new_width, int new_height, std::stri
int aspect_height = previewImage->size().height() * pixel_ratio.Reciprocal().ToDouble();
// Resize to fix DAR
- previewImage = std::shared_ptr(new QImage(previewImage->scaled(aspect_width, aspect_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
+ previewImage = std::make_shared(previewImage->scaled(
+ aspect_width, aspect_height,
+ Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
// Resize frame image
if (ignore_aspect)
// Ignore aspect ratio
- previewImage = std::shared_ptr(new QImage(previewImage->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
+ previewImage = std::make_shared(previewImage->scaled(
+ new_width, new_height,
+ Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
else
// Maintain aspect ratio
- previewImage = std::shared_ptr(new QImage(previewImage->scaled(new_width, new_height, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
+ previewImage = std::make_shared(previewImage->scaled(
+ new_width, new_height,
+ Qt::KeepAspectRatio, Qt::SmoothTransformation));
// Composite frame image onto background (centered)
int x = (new_width - previewImage->size().width()) / 2.0; // center
@@ -672,14 +674,16 @@ void Frame::Thumbnail(std::string path, int new_width, int new_height, std::stri
// Overlay Image (if any)
if (overlay_path != "") {
// Open overlay
- std::shared_ptr overlay = std::shared_ptr(new QImage());
+ auto overlay = std::make_shared();
overlay->load(QString::fromStdString(overlay_path));
// Set pixel format
- overlay = std::shared_ptr(new QImage(overlay->convertToFormat(QImage::Format_RGBA8888)));
+ overlay = std::make_shared(
+ overlay->convertToFormat(QImage::Format_RGBA8888_Premultiplied));
// Resize to fit
- overlay = std::shared_ptr(new QImage(overlay->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
+ overlay = std::make_shared(overlay->scaled(
+ new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
// Composite onto thumbnail
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
@@ -690,14 +694,16 @@ void Frame::Thumbnail(std::string path, int new_width, int new_height, std::stri
// Mask Image (if any)
if (mask_path != "") {
// Open mask
- std::shared_ptr mask = std::shared_ptr(new QImage());
+ auto mask = std::make_shared();
mask->load(QString::fromStdString(mask_path));
// Set pixel format
- mask = std::shared_ptr(new QImage(mask->convertToFormat(QImage::Format_RGBA8888)));
+ mask = std::make_shared(
+ mask->convertToFormat(QImage::Format_RGBA8888_Premultiplied));
// Resize to fit
- mask = std::shared_ptr(new QImage(mask->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
+ mask = std::make_shared(mask->scaled(
+ new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
// Negate mask
mask->invertPixels();
@@ -750,7 +756,7 @@ void Frame::AddColor(int new_width, int new_height, std::string new_color)
const GenericScopedLock lock(addingImageSection);
#pragma omp critical (AddImage)
{
- image = std::shared_ptr(new QImage(new_width, new_height, QImage::Format_RGBA8888));
+ image = std::make_shared(new_width, new_height, QImage::Format_RGBA8888_Premultiplied);
// Fill with solid color
image->fill(QColor(QString::fromStdString(color)));
@@ -762,30 +768,31 @@ void Frame::AddColor(int new_width, int new_height, std::string new_color)
}
// Add (or replace) pixel data to the frame
-void Frame::AddImage(int new_width, int new_height, int bytes_per_pixel, QImage::Format type, const unsigned char *pixels_)
+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);
- int buffer_size = new_width * new_height * bytes_per_pixel;
- qbuffer = new unsigned char[buffer_size]();
-
- // Copy buffer data
- memcpy((unsigned char*)qbuffer, pixels_, buffer_size);
-
- // Create new image object, and fill with pixel data
- #pragma omp critical (AddImage)
{
- image = std::shared_ptr(new QImage(qbuffer, new_width, new_height, new_width * bytes_per_pixel, type, (QImageCleanupFunction) &openshot::Frame::cleanUpBuffer, (void*) qbuffer));
-
- // Always convert to RGBA8888 (if different)
- if (image->format() != QImage::Format_RGBA8888)
- *image = image->convertToFormat(QImage::Format_RGBA8888);
-
- // Update height and width
- width = image->width();
- height = image->height();
- has_image_data = true;
- }
+ const GenericScopedLock lock(addingImageSection);
+ int buffer_size = new_width * new_height * bytes_per_pixel;
+ qbuffer = new unsigned char[buffer_size]();
+
+ // Copy buffer data
+ memcpy((unsigned char*)qbuffer, pixels_, buffer_size);
+
+ } // Release addingImageSection lock
+
+ // Create new image object from pixel data
+ auto new_image = std::make_shared(
+ qbuffer,
+ new_width, new_height,
+ new_width * bytes_per_pixel,
+ type,
+ (QImageCleanupFunction) &openshot::Frame::cleanUpBuffer,
+ (void*) qbuffer
+ );
+ AddImage(new_image);
}
// Add (or replace) pixel data to the frame
@@ -801,9 +808,9 @@ void Frame::AddImage(std::shared_ptr new_image)
{
image = new_image;
- // Always convert to RGBA8888 (if different)
- if (image->format() != QImage::Format_RGBA8888)
- *image = image->convertToFormat(QImage::Format_RGBA8888);
+ // Always convert to Format_RGBA8888_Premultiplied (if different)
+ if (image->format() != QImage::Format_RGBA8888_Premultiplied)
+ *image = image->convertToFormat(QImage::Format_RGBA8888_Premultiplied);
// Update height and width
width = image->width();
@@ -825,7 +832,6 @@ void Frame::AddImage(std::shared_ptr new_image, bool only_odd_lines)
AddImage(new_image);
} else {
-
// Ignore image of different sizes or formats
bool ret=false;
#pragma omp critical (AddImage)
@@ -833,8 +839,9 @@ void Frame::AddImage(std::shared_ptr new_image, bool only_odd_lines)
if (image == new_image || image->size() != new_image->size()) {
ret = true;
}
- else if (new_image->format() != image->format()) {
- new_image = std::shared_ptr(new QImage(new_image->convertToFormat(image->format())));
+ else if (new_image->format() != QImage::Format_RGBA8888_Premultiplied) {
+ new_image = std::make_shared(
+ new_image->convertToFormat(QImage::Format_RGBA8888_Premultiplied));
}
}
if (ret) {
@@ -992,7 +999,8 @@ std::shared_ptr Frame::GetMagickImage()
const QRgb *tmpBits = (const QRgb*)image->constBits();
// Create new image object, and fill with pixel data
- std::shared_ptr magick_image = std::shared_ptr(new Magick::Image(image->width(), image->height(),"RGBA", Magick::CharPixel, tmpBits));
+ auto magick_image = std::make_shared(
+ image->width(), image->height(),"RGBA", Magick::CharPixel, tmpBits);
// Give image a transparent background color
magick_image->backgroundColor(Magick::Color("none"));
@@ -1021,7 +1029,9 @@ void Frame::AddMagickImage(std::shared_ptr new_image)
MagickCore::ExportImagePixels(new_image->constImage(), 0, 0, new_image->columns(), new_image->rows(), "RGBA", Magick::CharPixel, buffer, &exception);
// Create QImage of frame data
- image = std::shared_ptr(new QImage(qbuffer, width, height, width * BPP, QImage::Format_RGBA8888, (QImageCleanupFunction) &cleanUpBuffer, (void*) qbuffer));
+ image = std::make_shared(
+ qbuffer, width, height, width * BPP, QImage::Format_RGBA8888_Premultiplied,
+ (QImageCleanupFunction) &cleanUpBuffer, (void*) qbuffer);
// Update height and width
width = image->width();
diff --git a/include/Frame.h b/src/Frame.h
similarity index 93%
rename from include/Frame.h
rename to src/Frame.h
index 7e8442219..d73d0c9e5 100644
--- a/include/Frame.h
+++ b/src/Frame.h
@@ -43,16 +43,8 @@
#include
#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+#include
+#include
#include
#include
#include "ZmqLogger.h"
@@ -82,17 +74,17 @@ namespace openshot
* There are many ways to create an instance of an openshot::Frame:
* @code
*
- * // Most basic: a blank frame (300x200 blank image, 48kHz audio silence)
+ * // Most basic: a blank frame (all default values)
* Frame();
*
- * // Image only settings (48kHz audio silence)
+ * // Image only settings
* Frame(1, // Frame number
* 720, // Width of image
* 480, // Height of image
* "#000000" // HTML color code of background color
* );
*
- * // Audio only (300x200 blank image)
+ * // Audio only
* Frame(number, // Frame number
* 44100, // Sample rate of audio stream
* 2 // Number of audio channels
@@ -108,7 +100,7 @@ namespace openshot
* );
*
* // Some methods require a shared pointer to an openshot::Frame object.
- * std::shared_ptr f(new Frame(1, 720, 480, "#000000", 44100, 2));
+ * auto f = std::make_shared(1, 720, 480, "#000000", 44100, 2);
*
* @endcode
*/
@@ -144,13 +136,13 @@ namespace openshot
bool has_image_data; ///< This frame has been loaded with pixel data
- /// Constructor - blank frame (300x200 blank image, 48kHz audio silence)
+ /// Constructor - blank frame
Frame();
- /// Constructor - image only (48kHz audio silence)
+ /// Constructor - image only
Frame(int64_t number, int width, int height, std::string color);
- /// Constructor - audio only (300x200 blank image)
+ /// Constructor - audio only
Frame(int64_t number, int samples, int channels);
/// Constructor - image & audio
diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp
index 4c561f8fe..096976cfd 100644
--- a/src/FrameMapper.cpp
+++ b/src/FrameMapper.cpp
@@ -28,7 +28,8 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/FrameMapper.h"
+#include "FrameMapper.h"
+#include "Clip.h"
using namespace std;
using namespace openshot;
@@ -116,6 +117,15 @@ void FrameMapper::Init()
// Clear cache
final_cache.Clear();
+ // Get clip position from parent clip (if any)
+ float clipPosition = 0.0;
+ float clipStart = 0.0;
+ Clip *parent = (Clip *) ParentClip();
+ if (parent) {
+ clipPosition = parent->Position();
+ clipStart = parent->Start();
+ }
+
// Some framerates are handled special, and some use a generic Keyframe curve to
// map the framerates. These are the special framerates:
if ((fabs(original.ToFloat() - 24.0) < 1e-7 || fabs(original.ToFloat() - 25.0) < 1e-7 || fabs(original.ToFloat() - 30.0) < 1e-7) &&
@@ -257,12 +267,12 @@ void FrameMapper::Init()
// the original sample rate.
int64_t end_samples_frame = start_samples_frame;
int end_samples_position = start_samples_position;
- int remaining_samples = Frame::GetSamplesPerFrame(frame_number, target, reader->info.sample_rate, reader->info.channels);
+ int remaining_samples = Frame::GetSamplesPerFrame(AdjustFrameNumber(frame_number, clipPosition, clipStart), target, reader->info.sample_rate, reader->info.channels);
while (remaining_samples > 0)
{
// get original samples
- int original_samples = Frame::GetSamplesPerFrame(end_samples_frame, original, reader->info.sample_rate, reader->info.channels) - end_samples_position;
+ int original_samples = Frame::GetSamplesPerFrame(AdjustFrameNumber(end_samples_frame, clipPosition, clipStart), original, reader->info.sample_rate, reader->info.channels) - end_samples_position;
// Enough samples
if (original_samples >= remaining_samples)
@@ -282,12 +292,12 @@ void FrameMapper::Init()
// Create the sample mapping struct
- SampleRange Samples = {start_samples_frame, start_samples_position, end_samples_frame, end_samples_position, Frame::GetSamplesPerFrame(frame_number, target, reader->info.sample_rate, reader->info.channels)};
+ SampleRange Samples = {start_samples_frame, start_samples_position, end_samples_frame, end_samples_position, Frame::GetSamplesPerFrame(AdjustFrameNumber(frame_number, clipPosition, clipStart), target, reader->info.sample_rate, reader->info.channels)};
// Reset the audio variables
start_samples_frame = end_samples_frame;
start_samples_position = end_samples_position + 1;
- if (start_samples_position >= Frame::GetSamplesPerFrame(start_samples_frame, original, reader->info.sample_rate, reader->info.channels))
+ if (start_samples_position >= Frame::GetSamplesPerFrame(AdjustFrameNumber(start_samples_frame, clipPosition, clipStart), original, reader->info.sample_rate, reader->info.channels))
{
start_samples_frame += 1; // increment the frame (since we need to wrap onto the next one)
start_samples_position = 0; // reset to 0, since we wrapped
@@ -353,8 +363,17 @@ std::shared_ptr FrameMapper::GetOrCreateFrame(int64_t number)
{
std::shared_ptr new_frame;
+ // Get clip position from parent clip (if any)
+ float clipPosition = 0.0;
+ float clipStart = 0.0;
+ Clip *parent = (Clip *) ParentClip();
+ if (parent) {
+ clipPosition = parent->Position();
+ clipStart = parent->Start();
+ }
+
// Init some basic properties about this frame (keep sample rate and # channels the same as the original reader for now)
- int samples_in_frame = Frame::GetSamplesPerFrame(number, target, reader->info.sample_rate, reader->info.channels);
+ int samples_in_frame = Frame::GetSamplesPerFrame(AdjustFrameNumber(number, clipPosition, clipStart), target, reader->info.sample_rate, reader->info.channels);
try {
// Debug output
@@ -404,6 +423,15 @@ std::shared_ptr FrameMapper::GetFrame(int64_t requested_frame)
final_frame = final_cache.GetFrame(requested_frame);
if (final_frame) return final_frame;
+ // Get clip position from parent clip (if any)
+ float clipPosition = 0.0;
+ float clipStart = 0.0;
+ Clip *parent = (Clip *) ParentClip();
+ if (parent) {
+ clipPosition = parent->Position();
+ clipStart = parent->Start();
+ }
+
// Minimum number of frames to process (for performance reasons)
// Dialing this down to 1 for now, as it seems to improve performance, and reduce export crashes
int minimum_frames = 1;
@@ -427,7 +455,7 @@ std::shared_ptr FrameMapper::GetFrame(int64_t requested_frame)
// Get # of channels in the actual frame
int channels_in_frame = mapped_frame->GetAudioChannelsCount();
- int samples_in_frame = Frame::GetSamplesPerFrame(frame_number, target, mapped_frame->SampleRate(), channels_in_frame);
+ int samples_in_frame = Frame::GetSamplesPerFrame(AdjustFrameNumber(frame_number, clipPosition, clipStart), target, mapped_frame->SampleRate(), channels_in_frame);
// Determine if mapped frame is identical to source frame
// including audio sample distribution according to mapped.Samples,
@@ -450,7 +478,8 @@ std::shared_ptr FrameMapper::GetFrame(int64_t requested_frame)
}
// Create a new frame
- std::shared_ptr frame = std::make_shared(frame_number, 1, 1, "#000000", samples_in_frame, channels_in_frame);
+ auto frame = std::make_shared(
+ frame_number, 1, 1, "#000000", samples_in_frame, channels_in_frame);
frame->SampleRate(mapped_frame->SampleRate());
frame->ChannelsLayout(mapped_frame->ChannelsLayout());
@@ -460,13 +489,14 @@ std::shared_ptr FrameMapper::GetFrame(int64_t requested_frame)
odd_frame = GetOrCreateFrame(mapped.Odd.Frame);
if (odd_frame)
- frame->AddImage(std::shared_ptr(new QImage(*odd_frame->GetImage())), true);
+ frame->AddImage(std::make_shared(*odd_frame->GetImage()), true);
if (mapped.Odd.Frame != mapped.Even.Frame) {
// Add even lines (if different than the previous image)
std::shared_ptr even_frame;
even_frame = GetOrCreateFrame(mapped.Even.Frame);
if (even_frame)
- frame->AddImage(std::shared_ptr(new QImage(*even_frame->GetImage())), false);
+ frame->AddImage(
+ std::make_shared(*even_frame->GetImage()), false);
}
// Resample audio on frame (if needed)
@@ -594,21 +624,6 @@ void FrameMapper::PrintMapping()
// Recalculate mappings
Init();
- // Get the difference (in frames) between the original and target frame rates
- float difference = target.ToInt() - original.ToInt();
-
- int field_interval = 0;
- int frame_interval = 0;
-
- if (difference != 0)
- {
- // Find the number (i.e. interval) of fields that need to be skipped or repeated
- field_interval = round(fabs(original.ToInt() / difference));
-
- // Get frame interval (2 fields per frame)
- frame_interval = field_interval * 2.0f;
- }
-
// Loop through frame mappings
for (float map = 1; map <= frames.size(); map++)
{
@@ -619,7 +634,6 @@ void FrameMapper::PrintMapping()
}
-
// Determine if reader is open or closed
bool FrameMapper::IsOpen() {
if (reader)
@@ -628,7 +642,6 @@ bool FrameMapper::IsOpen() {
return false;
}
-
// Open the internal reader
void FrameMapper::Open()
{
@@ -765,6 +778,15 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig
// Recalculate mappings
Init();
+ // Get clip position from parent clip (if any)
+ float clipPosition = 0.0;
+ float clipStart = 0.0;
+ Clip *parent = (Clip *) ParentClip();
+ if (parent) {
+ clipPosition = parent->Position();
+ clipStart = parent->Start();
+ }
+
// Init audio buffers / variables
int total_frame_samples = 0;
int channels_in_frame = frame->GetAudioChannelsCount();
@@ -826,7 +848,7 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig
}
// Update total samples & input frame size (due to bigger or smaller data types)
- total_frame_samples = Frame::GetSamplesPerFrame(frame->number, target, info.sample_rate, info.channels);
+ total_frame_samples = Frame::GetSamplesPerFrame(AdjustFrameNumber(frame->number, clipPosition, clipStart), target, info.sample_rate, info.channels);
ZmqLogger::Instance()->AppendDebugMethod("FrameMapper::ResampleMappedAudio (adjust # of samples)", "total_frame_samples", total_frame_samples, "info.sample_rate", info.sample_rate, "sample_rate_in_frame", sample_rate_in_frame, "info.channels", info.channels, "channels_in_frame", channels_in_frame, "original_frame_number", original_frame_number);
@@ -935,3 +957,15 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig
delete[] resampled_samples;
resampled_samples = NULL;
}
+
+// Adjust frame number for Clip position and start (which can result in a different number)
+int64_t FrameMapper::AdjustFrameNumber(int64_t clip_frame_number, float position, float start) {
+
+ int64_t clip_start_frame = (start * info.fps.ToDouble()) + 1;
+ int64_t clip_start_position = round(position * info.fps.ToDouble()) + 1;
+
+ int64_t frame_number = clip_frame_number + clip_start_position - clip_start_frame;
+
+ ///std::cout << "Conv Position " << round(position * info.fps.ToDouble()) << " position: " << position << " info::fps: " << info.fps.ToDouble() << std::endl;
+ return frame_number;
+}
diff --git a/include/FrameMapper.h b/src/FrameMapper.h
similarity index 97%
rename from include/FrameMapper.h
rename to src/FrameMapper.h
index e78401a9b..7f6c9c165 100644
--- a/include/FrameMapper.h
+++ b/src/FrameMapper.h
@@ -154,6 +154,9 @@ namespace openshot
// Get Frame or Generate Blank Frame
std::shared_ptr GetOrCreateFrame(int64_t number);
+ /// Adjust frame number for Clip position and start (which can result in a different number)
+ int64_t AdjustFrameNumber(int64_t clip_frame_number, float position, float start);
+
// Use the original and target frame rates and a pull-down technique to create
// a mapping between the original fields and frames or a video to a new frame rate.
// This might repeat or skip fields and frames of the original video, depending on
@@ -217,7 +220,6 @@ namespace openshot
/// Resample audio and map channels (if needed)
void ResampleMappedAudio(std::shared_ptr frame, int64_t original_frame_number);
-
};
}
diff --git a/src/ImageReader.cpp b/src/ImageReader.cpp
index 9ce3a70ff..ad21be157 100644
--- a/src/ImageReader.cpp
+++ b/src/ImageReader.cpp
@@ -31,18 +31,11 @@
// Require ImageMagick support
#ifdef USE_IMAGEMAGICK
-#include "../include/ImageReader.h"
+#include "ImageReader.h"
using namespace openshot;
-ImageReader::ImageReader(std::string path) : path(path), is_open(false)
-{
- // Open and Close the reader, to populate its attributes (such as height, width, etc...)
- Open();
- Close();
-}
-
-ImageReader::ImageReader(std::string path, bool inspect_reader) : path(path), is_open(false)
+ImageReader::ImageReader(const std::string& path, bool inspect_reader) : path(path), is_open(false)
{
// Open and Close the reader, to populate its attributes (such as height, width, etc...)
if (inspect_reader) {
@@ -61,7 +54,7 @@ void ImageReader::Open()
try
{
// load image
- image = std::shared_ptr(new Magick::Image(path));
+ image = std::make_shared(path);
// Give image a transparent background color
image->backgroundColor(Magick::Color("none"));
@@ -126,7 +119,9 @@ std::shared_ptr ImageReader::GetFrame(int64_t requested_frame)
throw ReaderClosed("The FFmpegReader is closed. Call Open() before calling this method.", path);
// Create or get frame object
- std::shared_ptr image_frame(new Frame(requested_frame, image->size().width(), image->size().height(), "#000000", 0, 2));
+ auto image_frame = std::make_shared(
+ requested_frame, image->size().width(), image->size().height(),
+ "#000000", 0, 2);
// Add Image data to frame
image_frame->AddMagickImage(image);
diff --git a/include/ImageReader.h b/src/ImageReader.h
similarity index 89%
rename from include/ImageReader.h
rename to src/ImageReader.h
index 5aafcc8f7..aa96272fd 100644
--- a/include/ImageReader.h
+++ b/src/ImageReader.h
@@ -76,15 +76,15 @@ namespace openshot
bool is_open;
public:
-
- /// Constructor for ImageReader. This automatically opens the media file and loads
- /// frame 1, or it throws one of the following exceptions.
- ImageReader(std::string path);
-
- /// Constructor for ImageReader. This only opens the media file to inspect its properties
- /// if inspect_reader=true. When not inspecting the media file, it's much faster, and useful
- /// when you are inflating the object using JSON after instantiating it.
- ImageReader(std::string path, bool inspect_reader);
+ /// @brief Constructor for ImageReader.
+ ///
+ /// Opens the media file to inspect its properties and loads frame 1,
+ /// iff inspect_reader == true (the default). Pass a false value in
+ /// the optional parameter to defer this initial Open()/Close() cycle.
+ ///
+ /// When not inspecting the media file, it's much faster, and useful
+ /// when you are inflating the object using JSON after instantiation.
+ ImageReader(const std::string& path, bool inspect_reader=true);
/// Close File
void Close() override;
diff --git a/src/ImageWriter.cpp b/src/ImageWriter.cpp
index 1b7a01e9b..275ea2703 100644
--- a/src/ImageWriter.cpp
+++ b/src/ImageWriter.cpp
@@ -34,7 +34,7 @@
//Require ImageMagick support
#ifdef USE_IMAGEMAGICK
-#include "../include/ImageWriter.h"
+#include "ImageWriter.h"
using namespace openshot;
diff --git a/include/ImageWriter.h b/src/ImageWriter.h
similarity index 100%
rename from include/ImageWriter.h
rename to src/ImageWriter.h
diff --git a/src/Json.cpp b/src/Json.cpp
index 0c83d9d62..9d6d9ba4d 100644
--- a/src/Json.cpp
+++ b/src/Json.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/Json.h"
+#include "Json.h"
const Json::Value openshot::stringToJson(const std::string value) {
diff --git a/include/Json.h b/src/Json.h
similarity index 100%
rename from include/Json.h
rename to src/Json.h
diff --git a/src/KeyFrame.cpp b/src/KeyFrame.cpp
index 57e424cf7..b113e6325 100644
--- a/src/KeyFrame.cpp
+++ b/src/KeyFrame.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/KeyFrame.h"
+#include "KeyFrame.h"
#include
#include
#include
diff --git a/include/KeyFrame.h b/src/KeyFrame.h
similarity index 100%
rename from include/KeyFrame.h
rename to src/KeyFrame.h
diff --git a/include/MagickUtilities.h b/src/MagickUtilities.h
similarity index 100%
rename from include/MagickUtilities.h
rename to src/MagickUtilities.h
diff --git a/include/OpenMPUtilities.h b/src/OpenMPUtilities.h
similarity index 85%
rename from include/OpenMPUtilities.h
rename to src/OpenMPUtilities.h
index 30bdd199a..b523bbd14 100644
--- a/include/OpenMPUtilities.h
+++ b/src/OpenMPUtilities.h
@@ -41,5 +41,12 @@
#define OPEN_MP_NUM_PROCESSORS (std::min(omp_get_num_procs(), std::max(2, openshot::Settings::Instance()->OMP_THREADS) ))
#define FF_NUM_PROCESSORS (std::min(omp_get_num_procs(), std::max(2, openshot::Settings::Instance()->FF_THREADS) ))
+// Set max-active-levels to the max supported, if possible
+// (supported_active_levels is OpenMP 5.0 (November 2018) or later, only.)
+#if (_OPENMP >= 201811)
+ #define OPEN_MP_MAX_ACTIVE openmp_get_supported_active_levels()
+#else
+ #define OPEN_MP_MAX_ACTIVE OPEN_MP_NUM_PROCESSORS
+#endif
#endif
diff --git a/include/OpenShot.h b/src/OpenShot.h
similarity index 99%
rename from include/OpenShot.h
rename to src/OpenShot.h
index 1c2d8870b..e1209ac49 100644
--- a/include/OpenShot.h
+++ b/src/OpenShot.h
@@ -138,6 +138,7 @@
#include "QtHtmlReader.h"
#include "QtImageReader.h"
#include "QtTextReader.h"
+#include "TimelineBase.h"
#include "Timeline.h"
#include "Settings.h"
#ifdef USE_OPENCV
diff --git a/include/OpenShotVersion.h.in b/src/OpenShotVersion.h.in
similarity index 100%
rename from include/OpenShotVersion.h.in
rename to src/OpenShotVersion.h.in
diff --git a/src/PlayerBase.cpp b/src/PlayerBase.cpp
index f152fbbb9..844b8d605 100644
--- a/src/PlayerBase.cpp
+++ b/src/PlayerBase.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/PlayerBase.h"
+#include "PlayerBase.h"
using namespace openshot;
diff --git a/include/PlayerBase.h b/src/PlayerBase.h
similarity index 100%
rename from include/PlayerBase.h
rename to src/PlayerBase.h
diff --git a/src/Point.cpp b/src/Point.cpp
index 136799778..4636b437d 100644
--- a/src/Point.cpp
+++ b/src/Point.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/Point.h"
+#include "Point.h"
using namespace std;
using namespace openshot;
diff --git a/include/Point.h b/src/Point.h
similarity index 100%
rename from include/Point.h
rename to src/Point.h
diff --git a/src/Profiles.cpp b/src/Profiles.cpp
index 5351520e9..167affe2c 100644
--- a/src/Profiles.cpp
+++ b/src/Profiles.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/Profiles.h"
+#include "Profiles.h"
using namespace openshot;
diff --git a/include/Profiles.h b/src/Profiles.h
similarity index 100%
rename from include/Profiles.h
rename to src/Profiles.h
diff --git a/src/Qt/AudioPlaybackThread.cpp b/src/Qt/AudioPlaybackThread.cpp
index 2ee1009c5..178642f6d 100644
--- a/src/Qt/AudioPlaybackThread.cpp
+++ b/src/Qt/AudioPlaybackThread.cpp
@@ -29,7 +29,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../../include/Qt/AudioPlaybackThread.h"
+#include "AudioPlaybackThread.h"
#include // for std::this_thread::sleep_for
#include // for std::chrono::milliseconds
diff --git a/include/Qt/AudioPlaybackThread.h b/src/Qt/AudioPlaybackThread.h
similarity index 100%
rename from include/Qt/AudioPlaybackThread.h
rename to src/Qt/AudioPlaybackThread.h
diff --git a/src/Qt/PlayerDemo.cpp b/src/Qt/PlayerDemo.cpp
index e5f0e11d0..bd5e45aa6 100644
--- a/src/Qt/PlayerDemo.cpp
+++ b/src/Qt/PlayerDemo.cpp
@@ -28,9 +28,11 @@
* along with OpenShot Library. If not, see .
*/
-#include
-#include "../../include/QtPlayer.h"
-#include "../../include/Qt/PlayerDemo.h"
+#include
+
+#include "PlayerDemo.h"
+#include "../QtPlayer.h"
+
#include
#include
#include
@@ -105,7 +107,6 @@ void PlayerDemo::keyPressEvent(QKeyEvent *event)
}
else if (event->key() == Qt::Key_J) {
- std::cout << "BACKWARD" << player->Speed() - 1 << std::endl;
if (player->Speed() - 1 != 0)
player->Speed(player->Speed() - 1);
else
@@ -115,7 +116,6 @@ void PlayerDemo::keyPressEvent(QKeyEvent *event)
player->Play();
}
else if (event->key() == Qt::Key_L) {
- std::cout << "FORWARD" << player->Speed() + 1 << std::endl;
if (player->Speed() + 1 != 0)
player->Speed(player->Speed() + 1);
else
@@ -126,19 +126,16 @@ void PlayerDemo::keyPressEvent(QKeyEvent *event)
}
else if (event->key() == Qt::Key_Left) {
- std::cout << "FRAME STEP -1" << std::endl;
if (player->Speed() != 0)
player->Speed(0);
player->Seek(player->Position() - 1);
}
else if (event->key() == Qt::Key_Right) {
- std::cout << "FRAME STEP +1" << std::endl;
if (player->Speed() != 0)
player->Speed(0);
player->Seek(player->Position() + 1);
}
else if (event->key() == Qt::Key_Escape) {
- std::cout << "QUIT PLAYER" << std::endl;
QWidget *pWin = QApplication::activeWindow();
pWin->hide();
diff --git a/include/Qt/PlayerDemo.h b/src/Qt/PlayerDemo.h
similarity index 100%
rename from include/Qt/PlayerDemo.h
rename to src/Qt/PlayerDemo.h
diff --git a/src/Qt/PlayerPrivate.cpp b/src/Qt/PlayerPrivate.cpp
index db6f2ff10..75052fc31 100644
--- a/src/Qt/PlayerPrivate.cpp
+++ b/src/Qt/PlayerPrivate.cpp
@@ -29,7 +29,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../../include/Qt/PlayerPrivate.h"
+#include "PlayerPrivate.h"
#include // for std::this_thread::sleep_for
#include // for std::chrono milliseconds, high_resolution_clock
diff --git a/include/Qt/PlayerPrivate.h b/src/Qt/PlayerPrivate.h
similarity index 100%
rename from include/Qt/PlayerPrivate.h
rename to src/Qt/PlayerPrivate.h
diff --git a/src/Qt/VideoCacheThread.cpp b/src/Qt/VideoCacheThread.cpp
index 4279e2381..f817c93f3 100644
--- a/src/Qt/VideoCacheThread.cpp
+++ b/src/Qt/VideoCacheThread.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../../include/Qt/VideoCacheThread.h"
+#include "VideoCacheThread.h"
#include
#include // for std::this_thread::sleep_for
diff --git a/include/Qt/VideoCacheThread.h b/src/Qt/VideoCacheThread.h
similarity index 100%
rename from include/Qt/VideoCacheThread.h
rename to src/Qt/VideoCacheThread.h
diff --git a/src/Qt/VideoPlaybackThread.cpp b/src/Qt/VideoPlaybackThread.cpp
index f1cff7565..01e2871bd 100644
--- a/src/Qt/VideoPlaybackThread.cpp
+++ b/src/Qt/VideoPlaybackThread.cpp
@@ -29,7 +29,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../../include/Qt/VideoPlaybackThread.h"
+#include "VideoPlaybackThread.h"
namespace openshot
{
diff --git a/include/Qt/VideoPlaybackThread.h b/src/Qt/VideoPlaybackThread.h
similarity index 100%
rename from include/Qt/VideoPlaybackThread.h
rename to src/Qt/VideoPlaybackThread.h
diff --git a/src/Qt/VideoRenderWidget.cpp b/src/Qt/VideoRenderWidget.cpp
index 2bfe8fa23..528983720 100644
--- a/src/Qt/VideoRenderWidget.cpp
+++ b/src/Qt/VideoRenderWidget.cpp
@@ -28,8 +28,14 @@
* along with OpenShot Library. If not, see .
*/
-#include "../../include/Qt/VideoRenderWidget.h"
-#include
+#include "VideoRenderWidget.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
VideoRenderWidget::VideoRenderWidget(QWidget *parent)
: QWidget(parent), renderer(new VideoRenderer(this))
diff --git a/include/Qt/VideoRenderWidget.h b/src/Qt/VideoRenderWidget.h
similarity index 96%
rename from include/Qt/VideoRenderWidget.h
rename to src/Qt/VideoRenderWidget.h
index 07c61037b..4d9ac17ff 100644
--- a/include/Qt/VideoRenderWidget.h
+++ b/src/Qt/VideoRenderWidget.h
@@ -31,11 +31,13 @@
#ifndef OPENSHOT_VIDEO_RENDERER_WIDGET_H
#define OPENSHOT_VIDEO_RENDERER_WIDGET_H
-#include
-#include
#include "../Fraction.h"
#include "VideoRenderer.h"
+#include
+#include
+#include
+#include
class VideoRenderWidget : public QWidget
{
diff --git a/src/Qt/VideoRenderer.cpp b/src/Qt/VideoRenderer.cpp
index 8d0e3a1d3..e70e85451 100644
--- a/src/Qt/VideoRenderer.cpp
+++ b/src/Qt/VideoRenderer.cpp
@@ -28,7 +28,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../../include/Qt/VideoRenderer.h"
+#include "VideoRenderer.h"
VideoRenderer::VideoRenderer(QObject *parent)
diff --git a/include/Qt/VideoRenderer.h b/src/Qt/VideoRenderer.h
similarity index 100%
rename from include/Qt/VideoRenderer.h
rename to src/Qt/VideoRenderer.h
diff --git a/src/QtHtmlReader.cpp b/src/QtHtmlReader.cpp
index 6b502fbd4..d2d96186c 100644
--- a/src/QtHtmlReader.cpp
+++ b/src/QtHtmlReader.cpp
@@ -30,7 +30,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/QtHtmlReader.h"
+#include "QtHtmlReader.h"
#include
#include
#include
@@ -62,7 +62,7 @@ void QtHtmlReader::Open()
if (!is_open)
{
// create image
- image = std::shared_ptr(new QImage(width, height, QImage::Format_RGBA8888));
+ image = std::make_shared(width, height, QImage::Format_RGBA8888_Premultiplied);
image->fill(QColor(background_color.c_str()));
//start painting
@@ -162,7 +162,9 @@ std::shared_ptr QtHtmlReader::GetFrame(int64_t requested_frame)
if (image)
{
// Create or get frame object
- std::shared_ptr image_frame(new Frame(requested_frame, image->size().width(), image->size().height(), background_color, 0, 2));
+ auto image_frame = std::make_shared(
+ requested_frame, image->size().width(), image->size().height(),
+ background_color, 0, 2);
// Add Image data to frame
image_frame->AddImage(image);
@@ -171,7 +173,8 @@ std::shared_ptr QtHtmlReader::GetFrame(int64_t requested_frame)
return image_frame;
} else {
// return empty frame
- std::shared_ptr image_frame(new Frame(1, 640, 480, background_color, 0, 2));
+ auto image_frame = std::make_shared(
+ 1, 640, 480, background_color, 0, 2);
// return frame object
return image_frame;
diff --git a/include/QtHtmlReader.h b/src/QtHtmlReader.h
similarity index 100%
rename from include/QtHtmlReader.h
rename to src/QtHtmlReader.h
diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp
index 59060ccd7..8fb222db4 100644
--- a/src/QtImageReader.cpp
+++ b/src/QtImageReader.cpp
@@ -28,10 +28,10 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/QtImageReader.h"
-#include "../include/Settings.h"
-#include "../include/Clip.h"
-#include "../include/CacheMemory.h"
+#include "QtImageReader.h"
+#include "Settings.h"
+#include "Clip.h"
+#include "CacheMemory.h"
#include
#include
#include
@@ -44,13 +44,6 @@
using namespace openshot;
-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{QString::fromStdString(path)}, is_open(false)
{
// Open and Close the reader, to populate its attributes (such as height, width, etc...)
@@ -82,7 +75,8 @@ void QtImageReader::Open()
ResvgRenderer renderer(path);
if (renderer.isValid()) {
- image = std::shared_ptr(new QImage(renderer.defaultSize(), QImage::Format_ARGB32_Premultiplied));
+ image = std::make_shared(
+ renderer.defaultSize(), QImage::Format_RGBA8888_Premultiplied);
image->fill(Qt::transparent);
QPainter p(image.get());
@@ -95,7 +89,7 @@ void QtImageReader::Open()
if (!loaded) {
// Attempt to open file using Qt's build in image processing capabilities
- image = std::shared_ptr(new QImage());
+ image = std::make_shared();
success = image->load(path);
}
@@ -104,9 +98,6 @@ void QtImageReader::Open()
throw InvalidFile("File could not be opened.", path.toStdString());
}
- // Convert to proper format
- image = std::shared_ptr(new QImage(image->convertToFormat(QImage::Format_RGBA8888)));
-
// Update image properties
info.has_audio = false;
info.has_video = true;
@@ -180,15 +171,16 @@ std::shared_ptr QtImageReader::GetFrame(int64_t requested_frame)
// without losing quality. NOTE: We cannot go smaller than the timeline itself, or the add_layer timeline
// method will scale it back to timeline size before scaling it smaller again. This needs to be fixed in
// the future.
- int max_width = Settings::Instance()->MAX_WIDTH;
- if (max_width <= 0)
- max_width = info.width;
- int max_height = Settings::Instance()->MAX_HEIGHT;
- if (max_height <= 0)
- max_height = info.height;
-
- Clip* parent = (Clip*) GetParentClip();
+ int max_width = info.width;
+ int max_height = info.height;
+
+ Clip* parent = (Clip*) ParentClip();
if (parent) {
+ if (parent->ParentTimeline()) {
+ // Set max width/height based on parent clip's timeline (if attached to a timeline)
+ max_width = parent->ParentTimeline()->preview_width;
+ max_height = parent->ParentTimeline()->preview_height;
+ }
if (parent->scale == SCALE_FIT || parent->scale == SCALE_STRETCH) {
// Best fit or Stretch scaling (based on max timeline size * scaling keyframes)
float max_scale_x = parent->scale_x.GetMaxPoint().co.Y;
@@ -238,7 +230,9 @@ std::shared_ptr QtImageReader::GetFrame(int64_t requested_frame)
svg_size.scale(max_width, max_height, Qt::KeepAspectRatio);
// Create empty QImage
- cached_image = std::shared_ptr(new QImage(QSize(svg_size.width(), svg_size.height()), QImage::Format_ARGB32_Premultiplied));
+ cached_image = std::make_shared(
+ QSize(svg_size.width(), svg_size.height()),
+ QImage::Format_RGBA8888_Premultiplied);
cached_image->fill(Qt::transparent);
// Render SVG into QImage
@@ -253,18 +247,20 @@ std::shared_ptr QtImageReader::GetFrame(int64_t requested_frame)
if (!rendered) {
// We need to resize the original image to a smaller image (for performance reasons)
// Only do this once, to prevent tons of unneeded scaling operations
- cached_image = std::shared_ptr(new QImage(image->scaled(max_width, max_height, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
+ cached_image = std::make_shared(image->scaled(
+ max_width, max_height, Qt::KeepAspectRatio, Qt::SmoothTransformation));
}
- cached_image = std::shared_ptr(new QImage(cached_image->convertToFormat(QImage::Format_RGBA8888)));
-
// Set max size (to later determine if max_size is changed)
max_size.setWidth(max_width);
max_size.setHeight(max_height);
}
// Create or get frame object
- std::shared_ptr image_frame(new Frame(requested_frame, cached_image->width(), cached_image->height(), "#000000", Frame::GetSamplesPerFrame(requested_frame, info.fps, info.sample_rate, info.channels), info.channels));
+ auto image_frame = std::make_shared(
+ requested_frame, cached_image->width(), cached_image->height(), "#000000",
+ Frame::GetSamplesPerFrame(requested_frame, info.fps, info.sample_rate, info.channels),
+ info.channels);
// Add Image data to frame
image_frame->AddImage(cached_image);
diff --git a/include/QtImageReader.h b/src/QtImageReader.h
similarity index 89%
rename from include/QtImageReader.h
rename to src/QtImageReader.h
index 3848065a1..5162b8f45 100644
--- a/include/QtImageReader.h
+++ b/src/QtImageReader.h
@@ -72,15 +72,15 @@ namespace openshot
QSize max_size; ///> Current max_size as calculated with Clip properties
public:
-
- /// Constructor for QtImageReader. This automatically opens the media file and loads
- /// frame 1, or it throws one of the following exceptions.
- QtImageReader(std::string path);
-
- /// Constructor for QtImageReader. This only opens the media file to inspect its properties
- /// if inspect_reader=true. When not inspecting the media file, it's much faster, and useful
- /// when you are inflating the object using JSON after instantiating it.
- QtImageReader(std::string path, bool inspect_reader);
+ /// @brief Constructor for QtImageReader.
+ ///
+ /// Opens the media file to inspect its properties and loads frame 1,
+ /// iff inspect_reader == true (the default). Pass a false value in
+ /// the optional parameter to defer this initial Open()/Close() cycle.
+ ///
+ /// When not inspecting the media file, it's much faster, and useful
+ /// when you are inflating the object using JSON after instantiation.
+ QtImageReader(std::string path, bool inspect_reader=true);
virtual ~QtImageReader();
diff --git a/src/QtPlayer.cpp b/src/QtPlayer.cpp
index e4d862d19..345bc24f0 100644
--- a/src/QtPlayer.cpp
+++ b/src/QtPlayer.cpp
@@ -29,12 +29,12 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/Clip.h"
-#include "../include/FFmpegReader.h"
-#include "../include/Timeline.h"
-#include "../include/QtPlayer.h"
-#include "../include/Qt/PlayerPrivate.h"
-#include "../include/Qt/VideoRenderer.h"
+#include "Clip.h"
+#include "FFmpegReader.h"
+#include "Timeline.h"
+#include "QtPlayer.h"
+#include "Qt/PlayerPrivate.h"
+#include "Qt/VideoRenderer.h"
namespace openshot
{
diff --git a/include/QtPlayer.h b/src/QtPlayer.h
similarity index 100%
rename from include/QtPlayer.h
rename to src/QtPlayer.h
diff --git a/src/QtTextReader.cpp b/src/QtTextReader.cpp
index d91d164e6..0a4410cb2 100644
--- a/src/QtTextReader.cpp
+++ b/src/QtTextReader.cpp
@@ -30,7 +30,7 @@
* along with OpenShot Library. If not, see .
*/
-#include "../include/QtTextReader.h"
+#include "QtTextReader.h"
#include
#include