diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index e2c4863a..6e88fc7b 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -44,6 +44,7 @@ #include "CacheMemory.h" #include "Exceptions.h" #include "OpenMPUtilities.h" +#include "Settings.h" using namespace std; @@ -105,7 +106,6 @@ namespace openshot bool check_interlace; bool check_fps; bool has_missing_frames; - bool use_omp_threads; CacheMemory working_cache; CacheMemory missing_frames; diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index 7eefacb7..e219f72c 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -51,6 +51,7 @@ #include "Exceptions.h" #include "OpenMPUtilities.h" #include "ZmqLogger.h" +#include "Settings.h" using namespace std; diff --git a/include/OpenMPUtilities.h b/include/OpenMPUtilities.h index 1525730d..65047c31 100644 --- a/include/OpenMPUtilities.h +++ b/include/OpenMPUtilities.h @@ -37,20 +37,6 @@ #define OPEN_MP_NUM_PROCESSORS (min(omp_get_num_procs(), 6)) #define FF_NUM_PROCESSORS (min(omp_get_num_procs(), 12)) -using namespace std; -namespace openshot { - - // Check if OS2_OMP_THREADS environment variable is present, and return - // if multiple threads should be used with OMP - static bool IsOMPEnabled() { - char* OS2_OMP_THREADS = getenv("OS2_OMP_THREADS"); - if (OS2_OMP_THREADS != NULL && strcmp(OS2_OMP_THREADS, "0") == 0) - return false; - else - return true; - } - -} #endif diff --git a/include/OpenShot.h b/include/OpenShot.h index e4b60f3e..207f4b42 100644 --- a/include/OpenShot.h +++ b/include/OpenShot.h @@ -134,5 +134,6 @@ #include "Profiles.h" #include "QtImageReader.h" #include "Timeline.h" +#include "Settings.h" #endif diff --git a/include/Settings.h b/include/Settings.h new file mode 100644 index 00000000..6a7940eb --- /dev/null +++ b/include/Settings.h @@ -0,0 +1,97 @@ +/** + * @file + * @brief Header file for global Settings class + * @author Jonathan Thomas + * + * @section LICENSE + * + * Copyright (c) 2008-2014 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_SETTINGS_H +#define OPENSHOT_SETTINGS_H + + +#include "JuceLibraryCode/JuceHeader.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace std; + +namespace openshot { + + /** + * @brief This class is contains settings used by libopenshot (and can be safely toggled at any point) + * + * Settings class is used primarily to toggle scale settings between preview and rendering, and adjust + * other runtime related settings. + */ + class Settings { + private: + + /// Default constructor + Settings(){}; // Don't allow user to create an instance of this singleton + +#if __GNUC__ >=7 + /// Default copy method + Settings(Settings const&) = delete; // Don't allow the user to assign this instance + + /// Default assignment operator + Settings & operator=(Settings const&) = delete; // Don't allow the user to assign this instance +#else + /// Default copy method + Settings(Settings const&) {}; // Don't allow the user to assign this instance + + /// Default assignment operator + Settings & operator=(Settings const&); // Don't allow the user to assign this instance +#endif + + /// Private variable to keep track of singleton instance + static Settings * m_pInstance; + + public: + /// Use video card for faster video decoding (if supported) + bool HARDWARE_DECODE = false; + + /// Use video card for faster video encoding (if supported) + bool HARDWARE_ENCODE = false; + + /// Scale mode used in FFmpeg decoding and encoding (used as an optimization for faster previews) + bool HIGH_QUALITY_SCALING = false; + + /// Wait for OpenMP task to finish before continuing (used to limit threads on slower systems) + bool WAIT_FOR_VIDEO_PROCESSING_TASK = false; + + /// Create or get an instance of this logger singleton (invoke the class with this method) + static Settings * Instance(); + }; + +} + +#endif diff --git a/include/ZmqLogger.h b/include/ZmqLogger.h index e825ed0e..62773e68 100644 --- a/include/ZmqLogger.h +++ b/include/ZmqLogger.h @@ -47,11 +47,10 @@ using namespace std; namespace openshot { /** - * @brief This abstract class is the base class, used by all readers in libopenshot. + * @brief This class is used for logging and sending those logs over a ZemoMQ socket to a listener * - * Readers are types of classes that read video, audio, and image files, and - * return openshot::Frame objects. The only requirements for a 'reader', are to - * derive from this base class, implement the GetFrame method, and call the InitFileInfo() method. + * OpenShot desktop editor listens to this port, to receive libopenshot debug output. It both logs to + * a file and sends the stdout over a socket. */ class ZmqLogger { private: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d71067a3..7752df15 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -244,6 +244,7 @@ SET ( OPENSHOT_SOURCE_FILES Profiles.cpp QtImageReader.cpp QtPlayer.cpp + Settings.cpp Timeline.cpp # Qt Video Player diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index dc79be8f..434b1ae4 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -38,7 +38,7 @@ FFmpegReader::FFmpegReader(string path) 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), use_omp_threads(true) { + packet(NULL) { // Initialize FFMpeg, and register all formats and codecs AV_REGISTER_ALL @@ -60,7 +60,7 @@ FFmpegReader::FFmpegReader(string path, bool inspect_reader) 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), use_omp_threads(true) { + packet(NULL) { // Initialize FFMpeg, and register all formats and codecs AV_REGISTER_ALL @@ -229,9 +229,6 @@ void FFmpegReader::Open() 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); - // Initialize OMP threading support - use_omp_threads = openshot::IsOMPEnabled(); - // Mark as "open" is_open = true; } @@ -613,7 +610,7 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) // Process Video Packet ProcessVideoPacket(requested_frame); - if (!use_omp_threads) { + if (openshot::Settings::Instance()->WAIT_FOR_VIDEO_PROCESSING_TASK) { // Wait on each OMP task to complete before moving on to the next one. This slows // down processing considerably, but might be more stable on some systems. #pragma omp taskwait @@ -628,16 +625,16 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) num_packets_since_video_frame++; // Check the status of a seek (if any) - if (is_seeking) - #pragma omp critical (openshot_seek) - check_seek = CheckSeek(false); - else - check_seek = false; + if (is_seeking) + #pragma omp critical (openshot_seek) + check_seek = CheckSeek(false); + else + check_seek = false; - if (check_seek) { - // Jump to the next iteration of this loop - continue; - } + if (check_seek) { + // Jump to the next iteration of this loop + continue; + } // Update PTS / Frame Offset (if any) UpdatePTSOffset(false); @@ -919,8 +916,12 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) // Copy picture data from one AVFrame (or AVPicture) to another one. AV_COPY_PICTURE_DATA(pFrameRGB, buffer, PIX_FMT_RGBA, width, height); + int scale_mode = SWS_FAST_BILINEAR; + if (openshot::Settings::Instance()->HIGH_QUALITY_SCALING) { + scale_mode = SWS_LANCZOS; + } SwsContext *img_convert_ctx = sws_getContext(info.width, info.height, AV_GET_CODEC_PIXEL_FORMAT(pStream, pCodecCtx), width, - height, PIX_FMT_RGBA, SWS_LANCZOS, NULL, NULL, NULL); + height, PIX_FMT_RGBA, scale_mode, NULL, NULL, NULL); // Resize / Convert to RGB sws_scale(img_convert_ctx, my_frame->data, my_frame->linesize, 0, diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index e02c8803..56f98354 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1748,11 +1748,16 @@ void FFmpegWriter::OutputStreamInfo() // Init a collection of software rescalers (thread safe) void FFmpegWriter::InitScalers(int source_width, int source_height) { + int scale_mode = SWS_FAST_BILINEAR; + if (openshot::Settings::Instance()->HIGH_QUALITY_SCALING) { + scale_mode = SWS_LANCZOS; + } + // Init software rescalers vector (many of them, one for each thread) for (int x = 0; x < num_of_rescalers; x++) { // Init the software scaler from FFMpeg - 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), SWS_LANCZOS, 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 image_rescalers.push_back(img_convert_ctx); diff --git a/src/Settings.cpp b/src/Settings.cpp new file mode 100644 index 00000000..e6749d5c --- /dev/null +++ b/src/Settings.cpp @@ -0,0 +1,50 @@ +/** + * @file + * @brief Source file for global Settings class + * @author Jonathan Thomas + * + * @section LICENSE + * + * Copyright (c) 2008-2014 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 "../include/Settings.h" + +using namespace std; +using namespace openshot; + + +// Global reference to logger +Settings *Settings::m_pInstance = NULL; + +// Create or Get an instance of the logger singleton +Settings *Settings::Instance() +{ + if (!m_pInstance) { + // Create the actual instance of logger only once + m_pInstance = new Settings; + m_pInstance->HARDWARE_DECODE = false; + m_pInstance->HARDWARE_ENCODE = false; + m_pInstance->HIGH_QUALITY_SCALING = false; + m_pInstance->WAIT_FOR_VIDEO_PROCESSING_TASK = false; + } + + return m_pInstance; +} diff --git a/src/bindings/python/openshot.i b/src/bindings/python/openshot.i index f338f18a..de1f020c 100644 --- a/src/bindings/python/openshot.i +++ b/src/bindings/python/openshot.i @@ -84,6 +84,7 @@ #include "../../../include/QtPlayer.h" #include "../../../include/KeyFrame.h" #include "../../../include/RendererBase.h" +#include "../../../include/Settings.h" #include "../../../include/Timeline.h" #include "../../../include/ZmqLogger.h" @@ -150,6 +151,7 @@ %include "../../../include/QtPlayer.h" %include "../../../include/KeyFrame.h" %include "../../../include/RendererBase.h" +%include "../../../include/Settings.h" %include "../../../include/Timeline.h" %include "../../../include/ZmqLogger.h" diff --git a/src/bindings/ruby/openshot.i b/src/bindings/ruby/openshot.i index c2f6fdf9..b9a35d41 100644 --- a/src/bindings/ruby/openshot.i +++ b/src/bindings/ruby/openshot.i @@ -88,6 +88,7 @@ namespace std { #include "../../../include/QtPlayer.h" #include "../../../include/KeyFrame.h" #include "../../../include/RendererBase.h" +#include "../../../include/Settings.h" #include "../../../include/Timeline.h" #include "../../../include/ZmqLogger.h" @@ -143,6 +144,7 @@ namespace std { %include "../../../include/QtPlayer.h" %include "../../../include/KeyFrame.h" %include "../../../include/RendererBase.h" +%include "../../../include/Settings.h" %include "../../../include/Timeline.h" %include "../../../include/ZmqLogger.h" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2c455503..45ce0906 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -172,6 +172,7 @@ IF (NOT DISABLE_TESTS) FrameMapper_Tests.cpp KeyFrame_Tests.cpp Point_Tests.cpp + Settings_Tests.cpp Timeline_Tests.cpp ) ################ TESTER EXECUTABLE ################# diff --git a/tests/Settings_Tests.cpp b/tests/Settings_Tests.cpp new file mode 100644 index 00000000..86790653 --- /dev/null +++ b/tests/Settings_Tests.cpp @@ -0,0 +1,63 @@ +/** + * @file + * @brief Unit tests for openshot::Color + * @author Jonathan Thomas + * + * @section LICENSE + * + * Copyright (c) 2008-2014 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" + +using namespace std; +using namespace openshot; + +TEST(Settings_Default_Constructor) +{ + // Create an empty color + Settings *s = Settings::Instance(); + + CHECK_EQUAL(false, s->HARDWARE_DECODE); + CHECK_EQUAL(false, s->HARDWARE_ENCODE); + CHECK_EQUAL(false, s->HIGH_QUALITY_SCALING); + CHECK_EQUAL(false, s->WAIT_FOR_VIDEO_PROCESSING_TASK); +} + +TEST(Settings_Change_Settings) +{ + // Create an empty color + Settings *s = Settings::Instance(); + s->HARDWARE_DECODE = true; + s->HARDWARE_ENCODE = true; + s->HIGH_QUALITY_SCALING = true; + s->WAIT_FOR_VIDEO_PROCESSING_TASK = true; + + CHECK_EQUAL(true, s->HARDWARE_DECODE); + CHECK_EQUAL(true, s->HARDWARE_ENCODE); + CHECK_EQUAL(true, s->HIGH_QUALITY_SCALING); + CHECK_EQUAL(true, s->WAIT_FOR_VIDEO_PROCESSING_TASK); + + CHECK_EQUAL(true, s->HARDWARE_DECODE); + CHECK_EQUAL(true, s->HARDWARE_ENCODE); + CHECK_EQUAL(true, Settings::Instance()->HIGH_QUALITY_SCALING); + CHECK_EQUAL(true, Settings::Instance()->WAIT_FOR_VIDEO_PROCESSING_TASK); +} \ No newline at end of file