From 296f46f4c00fc2a8ad46051438ed635e71c1a075 Mon Sep 17 00:00:00 2001 From: Kirill Makhonin Date: Wed, 9 Oct 2019 00:58:51 -0400 Subject: [PATCH 1/6] DynamicEffects: Add code for Linux with tests --- .gitignore | 1 + CMakeLists.txt | 1 + external-effects/CMakeLists.txt | 29 ++ external-effects/super-blur/CMakeLists.txt | 161 ++++++++++ external-effects/super-blur/SuperBlur.cpp | 348 +++++++++++++++++++++ external-effects/super-blur/SuperBlur.h | 130 ++++++++ include/EffectInfo.h | 17 + src/EffectInfo.cpp | 61 +++- tests/CMakeLists.txt | 5 +- tests/DynamicEffects_Tests.cpp | 93 ++++++ 10 files changed, 843 insertions(+), 3 deletions(-) create mode 100644 external-effects/CMakeLists.txt create mode 100644 external-effects/super-blur/CMakeLists.txt create mode 100644 external-effects/super-blur/SuperBlur.cpp create mode 100644 external-effects/super-blur/SuperBlur.h create mode 100644 tests/DynamicEffects_Tests.cpp diff --git a/.gitignore b/.gitignore index c02a2fb9c..41dbaab75 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ .project .cproject /.metadata/ +/plugins* *~ diff --git a/CMakeLists.txt b/CMakeLists.txt index 24d3e19df..48c5b389c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,7 @@ FILE(GLOB QT_HEADER_FILES "${QT_HEADER_DIR}/*.h") ############## PROCESS SUB-DIRECTORIES ############## add_subdirectory(src) add_subdirectory(tests) +add_subdirectory(external-effects) ################### DOCUMENTATION ################### # Find Doxygen (used for documentation) diff --git a/external-effects/CMakeLists.txt b/external-effects/CMakeLists.txt new file mode 100644 index 000000000..3ad34aeb2 --- /dev/null +++ b/external-effects/CMakeLists.txt @@ -0,0 +1,29 @@ +####################### CMakeLists.txt (libopenshot) ######################### +# @brief CMake build file for libopenshot (used to generate makefiles) +# @author Jonathan Thomas +# +# @section LICENSE +# +# Copyright (c) 2008-2019 OpenShot Studios, LLC +# . This file is part of +# OpenShot Library (libopenshot), an open-source project dedicated to +# delivering high quality video editing and animation solutions to the +# world. For more information visit . +# +# OpenShot Library (libopenshot) is free software: you can redistribute it +# and/or modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# OpenShot Library (libopenshot) is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with OpenShot Library. If not, see . +################################################################################ + +############## PROCESS SUB-DIRECTORIES ############## +add_subdirectory(super-blur) + diff --git a/external-effects/super-blur/CMakeLists.txt b/external-effects/super-blur/CMakeLists.txt new file mode 100644 index 000000000..f8bebac22 --- /dev/null +++ b/external-effects/super-blur/CMakeLists.txt @@ -0,0 +1,161 @@ +##################### tests/CMakeLists.txt (libopenshot) ###################### +# @brief CMake build file for libopenshot (used to generate makefiles) +# @author Jonathan Thomas +# +# @section LICENSE +# +# Copyright (c) 2008-2019 OpenShot Studios, LLC +# . This file is part of +# OpenShot Library (libopenshot), an open-source project dedicated to +# delivering high quality video editing and animation solutions to the +# world. For more information visit . +# +# OpenShot Library (libopenshot) is free software: you can redistribute it +# and/or modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# OpenShot Library (libopenshot) is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with OpenShot Library. If not, see . +################################################################################ + +# Pick up our include directories from the parent context +include_directories(${OPENSHOT_INCLUDE_DIRS}) + +################ IMAGE MAGICK ################## +# Set the Quantum Depth that ImageMagick was built with (default to 16 bits) +IF (MAGICKCORE_QUANTUM_DEPTH) + add_definitions( -DMAGICKCORE_QUANTUM_DEPTH=${MAGICKCORE_QUANTUM_DEPTH} ) +ELSE (MAGICKCORE_QUANTUM_DEPTH) + add_definitions( -DMAGICKCORE_QUANTUM_DEPTH=16 ) +ENDIF (MAGICKCORE_QUANTUM_DEPTH) +IF (MAGICKCORE_HDRI_ENABLE) + add_definitions( -DMAGICKCORE_HDRI_ENABLE=${MAGICKCORE_HDRI_ENABLE} ) +ELSE (MAGICKCORE_HDRI_ENABLE) + add_definitions( -DMAGICKCORE_HDRI_ENABLE=0 ) +ENDIF (MAGICKCORE_HDRI_ENABLE) +IF (OPENSHOT_IMAGEMAGICK_COMPATIBILITY) + add_definitions( -DOPENSHOT_IMAGEMAGICK_COMPATIBILITY=${OPENSHOT_IMAGEMAGICK_COMPATIBILITY} ) +ELSE (OPENSHOT_IMAGEMAGICK_COMPATIBILITY) + add_definitions( -DOPENSHOT_IMAGEMAGICK_COMPATIBILITY=0 ) +ENDIF (OPENSHOT_IMAGEMAGICK_COMPATIBILITY) + +# Find the ImageMagick++ library +FIND_PACKAGE(ImageMagick COMPONENTS Magick++ MagickWand MagickCore) +IF (ImageMagick_FOUND) + # Include ImageMagick++ headers (needed for compile) + include_directories(${ImageMagick_INCLUDE_DIRS}) + + # define a global var (used in the C++) + add_definitions( -DUSE_IMAGEMAGICK=1 ) + SET(CMAKE_SWIG_FLAGS "-DUSE_IMAGEMAGICK=1") + +ENDIF (ImageMagick_FOUND) + +################### FFMPEG ##################### +# Find FFmpeg libraries (used for video encoding / decoding) +FIND_PACKAGE(FFmpeg REQUIRED) + +foreach(ffmpeg_comp AVCODEC AVDEVICE AVFORMAT AVFILTER AVUTIL POSTPROC SWSCALE SWRESAMPLE AVRESAMPLE) + if(${ffmpeg_comp}_FOUND) + # Include FFmpeg headers (needed for compile) + list(APPEND FF_INCLUDES ${${ffmpeg_comp}_INCLUDE_DIRS}) + add_definitions(${${ffmpeg_comp}_DEFINITIONS}) + endif() +endforeach() +list(REMOVE_DUPLICATES FF_INCLUDES) +include_directories(${FF_INCLUDES}) + +################# LIBOPENSHOT-AUDIO ################### +# Find JUCE-based openshot Audio libraries +FIND_PACKAGE(OpenShotAudio 0.1.8 REQUIRED) + +# Include Juce headers (needed for compile) +include_directories(${LIBOPENSHOT_AUDIO_INCLUDE_DIRS}) + +################# QT5 ################### +# Find QT5 libraries +foreach(qt_lib Qt5Widgets Qt5Core Qt5Gui Qt5Multimedia Qt5MultimediaWidgets) + find_package(${qt_lib} REQUIRED) + # Header files + list(APPEND QT_INCLUDES ${${qt_lib}_INCLUDE_DIRS}) + # Compiler definitions + add_definitions(${${qt_lib}_DEFINITIONS}) + # Other CFLAGS + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${${qt_lib}_EXECUTABLE_COMPILE_FLAGS}") +endforeach() +list(REMOVE_DUPLICATES QT_INCLUDES) +include_directories(${QT_INCLUDES}) + +# Manually moc Qt files +qt5_wrap_cpp(MOC_FILES ${QT_HEADER_FILES}) + + +################# BLACKMAGIC DECKLINK ################### +IF (ENABLE_BLACKMAGIC) + # Find BlackMagic DeckLinkAPI libraries + FIND_PACKAGE(BlackMagic) + + IF (BLACKMAGIC_FOUND) + # Include Blackmagic headers (needed for compile) + include_directories(${BLACKMAGIC_INCLUDE_DIR}) + ENDIF (BLACKMAGIC_FOUND) +ENDIF (ENABLE_BLACKMAGIC) + +################### OPENMP ##################### +# Check for OpenMP (used for multi-core processing) +FIND_PACKAGE(OpenMP) + +if (OPENMP_FOUND) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS} ") +endif(OPENMP_FOUND) + +################### ZEROMQ ##################### +# Find ZeroMQ library (used for socket communication & logging) +FIND_PACKAGE(ZMQ REQUIRED) + +# Include ZeroMQ headers (needed for compile) +include_directories(${ZMQ_INCLUDE_DIRS}) + +################### RESVG ##################### +# Find resvg library (used for rendering svg files) +FIND_PACKAGE(RESVG) + +# Include resvg headers (optional SVG library) +if (RESVG_FOUND) + include_directories(${RESVG_INCLUDE_DIRS}) +endif(RESVG_FOUND) + +################### JSONCPP ##################### +# Include jsoncpp headers (needed for JSON parsing) +if (USE_SYSTEM_JSONCPP) + find_package(JsonCpp REQUIRED) + include_directories(${JSONCPP_INCLUDE_DIRS}) +else() + include_directories("../../thirdparty/jsoncpp") +endif(USE_SYSTEM_JSONCPP) + +SET ( EFFECT_SOURCE_FILES + SuperBlur.cpp) + +IF (NOT DISABLE_EXTERNAL_EFFECTS) + # Create shared openshot library + add_library(libeffectsuperblur SHARED + ${EFFECT_SOURCE_FILES}) + + set(LIB_INSTALL_DIR libeffect${LIB_SUFFIX}) # determine correct lib folder + + add_custom_command( + TARGET libeffectsuperblur + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + $ + ${PROJECT_SOURCE_DIR}/plugins/$ + ) + +ENDIF (NOT DISABLE_EXTERNAL_EFFECTS) diff --git a/external-effects/super-blur/SuperBlur.cpp b/external-effects/super-blur/SuperBlur.cpp new file mode 100644 index 000000000..76051e64e --- /dev/null +++ b/external-effects/super-blur/SuperBlur.cpp @@ -0,0 +1,348 @@ +/** + * @file + * @brief Source file for Blur effect class + * @author Jonathan Thomas + * + * @ref License + */ + +/* LICENSE + * + * Copyright (c) 2008-2019 OpenShot Studios, LLC + * . This file is part of + * OpenShot Library (libopenshot), an open-source project dedicated to + * delivering high quality video editing and animation solutions to the + * world. For more information visit . + * + * OpenShot Library (libopenshot) is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * OpenShot Library (libopenshot) is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with OpenShot Library. If not, see . + */ + +#include "./SuperBlur.h" + +using namespace openshot; + +void * factory(){ + return (void *)new SuperBlur(); +} + +/// Blank constructor, useful when using Json to load the effect properties +SuperBlur::SuperBlur() : horizontal_radius(6.0), vertical_radius(6.0), sigma(3.0), iterations(3.0) { + // Init effect properties + init_effect_details(); +} + +// Default constructor +SuperBlur::SuperBlur(Keyframe new_horizontal_radius, Keyframe new_vertical_radius, Keyframe new_sigma, Keyframe new_iterations) : + horizontal_radius(new_horizontal_radius), vertical_radius(new_vertical_radius), + sigma(new_sigma), iterations(new_iterations) +{ + // Init effect properties + init_effect_details(); +} + +// Init effect settings +void SuperBlur::init_effect_details() +{ + /// Initialize the values of the EffectInfo struct. + InitEffectInfo(); + + /// Set the effect info + info.class_name = "SuperBlur"; + info.name = "SuperBlur"; + info.description = "Adjust the blur of the frame's image."; + info.has_audio = false; + info.has_video = true; +} + +// This method is required for all derived classes of EffectBase, and returns a +// modified openshot::Frame object +std::shared_ptr SuperBlur::GetFrame(std::shared_ptr frame, int64_t frame_number) +{ + // Get the frame's image + std::shared_ptr frame_image = frame->GetImage(); + + // Get the current blur radius + int horizontal_radius_value = horizontal_radius.GetValue(frame_number); + int vertical_radius_value = vertical_radius.GetValue(frame_number); + float sigma_value = sigma.GetValue(frame_number); + int iteration_value = iterations.GetInt(frame_number); + + + // Declare arrays for each color channel + unsigned char *red = new unsigned char[frame_image->width() * frame_image->height()](); + unsigned char *green = new unsigned char[frame_image->width() * frame_image->height()](); + unsigned char *blue = new unsigned char[frame_image->width() * frame_image->height()](); + unsigned char *alpha = new unsigned char[frame_image->width() * frame_image->height()](); + // Create empty target RGBA arrays (for the results of our blur) + unsigned char *blur_red = new unsigned char[frame_image->width() * frame_image->height()](); + unsigned char *blur_green = new unsigned char[frame_image->width() * frame_image->height()](); + unsigned char *blur_blue = new unsigned char[frame_image->width() * frame_image->height()](); + unsigned char *blur_alpha = new unsigned char[frame_image->width() * frame_image->height()](); + + // Loop through pixels and split RGBA channels into separate arrays + unsigned char *pixels = (unsigned char *) frame_image->bits(); + for (int pixel = 0, byte_index=0; pixel < frame_image->width() * frame_image->height(); pixel++, byte_index+=4) + { + // Get the RGBA values from each pixel + unsigned char R = pixels[byte_index]; + unsigned char G = pixels[byte_index + 1]; + unsigned char B = pixels[byte_index + 2]; + unsigned char A = pixels[byte_index + 3]; + + // Split channels into their own arrays + red[pixel] = R; + green[pixel] = G; + blue[pixel] = B; + alpha[pixel] = A; + } + + // Init target RGBA arrays + for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) blur_red[i] = red[i]; + for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) blur_green[i] = green[i]; + for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) blur_blue[i] = blue[i]; + for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) blur_alpha[i] = alpha[i]; + + // Loop through each iteration + for (int iteration = 0; iteration < iteration_value; iteration++) + { + // HORIZONTAL BLUR (if any) + if (horizontal_radius_value > 0.0) { + // Init boxes for computing blur + int *bxs = initBoxes(sigma_value, horizontal_radius_value); + + // Apply horizontal blur to target RGBA channels + boxBlurH(red, blur_red, frame_image->width(), frame_image->height(), horizontal_radius_value); + boxBlurH(green, blur_green, frame_image->width(), frame_image->height(), horizontal_radius_value); + boxBlurH(blue, blur_blue, frame_image->width(), frame_image->height(), horizontal_radius_value); + boxBlurH(alpha, blur_alpha, frame_image->width(), frame_image->height(), horizontal_radius_value); + + // Remove boxes + delete[] bxs; + + // Copy blur_ back to for vertical blur or next iteration + for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) red[i] = blur_red[i]; + for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) green[i] = blur_green[i]; + for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) blue[i] = blur_blue[i]; + for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) alpha[i] = blur_alpha[i]; + } + + // VERTICAL BLUR (if any) + if (vertical_radius_value > 0.0) { + // Init boxes for computing blur + int *bxs = initBoxes(sigma_value, vertical_radius_value); + + // Apply vertical blur to target RGBA channels + boxBlurT(red, blur_red, frame_image->width(), frame_image->height(), vertical_radius_value); + boxBlurT(green, blur_green, frame_image->width(), frame_image->height(), vertical_radius_value); + boxBlurT(blue, blur_blue, frame_image->width(), frame_image->height(), vertical_radius_value); + boxBlurT(alpha, blur_alpha, frame_image->width(), frame_image->height(), vertical_radius_value); + + // Remove boxes + delete[] bxs; + + // Copy blur_ back to for vertical blur or next iteration + for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) red[i] = blur_red[i]; + for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) green[i] = blur_green[i]; + for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) blue[i] = blur_blue[i]; + for (int i = 0; i < (frame_image->width() * frame_image->height()); i++) alpha[i] = blur_alpha[i]; + } + } + + // Copy RGBA channels back to original image + for (int pixel = 0, byte_index=0; pixel < frame_image->width() * frame_image->height(); pixel++, byte_index+=4) + { + // Get the RGB values from the pixel + unsigned char R = blur_red[pixel]; + unsigned char G = blur_green[pixel]; + unsigned char B = blur_blue[pixel]; + unsigned char A = blur_alpha[pixel]; + + // Split channels into their own arrays + pixels[byte_index] = R; + pixels[byte_index + 1] = G; + pixels[byte_index + 2] = B; + pixels[byte_index + 3] = A; + } + + // Delete channel arrays + delete[] red; + delete[] green; + delete[] blue; + delete[] alpha; + delete[] blur_red; + delete[] blur_green; + delete[] blur_blue; + delete[] blur_alpha; + + // return the modified frame + return frame; +} + +// Credit: http://blog.ivank.net/fastest-gaussian-blur.html (MIT License) +int* SuperBlur::initBoxes(float sigma, int n) // standard deviation, number of boxes +{ + float wIdeal = sqrt((12.0 * sigma * sigma / n) + 1.0); // Ideal averaging filter width + int wl = floor(wIdeal); + if (wl % 2 == 0) wl--; + int wu = wl + 2; + + float mIdeal = (12.0 * sigma * sigma - n * wl * wl - 4 * n * wl - 3 * n) / (-4.0 * wl - 4); + int m = round(mIdeal); + + int *sizes = new int[n](); + for (int i = 0; i < n; i++) sizes[i] = i < m ? wl : wu; + return sizes; +} + +// Credit: http://blog.ivank.net/fastest-gaussian-blur.html (MIT License) +void SuperBlur::boxBlurH(unsigned char *scl, unsigned char *tcl, int w, int h, int r) { + float iarr = 1.0 / (r + r + 1); + for (int i = 0; i < h; i++) { + int ti = i * w, li = ti, ri = ti + r; + int fv = scl[ti], lv = scl[ti + w - 1], val = (r + 1) * fv; + for (int j = 0; j < r; j++) val += scl[ti + j]; + for (int j = 0; j <= r; j++) { + val += scl[ri++] - fv; + tcl[ti++] = round(val * iarr); + } + for (int j = r + 1; j < w - r; j++) { + val += scl[ri++] - scl[li++]; + tcl[ti++] = round(val * iarr); + } + for (int j = w - r; j < w; j++) { + val += lv - scl[li++]; + tcl[ti++] = round(val * iarr); + } + } +} + +void SuperBlur::boxBlurT(unsigned char *scl, unsigned char *tcl, int w, int h, int r) { + float iarr = 1.0 / (r + r + 1); + for (int i = 0; i < w; i++) { + int ti = i, li = ti, ri = ti + r * w; + int fv = scl[ti], lv = scl[ti + w * (h - 1)], val = (r + 1) * fv; + for (int j = 0; j < r; j++) val += scl[ti + j * w]; + for (int j = 0; j <= r; j++) { + val += scl[ri] - fv; + tcl[ti] = round(val * iarr); + ri += w; + ti += w; + } + for (int j = r + 1; j < h - r; j++) { + val += scl[ri] - scl[li]; + tcl[ti] = round(val * iarr); + li += w; + ri += w; + ti += w; + } + for (int j = h - r; j < h; j++) { + val += lv - scl[li]; + tcl[ti] = round(val * iarr); + li += w; + ti += w; + } + } +} + +// Generate JSON string of this object +string SuperBlur::Json() { + + // Return formatted string + return JsonValue().toStyledString(); +} + +// Generate Json::JsonValue for this object +Json::Value SuperBlur::JsonValue() { + + // Create root json object + Json::Value root = EffectBase::JsonValue(); // get parent properties + root["type"] = info.class_name; + root["horizontal_radius"] = horizontal_radius.JsonValue(); + root["vertical_radius"] = vertical_radius.JsonValue(); + root["sigma"] = sigma.JsonValue(); + root["iterations"] = iterations.JsonValue(); + + // return JsonValue + return root; +} + +// Load JSON string into this object +void SuperBlur::SetJson(string value) { + + // Parse JSON string into JSON objects + Json::Value root; + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); + delete reader; + + if (!success) + // Raise exception + throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); + + try + { + // Set all values that match + SetJsonValue(root); + } + catch (const std::exception& e) + { + // Error parsing JSON (or missing keys) + throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); + } +} + +// Load Json::JsonValue into this object +void SuperBlur::SetJsonValue(Json::Value root) { + + // Set parent data + EffectBase::SetJsonValue(root); + + // Set data from Json (if key is found) + if (!root["horizontal_radius"].isNull()) + horizontal_radius.SetJsonValue(root["horizontal_radius"]); + if (!root["vertical_radius"].isNull()) + vertical_radius.SetJsonValue(root["vertical_radius"]); + if (!root["sigma"].isNull()) + sigma.SetJsonValue(root["sigma"]); + if (!root["iterations"].isNull()) + iterations.SetJsonValue(root["iterations"]); +} + +// Get all properties for a specific frame +string SuperBlur::PropertiesJSON(int64_t requested_frame) { + + // Generate JSON properties list + Json::Value root; + root["id"] = add_property_json("ID", 0.0, "string", Id(), NULL, -1, -1, true, requested_frame); + root["position"] = add_property_json("Position", Position(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame); + root["layer"] = add_property_json("Track", Layer(), "int", "", NULL, 0, 20, false, requested_frame); + root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame); + root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame); + root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 1000 * 60 * 30, true, requested_frame); + + // Keyframes + root["horizontal_radius"] = add_property_json("Horizontal Radius", horizontal_radius.GetValue(requested_frame), "float", "", &horizontal_radius, 0, 100, false, requested_frame); + root["vertical_radius"] = add_property_json("Vertical Radius", vertical_radius.GetValue(requested_frame), "float", "", &vertical_radius, 0, 100, false, requested_frame); + root["sigma"] = add_property_json("Sigma", sigma.GetValue(requested_frame), "float", "", &sigma, 0, 100, false, requested_frame); + root["iterations"] = add_property_json("Iterations", iterations.GetValue(requested_frame), "float", "", &iterations, 0, 100, false, requested_frame); + + // Return formatted string + return root.toStyledString(); +} + + diff --git a/external-effects/super-blur/SuperBlur.h b/external-effects/super-blur/SuperBlur.h new file mode 100644 index 000000000..6867b40c9 --- /dev/null +++ b/external-effects/super-blur/SuperBlur.h @@ -0,0 +1,130 @@ +/** + * @file + * @brief Header file for SuperBlur effect class + * @author Jonathan Thomas + * + * @ref License + */ + +/* LICENSE + * + * Copyright (c) 2008-2019 OpenShot Studios, LLC + * . This file is part of + * OpenShot Library (libopenshot), an open-source project dedicated to + * delivering high quality video editing and animation solutions to the + * world. For more information visit . + * + * OpenShot Library (libopenshot) is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * OpenShot Library (libopenshot) is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with OpenShot Library. If not, see . + */ + +#ifndef OPENSHOT_EXTERNAL_BLUR_EFFECT_H +#define OPENSHOT_EXTERNAL_BLUR_EFFECT_H + +#include "../../include/EffectBase.h" + +#include +#include +#include +#include +#include +#include +#include +#include "../../include/Color.h" +#include "../../include/Exceptions.h" +#include "../../include/Json.h" +#include "../../include/KeyFrame.h" +#include "../../include/ReaderBase.h" +#include "../../include/FFmpegReader.h" +#include "../../include/QtImageReader.h" +#include "../../include/ChunkReader.h" + +using namespace std; + +#ifdef __cplusplus +extern "C" { +#endif + +void * factory(); + +#ifdef __cplusplus +} +#endif + + +namespace openshot +{ + + /** + * @brief This class adjusts the blur of an image, and can be animated + * with openshot::Keyframe curves over time. + * + * Adjusting the blur of an image over time can create many different powerful effects. To achieve a + * box blur effect, use identical horizontal and vertical blur values. To achieve a Gaussian blur, + * use 3 iterations, a sigma of 3.0, and a radius between 3 and X (depending on how much blur you want). + */ + class SuperBlur : public EffectBase + { + private: + /// Init effect settings + void init_effect_details(); + + /// Internal blur methods (inspired and credited to http://blog.ivank.net/fastest-gaussian-blur.html) + int* initBoxes(float sigma, int n); + void boxBlurH(unsigned char *scl, unsigned char *tcl, int w, int h, int r); + void boxBlurT(unsigned char *scl, unsigned char *tcl, int w, int h, int r); + + + public: + Keyframe horizontal_radius; ///< Horizontal blur radius keyframe. The size of the horizontal blur operation in pixels. + Keyframe vertical_radius; ///< Vertical blur radius keyframe. The size of the vertical blur operation in pixels. + Keyframe sigma; ///< Sigma keyframe. The amount of spread in the blur operation. Should be larger than radius. + Keyframe iterations; ///< Iterations keyframe. The # of blur iterations per pixel. 3 iterations = Gaussian. + + /// Blank constructor, useful when using Json to load the effect properties + SuperBlur(); + + /// Default constructor, which takes 1 curve. The curve adjusts the blur radius + /// of a frame's image. + /// + /// @param new_horizontal_radius The curve to adjust the horizontal blur radius (between 0 and 100, rounded to int) + /// @param new_vertical_radius The curve to adjust the vertical blur radius (between 0 and 100, rounded to int) + /// @param new_sigma The curve to adjust the sigma amount (the size of the blur brush (between 0 and 100), float values accepted) + /// @param new_iterations The curve to adjust the # of iterations (between 1 and 100) + SuperBlur(Keyframe new_horizontal_radius, Keyframe new_vertical_radius, Keyframe new_sigma, Keyframe new_iterations); + + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + + /// Get and Set JSON methods + string Json(); ///< Generate JSON string of this object + void SetJson(string value); ///< Load JSON string into this object + Json::Value JsonValue(); ///< Generate Json::JsonValue for this object + void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object + + /// Get all properties for a specific frame (perfect for a UI to display the current state + /// of all properties at any time) + string PropertiesJSON(int64_t requested_frame); + }; + +} + +#endif diff --git a/include/EffectInfo.h b/include/EffectInfo.h index 7806f096b..8d6ecf361 100644 --- a/include/EffectInfo.h +++ b/include/EffectInfo.h @@ -32,6 +32,14 @@ #define OPENSHOT_EFFECT_INFO_H #include "Effects.h" +#include +#include +#include + + +#if defined(__linux__) +#include +#endif using namespace std; @@ -51,10 +59,19 @@ namespace openshot // Create an instance of an effect (factory style) EffectBase* CreateEffect(string effect_type); + // Load effect built in shared library (factory style) + EffectBase* LoadEffect(string location); + + // Unload all effect loaded dynamically + void UnloadDynamicEffects(); + /// JSON methods static string Json(); ///< Generate JSON string of this object static Json::Value JsonValue(); ///< Generate Json::JsonValue for this object + private: + pthread_mutex_t m_mutex; + }; } diff --git a/src/EffectInfo.cpp b/src/EffectInfo.cpp index 0b9c360dc..5de17d4a0 100644 --- a/src/EffectInfo.cpp +++ b/src/EffectInfo.cpp @@ -30,9 +30,9 @@ #include "../include/EffectInfo.h" - using namespace openshot; - +static map m_loadedDynamicEffects; +static vector m_loadedDynamicHandles; // Generate JSON string of this object string EffectInfo::Json() { @@ -43,6 +43,11 @@ string EffectInfo::Json() { // Create a new effect instance EffectBase* EffectInfo::CreateEffect(string effect_type) { + // Try to find dynamically loaded effect + auto effect_factory = m_loadedDynamicEffects.find(effect_type); + if (effect_factory != m_loadedDynamicEffects.end()) + return effect_factory->second(); + // Init the matching effect object if (effect_type == "Bars") return new Bars(); @@ -88,6 +93,52 @@ EffectBase* EffectInfo::CreateEffect(string effect_type) { return NULL; } +#if defined(__linux__) +EffectBase* EffectInfo::LoadEffect(string location){ + pthread_mutex_lock(&m_mutex); + + void * file = dlopen(location.c_str(), RTLD_NOW); + if (file == nullptr){ + pthread_mutex_unlock(&m_mutex); + return nullptr; + } + void * factory_ptr = dlsym(file, "factory"); + if (factory_ptr == nullptr){ + pthread_mutex_unlock(&m_mutex); + return nullptr; + } + + EffectBase * (*factory)(); + factory = (EffectBase* (*)()) factory_ptr; + + EffectBase* instance = factory(); + m_loadedDynamicEffects.insert(make_pair(instance->info.name, factory)); + m_loadedDynamicHandles.insert(m_loadedDynamicHandles.end(), file); + + pthread_mutex_unlock(&m_mutex); + return instance; +} + +void EffectInfo::UnloadDynamicEffects(){ + pthread_mutex_lock(&m_mutex); + for (auto & handle : m_loadedDynamicHandles){ + dlclose(handle); + } + + m_loadedDynamicEffects.clear(); + m_loadedDynamicHandles.clear(); + pthread_mutex_unlock(&m_mutex); +} +#else +EffectBase* EffectInfo::LoadEffect(string location){ + return NULL; +} + +void EffectInfo::UnloadDynamicEffects(){ + +} +#endif + // Generate Json::JsonValue for this object Json::Value EffectInfo::JsonValue() { @@ -110,6 +161,12 @@ Json::Value EffectInfo::JsonValue() { root.append(Shift().JsonInfo()); root.append(Wave().JsonInfo()); + for (auto & effect : m_loadedDynamicEffects){ + auto instance = effect.second(); + root.append(instance->JsonInfo()); + delete instance; + } + // return JsonValue return root; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ab44fa319..c0f8300e5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -28,6 +28,8 @@ include_directories(${OPENSHOT_INCLUDE_DIRS}) SET(TEST_MEDIA_PATH "${PROJECT_SOURCE_DIR}/src/examples/") +SET(TEST_PLUGINS_PATH "${PROJECT_SOURCE_DIR}/plugins/") +add_definitions( -DTEST_PLUGINS_PATH="${TEST_PLUGINS_PATH}" ) ################ WINDOWS ################## # Set some compiler options for Windows @@ -167,6 +169,7 @@ IF (NOT DISABLE_TESTS) Clip_Tests.cpp Color_Tests.cpp Coordinate_Tests.cpp + DynamicEffects_Tests.cpp ReaderBase_Tests.cpp ImageWriter_Tests.cpp FFmpegReader_Tests.cpp @@ -185,7 +188,7 @@ IF (NOT DISABLE_TESTS) ${OPENSHOT_TEST_FILES} ) # Link libraries to the new executable - target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY}) + target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY} libeffectsuperblur) #################### MAKE TEST ###################### # Hook up the 'make os_test' target to the 'openshot-test' executable diff --git a/tests/DynamicEffects_Tests.cpp b/tests/DynamicEffects_Tests.cpp new file mode 100644 index 000000000..1d7e32981 --- /dev/null +++ b/tests/DynamicEffects_Tests.cpp @@ -0,0 +1,93 @@ +/** + * @file + * @brief Unit tests for openshot::Timeline + * @author Jonathan Thomas + * + * @ref License + */ + +/* LICENSE + * + * Copyright (c) 2008-2019 OpenShot Studios, LLC + * . This file is part of + * OpenShot Library (libopenshot), an open-source project dedicated to + * delivering high quality video editing and animation solutions to the + * world. For more information visit . + * + * OpenShot Library (libopenshot) is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * OpenShot Library (libopenshot) is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with OpenShot Library. If not, see . + */ + +#include "UnitTest++.h" +#include "../include/OpenShot.h" + +#ifdef TEST_PLUGINS_PATH +#define TEST_PLUGINS_PATH_LIB TEST_PLUGINS_PATH "liblibeffectsuperblur.so" +#else +#define TEST_PLUGINS_PATH_LIB "liblibeffectsuperblur.so" +#endif + +using namespace std; +using namespace openshot; + + +TEST(DynamicEffect_Loader) +{ + auto effect_info = EffectInfo(); + effect_info.UnloadDynamicEffects(); + + auto effect = effect_info.LoadEffect(TEST_PLUGINS_PATH_LIB); + + CHECK(effect != nullptr); + + delete effect; +} + + +TEST(DynamicEffect_DoubleLoader) +{ + auto effect_info = EffectInfo(); + effect_info.UnloadDynamicEffects(); + + auto effect = effect_info.LoadEffect(TEST_PLUGINS_PATH_LIB); + + CHECK(effect != nullptr); + + delete effect; + + effect = effect_info.LoadEffect(TEST_PLUGINS_PATH_LIB); + + CHECK(effect != nullptr); + + delete effect; +} + + +TEST(DynamicEffect_ReachByName) +{ + auto effect_info = EffectInfo(); + effect_info.UnloadDynamicEffects(); + + auto effect = effect_info.LoadEffect(TEST_PLUGINS_PATH_LIB); + + CHECK(effect != nullptr); + + delete effect; + + effect = effect_info.CreateEffect("SuperBlur"); + + CHECK(effect != nullptr); + + delete effect; +} + From 54c9af79e161aa327deabd060844f2e025bee2b8 Mon Sep 17 00:00:00 2001 From: Kirill Makhonin Date: Sat, 12 Oct 2019 01:37:13 -0400 Subject: [PATCH 2/6] Fix all comments --- .gitignore | 1 - CMakeLists.txt | 5 +++- external-effects/super-blur/CMakeLists.txt | 21 ++++----------- external-effects/super-blur/SuperBlur.cpp | 2 +- external-effects/super-blur/SuperBlur.h | 2 +- include/EffectBase.h | 2 ++ include/EffectInfo.h | 9 +++---- src/EffectInfo.cpp | 31 +++++++++++++--------- tests/CMakeLists.txt | 13 ++++++--- tests/DynamicEffects_Tests.cpp | 20 +++++++------- 10 files changed, 53 insertions(+), 53 deletions(-) diff --git a/.gitignore b/.gitignore index 41dbaab75..c02a2fb9c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,4 @@ .project .cproject /.metadata/ -/plugins* *~ diff --git a/CMakeLists.txt b/CMakeLists.txt index 48c5b389c..a7b8ebea2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,7 +95,10 @@ FILE(GLOB QT_HEADER_FILES "${QT_HEADER_DIR}/*.h") ############## PROCESS SUB-DIRECTORIES ############## add_subdirectory(src) add_subdirectory(tests) -add_subdirectory(external-effects) + +IF (NOT DISABLE_EXTERNAL_EFFECTS) + add_subdirectory(external-effects) +ENDIF (NOT DISABLE_EXTERNAL_EFFECTS) ################### DOCUMENTATION ################### # Find Doxygen (used for documentation) diff --git a/external-effects/super-blur/CMakeLists.txt b/external-effects/super-blur/CMakeLists.txt index f8bebac22..b58052346 100644 --- a/external-effects/super-blur/CMakeLists.txt +++ b/external-effects/super-blur/CMakeLists.txt @@ -143,19 +143,8 @@ endif(USE_SYSTEM_JSONCPP) SET ( EFFECT_SOURCE_FILES SuperBlur.cpp) -IF (NOT DISABLE_EXTERNAL_EFFECTS) - # Create shared openshot library - add_library(libeffectsuperblur SHARED - ${EFFECT_SOURCE_FILES}) - - set(LIB_INSTALL_DIR libeffect${LIB_SUFFIX}) # determine correct lib folder - - add_custom_command( - TARGET libeffectsuperblur - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - $ - ${PROJECT_SOURCE_DIR}/plugins/$ - ) - -ENDIF (NOT DISABLE_EXTERNAL_EFFECTS) +# Create shared openshot library +add_library(effectsuperblur SHARED + ${EFFECT_SOURCE_FILES}) + +set(LIB_INSTALL_DIR libeffect${LIB_SUFFIX}) # determine correct lib folder diff --git a/external-effects/super-blur/SuperBlur.cpp b/external-effects/super-blur/SuperBlur.cpp index 76051e64e..d6bf68c8d 100644 --- a/external-effects/super-blur/SuperBlur.cpp +++ b/external-effects/super-blur/SuperBlur.cpp @@ -32,7 +32,7 @@ using namespace openshot; -void * factory(){ +void * factory(uint16_t openshot_version){ return (void *)new SuperBlur(); } diff --git a/external-effects/super-blur/SuperBlur.h b/external-effects/super-blur/SuperBlur.h index 6867b40c9..445f9c7ed 100644 --- a/external-effects/super-blur/SuperBlur.h +++ b/external-effects/super-blur/SuperBlur.h @@ -55,7 +55,7 @@ using namespace std; extern "C" { #endif -void * factory(); +void * factory(uint16_t); #ifdef __cplusplus } diff --git a/include/EffectBase.h b/include/EffectBase.h index a16b6620d..31c73c314 100644 --- a/include/EffectBase.h +++ b/include/EffectBase.h @@ -31,6 +31,8 @@ #ifndef OPENSHOT_EFFECT_BASE_H #define OPENSHOT_EFFECT_BASE_H +#define OPENSHOT_PLUGIN_API_VERSION 0x0001 + #include #include #include diff --git a/include/EffectInfo.h b/include/EffectInfo.h index 8d6ecf361..fb5416438 100644 --- a/include/EffectInfo.h +++ b/include/EffectInfo.h @@ -41,9 +41,6 @@ #include #endif - -using namespace std; - namespace openshot { @@ -57,16 +54,16 @@ namespace openshot { public: // Create an instance of an effect (factory style) - EffectBase* CreateEffect(string effect_type); + EffectBase* CreateEffect(std::string effect_type); // Load effect built in shared library (factory style) - EffectBase* LoadEffect(string location); + EffectBase* LoadEffect(std::string location); // Unload all effect loaded dynamically void UnloadDynamicEffects(); /// JSON methods - static string Json(); ///< Generate JSON string of this object + static std::string Json(); ///< Generate JSON string of this object static Json::Value JsonValue(); ///< Generate Json::JsonValue for this object private: diff --git a/src/EffectInfo.cpp b/src/EffectInfo.cpp index 5de17d4a0..88d9fddbb 100644 --- a/src/EffectInfo.cpp +++ b/src/EffectInfo.cpp @@ -31,22 +31,22 @@ #include "../include/EffectInfo.h" using namespace openshot; -static map m_loadedDynamicEffects; +static map m_loadedDynamicEffects; static vector m_loadedDynamicHandles; // Generate JSON string of this object -string EffectInfo::Json() { +std::string EffectInfo::Json() { // Return formatted string return JsonValue().toStyledString(); } // Create a new effect instance -EffectBase* EffectInfo::CreateEffect(string effect_type) { +EffectBase* EffectInfo::CreateEffect(std::string effect_type) { // Try to find dynamically loaded effect auto effect_factory = m_loadedDynamicEffects.find(effect_type); if (effect_factory != m_loadedDynamicEffects.end()) - return effect_factory->second(); + return effect_factory->second(OPENSHOT_PLUGIN_API_VERSION); // Init the matching effect object if (effect_type == "Bars") @@ -94,24 +94,31 @@ EffectBase* EffectInfo::CreateEffect(string effect_type) { } #if defined(__linux__) -EffectBase* EffectInfo::LoadEffect(string location){ +EffectBase* EffectInfo::LoadEffect(std::string location){ pthread_mutex_lock(&m_mutex); void * file = dlopen(location.c_str(), RTLD_NOW); if (file == nullptr){ pthread_mutex_unlock(&m_mutex); - return nullptr; + throw InvalidFile("Can not open file", location.c_str()); } void * factory_ptr = dlsym(file, "factory"); + if (factory_ptr == nullptr){ pthread_mutex_unlock(&m_mutex); - return nullptr; + throw InvalidFile("Can not find requested plugin API in file", location.c_str()); } - EffectBase * (*factory)(); - factory = (EffectBase* (*)()) factory_ptr; + EffectBase * (*factory)(uint16_t); + factory = (EffectBase* (*)(uint16_t)) factory_ptr; + + EffectBase* instance = factory(OPENSHOT_PLUGIN_API_VERSION); + + if (instance == nullptr){ + pthread_mutex_unlock(&m_mutex); + throw InvalidFile("Plugin does not support current version of openshot", location.c_str()); + } - EffectBase* instance = factory(); m_loadedDynamicEffects.insert(make_pair(instance->info.name, factory)); m_loadedDynamicHandles.insert(m_loadedDynamicHandles.end(), file); @@ -130,7 +137,7 @@ void EffectInfo::UnloadDynamicEffects(){ pthread_mutex_unlock(&m_mutex); } #else -EffectBase* EffectInfo::LoadEffect(string location){ +EffectBase* EffectInfo::LoadEffect(std::string location){ return NULL; } @@ -162,7 +169,7 @@ Json::Value EffectInfo::JsonValue() { root.append(Wave().JsonInfo()); for (auto & effect : m_loadedDynamicEffects){ - auto instance = effect.second(); + auto instance = effect.second(OPENSHOT_PLUGIN_API_VERSION); root.append(instance->JsonInfo()); delete instance; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c0f8300e5..a50f4083c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -28,8 +28,6 @@ include_directories(${OPENSHOT_INCLUDE_DIRS}) SET(TEST_MEDIA_PATH "${PROJECT_SOURCE_DIR}/src/examples/") -SET(TEST_PLUGINS_PATH "${PROJECT_SOURCE_DIR}/plugins/") -add_definitions( -DTEST_PLUGINS_PATH="${TEST_PLUGINS_PATH}" ) ################ WINDOWS ################## # Set some compiler options for Windows @@ -187,8 +185,15 @@ IF (NOT DISABLE_TESTS) tests.cpp ${OPENSHOT_TEST_FILES} ) - # Link libraries to the new executable - target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY} libeffectsuperblur) + IF (NOT DISABLE_EXTERNAL_EFFECTS) + # Link libraries to the new executable + target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY} effectsuperblur) + add_definitions(-DTEST_PLUGIN="${PROJECT_BINARY_DIR}/external-effects/super-blur/libeffectsuperblur.so" + -DTEST_PLUGIN_NAME="SuperBlur") + ELSE() + # Link libraries to the new executable + target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY}) + ENDIF(NOT DISABLE_EXTERNAL_EFFECTS) #################### MAKE TEST ###################### # Hook up the 'make os_test' target to the 'openshot-test' executable diff --git a/tests/DynamicEffects_Tests.cpp b/tests/DynamicEffects_Tests.cpp index 1d7e32981..79895c343 100644 --- a/tests/DynamicEffects_Tests.cpp +++ b/tests/DynamicEffects_Tests.cpp @@ -31,13 +31,9 @@ #include "UnitTest++.h" #include "../include/OpenShot.h" -#ifdef TEST_PLUGINS_PATH -#define TEST_PLUGINS_PATH_LIB TEST_PLUGINS_PATH "liblibeffectsuperblur.so" -#else -#define TEST_PLUGINS_PATH_LIB "liblibeffectsuperblur.so" -#endif +#ifdef TEST_PLUGIN +#if defined(__linux__) -using namespace std; using namespace openshot; @@ -46,7 +42,7 @@ TEST(DynamicEffect_Loader) auto effect_info = EffectInfo(); effect_info.UnloadDynamicEffects(); - auto effect = effect_info.LoadEffect(TEST_PLUGINS_PATH_LIB); + auto effect = effect_info.LoadEffect(TEST_PLUGIN); CHECK(effect != nullptr); @@ -59,13 +55,13 @@ TEST(DynamicEffect_DoubleLoader) auto effect_info = EffectInfo(); effect_info.UnloadDynamicEffects(); - auto effect = effect_info.LoadEffect(TEST_PLUGINS_PATH_LIB); + auto effect = effect_info.LoadEffect(TEST_PLUGIN); CHECK(effect != nullptr); delete effect; - effect = effect_info.LoadEffect(TEST_PLUGINS_PATH_LIB); + effect = effect_info.LoadEffect(TEST_PLUGIN); CHECK(effect != nullptr); @@ -78,16 +74,18 @@ TEST(DynamicEffect_ReachByName) auto effect_info = EffectInfo(); effect_info.UnloadDynamicEffects(); - auto effect = effect_info.LoadEffect(TEST_PLUGINS_PATH_LIB); + auto effect = effect_info.LoadEffect(TEST_PLUGIN); CHECK(effect != nullptr); delete effect; - effect = effect_info.CreateEffect("SuperBlur"); + effect = effect_info.CreateEffect(TEST_PLUGIN_NAME); CHECK(effect != nullptr); delete effect; } +#endif +#endif \ No newline at end of file From 10f05a455ef7852c7dfef1b500219d75b32f4fdb Mon Sep 17 00:00:00 2001 From: Kirill Makhonin Date: Sat, 12 Oct 2019 01:43:54 -0400 Subject: [PATCH 3/6] Fix naming, remove using construction --- external-effects/super-blur/CMakeLists.txt | 2 +- external-effects/super-blur/SuperBlur.cpp | 8 ++++---- external-effects/super-blur/SuperBlur.h | 7 +++---- tests/CMakeLists.txt | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/external-effects/super-blur/CMakeLists.txt b/external-effects/super-blur/CMakeLists.txt index b58052346..d95edd88d 100644 --- a/external-effects/super-blur/CMakeLists.txt +++ b/external-effects/super-blur/CMakeLists.txt @@ -144,7 +144,7 @@ SET ( EFFECT_SOURCE_FILES SuperBlur.cpp) # Create shared openshot library -add_library(effectsuperblur SHARED +add_library(effect-superblur SHARED ${EFFECT_SOURCE_FILES}) set(LIB_INSTALL_DIR libeffect${LIB_SUFFIX}) # determine correct lib folder diff --git a/external-effects/super-blur/SuperBlur.cpp b/external-effects/super-blur/SuperBlur.cpp index d6bf68c8d..f473cd41d 100644 --- a/external-effects/super-blur/SuperBlur.cpp +++ b/external-effects/super-blur/SuperBlur.cpp @@ -256,7 +256,7 @@ void SuperBlur::boxBlurT(unsigned char *scl, unsigned char *tcl, int w, int h, i } // Generate JSON string of this object -string SuperBlur::Json() { +std::string SuperBlur::Json() { // Return formatted string return JsonValue().toStyledString(); @@ -278,14 +278,14 @@ Json::Value SuperBlur::JsonValue() { } // Load JSON string into this object -void SuperBlur::SetJson(string value) { +void SuperBlur::SetJson(std::string value) { // Parse JSON string into JSON objects Json::Value root; Json::CharReaderBuilder rbuilder; Json::CharReader* reader(rbuilder.newCharReader()); - string errors; + std::string errors; bool success = reader->parse( value.c_str(), value.c_str() + value.size(), &root, &errors ); delete reader; @@ -324,7 +324,7 @@ void SuperBlur::SetJsonValue(Json::Value root) { } // Get all properties for a specific frame -string SuperBlur::PropertiesJSON(int64_t requested_frame) { +std::string SuperBlur::PropertiesJSON(int64_t requested_frame) { // Generate JSON properties list Json::Value root; diff --git a/external-effects/super-blur/SuperBlur.h b/external-effects/super-blur/SuperBlur.h index 445f9c7ed..1c618cd83 100644 --- a/external-effects/super-blur/SuperBlur.h +++ b/external-effects/super-blur/SuperBlur.h @@ -49,7 +49,6 @@ #include "../../include/QtImageReader.h" #include "../../include/ChunkReader.h" -using namespace std; #ifdef __cplusplus extern "C" { @@ -115,14 +114,14 @@ namespace openshot std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); /// Get and Set JSON methods - string Json(); ///< Generate JSON string of this object - void SetJson(string value); ///< Load JSON string into this object + std::string Json(); ///< Generate JSON string of this object + void SetJson(std::string value); ///< Load JSON string into this object Json::Value JsonValue(); ///< Generate Json::JsonValue for this object void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) - string PropertiesJSON(int64_t requested_frame); + std::string PropertiesJSON(int64_t requested_frame); }; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a50f4083c..8c2ecbcb8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -187,8 +187,8 @@ IF (NOT DISABLE_TESTS) IF (NOT DISABLE_EXTERNAL_EFFECTS) # Link libraries to the new executable - target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY} effectsuperblur) - add_definitions(-DTEST_PLUGIN="${PROJECT_BINARY_DIR}/external-effects/super-blur/libeffectsuperblur.so" + target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY} effect-superblur) + add_definitions(-DTEST_PLUGIN="${PROJECT_BINARY_DIR}/external-effects/super-blur/libeffect-superblur.so" -DTEST_PLUGIN_NAME="SuperBlur") ELSE() # Link libraries to the new executable From 85b551aa6c48e47e648f83b7d1233360e39619c1 Mon Sep 17 00:00:00 2001 From: Kirill Makhonin Date: Sun, 13 Oct 2019 10:53:25 -0400 Subject: [PATCH 4/6] Add dlclose calling --- src/EffectInfo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/EffectInfo.cpp b/src/EffectInfo.cpp index 88d9fddbb..cebc07d9d 100644 --- a/src/EffectInfo.cpp +++ b/src/EffectInfo.cpp @@ -106,6 +106,7 @@ EffectBase* EffectInfo::LoadEffect(std::string location){ if (factory_ptr == nullptr){ pthread_mutex_unlock(&m_mutex); + dlclose(file); throw InvalidFile("Can not find requested plugin API in file", location.c_str()); } @@ -116,6 +117,7 @@ EffectBase* EffectInfo::LoadEffect(std::string location){ if (instance == nullptr){ pthread_mutex_unlock(&m_mutex); + dlclose(file); throw InvalidFile("Plugin does not support current version of openshot", location.c_str()); } From 2fda2ebf1764864950360fcb27fe8d6cb9e63884 Mon Sep 17 00:00:00 2001 From: Kirill Makhonin Date: Sun, 13 Oct 2019 11:04:44 -0400 Subject: [PATCH 5/6] Force cast to string --- src/EffectInfo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/EffectInfo.cpp b/src/EffectInfo.cpp index cebc07d9d..536d83428 100644 --- a/src/EffectInfo.cpp +++ b/src/EffectInfo.cpp @@ -121,7 +121,7 @@ EffectBase* EffectInfo::LoadEffect(std::string location){ throw InvalidFile("Plugin does not support current version of openshot", location.c_str()); } - m_loadedDynamicEffects.insert(make_pair(instance->info.name, factory)); + m_loadedDynamicEffects.insert(make_pair(std::string(instance->info.name), factory)); m_loadedDynamicHandles.insert(m_loadedDynamicHandles.end(), file); pthread_mutex_unlock(&m_mutex); @@ -130,6 +130,7 @@ EffectBase* EffectInfo::LoadEffect(std::string location){ void EffectInfo::UnloadDynamicEffects(){ pthread_mutex_lock(&m_mutex); + for (auto & handle : m_loadedDynamicHandles){ dlclose(handle); } From 553cf55a580e4ee7280caa99f9e6d748cfc67e51 Mon Sep 17 00:00:00 2001 From: Kirill Makhonin Date: Sun, 13 Oct 2019 17:36:11 -0400 Subject: [PATCH 6/6] Ignore effects is not used --- tests/CMakeLists.txt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8c2ecbcb8..b2934a6c0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -167,7 +167,6 @@ IF (NOT DISABLE_TESTS) Clip_Tests.cpp Color_Tests.cpp Coordinate_Tests.cpp - DynamicEffects_Tests.cpp ReaderBase_Tests.cpp ImageWriter_Tests.cpp FFmpegReader_Tests.cpp @@ -179,20 +178,25 @@ IF (NOT DISABLE_TESTS) Settings_Tests.cpp Timeline_Tests.cpp ) + + IF (NOT DISABLE_EXTERNAL_EFFECTS) + list(APPEND OPENSHOT_TEST_FILES + DynamicEffects_Tests.cpp) + ENDIF(NOT DISABLE_EXTERNAL_EFFECTS) + ################ TESTER EXECUTABLE ################# # Create unit test executable (openshot-test) add_executable(openshot-test tests.cpp ${OPENSHOT_TEST_FILES} ) + + target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY}) + IF (NOT DISABLE_EXTERNAL_EFFECTS) - # Link libraries to the new executable - target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY} effect-superblur) add_definitions(-DTEST_PLUGIN="${PROJECT_BINARY_DIR}/external-effects/super-blur/libeffect-superblur.so" -DTEST_PLUGIN_NAME="SuperBlur") - ELSE() - # Link libraries to the new executable - target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY}) + add_dependencies(openshot-test effect-superblur) ENDIF(NOT DISABLE_EXTERNAL_EFFECTS) #################### MAKE TEST ######################