diff --git a/include/Clip.h b/include/Clip.h index fe4effab..24d4c599 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -42,6 +42,7 @@ #include "Effects.h" #include "EffectInfo.h" #include "Fraction.h" +#include "Frame.h" #include "KeyFrame.h" #include "ReaderBase.h" #include "JuceHeader.h" @@ -146,9 +147,6 @@ namespace openshot { void reverse_buffer(juce::AudioSampleBuffer* buffer); public: - /// Final cache object used to hold final frames - CacheMemory final_cache; - openshot::GravityType gravity; ///< The gravity of a clip determines where it snaps to its parent openshot::ScaleType scale; ///< The scale determines how a clip should be resized to fit its parent openshot::AnchorType anchor; ///< The anchor determines what parent a clip should snap to @@ -169,9 +167,8 @@ namespace openshot { /// Destructor virtual ~Clip(); - - /// Get the cache object used by this reader (always returns NULL for this object) - CacheMemory* GetCache() override { return &final_cache; }; + /// 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; }; @@ -197,20 +194,21 @@ namespace openshot { /// @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. /// - /// @returns The requested frame (containing the image) - /// @param requested_frame The frame number that is requested - /// @param width The width of the image requested - /// @param height The height of the image requested - /// @param samples The number of samples requested - std::shared_ptr GetFrame(int64_t requested_frame, int width, int height, int samples); + /// 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(); @@ -265,13 +263,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/include/ClipBase.h b/include/ClipBase.h index 1f7f55c4..e335c501 100644 --- a/include/ClipBase.h +++ b/include/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,6 +66,7 @@ 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() { }; @@ -72,6 +77,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 +103,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 +111,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/include/EffectBase.h b/include/EffectBase.h index 1f967a02..353e1817 100644 --- a/include/EffectBase.h +++ b/include/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/include/OpenShot.h b/include/OpenShot.h index 5273ff0d..56f847d1 100644 --- a/include/OpenShot.h +++ b/include/OpenShot.h @@ -138,6 +138,7 @@ #include "QtHtmlReader.h" #include "QtImageReader.h" #include "QtTextReader.h" +#include "TimelineBase.h" #include "Timeline.h" #include "Settings.h" diff --git a/include/ReaderBase.h b/include/ReaderBase.h index c997b76d..6d68f729 100644 --- a/include/ReaderBase.h +++ b/include/ReaderBase.h @@ -98,9 +98,9 @@ namespace openshot { protected: /// Section lock for multiple threads - juce::CriticalSection getFrameCriticalSection; - juce::CriticalSection processingCriticalSection; - openshot::ClipBase* parent; + juce::CriticalSection getFrameCriticalSection; + juce::CriticalSection processingCriticalSection; + openshot::ClipBase* clip; ///< Pointer to the parent clip instance (if any) public: diff --git a/include/Timeline.h b/include/Timeline.h index d5b01c0b..22718342 100644 --- a/include/Timeline.h +++ b/include/Timeline.h @@ -54,6 +54,8 @@ #include "OpenMPUtilities.h" #include "ReaderBase.h" #include "Settings.h" +#include "TimelineBase.h" + namespace openshot { @@ -161,7 +163,7 @@ namespace openshot { * t.Close(); * @endcode */ - class Timeline : public openshot::ReaderBase { + class Timeline : public openshot::TimelineBase, public openshot::ReaderBase { private: bool is_open; /// + * + * @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_TIMELINE_BASE_H +#define OPENSHOT_TIMELINE_BASE_H + + +namespace openshot { + /** + * @brief This class represents a timeline (used for building generic timeline implementations) + */ + class TimelineBase { + + public: + int preview_width; ///< Optional preview width of timeline image. If your preview window is smaller than the timeline, it's recommended to set this. + int preview_height; ///< Optional preview width of timeline image. If your preview window is smaller than the timeline, it's recommended to set this. + }; +} + +#endif diff --git a/include/effects/Bars.h b/include/effects/Bars.h index 7c92255a..a781a520 100644 --- a/include/effects/Bars.h +++ b/include/effects/Bars.h @@ -77,16 +77,24 @@ namespace openshot /// @param bottom The curve to adjust the bottom bar size (between 0 and 1) Bars(Color color, Keyframe left, Keyframe top, Keyframe right, Keyframe bottom); - /// @brief This method is required for all derived classes of EffectBase, and returns a + /// @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. + std::shared_ptr GetFrame(int64_t frame_number) override { return GetFrame(std::shared_ptr (new Frame()), frame_number); } + + /// @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 a frame_number is passed in which - /// tells the effect which settings to use from its keyframes (starting at 1). + /// 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 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) override; + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object diff --git a/include/effects/Blur.h b/include/effects/Blur.h index 60a0cd08..a3211e76 100644 --- a/include/effects/Blur.h +++ b/include/effects/Blur.h @@ -89,16 +89,24 @@ namespace openshot /// @param new_iterations The curve to adjust the # of iterations (between 1 and 100) Blur(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 + /// @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. + std::shared_ptr GetFrame(int64_t frame_number) override { return GetFrame(std::shared_ptr (new Frame()), frame_number); } + + /// @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 a frame_number is passed in which - /// tells the effect which settings to use from its keyframes (starting at 1). + /// 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 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) override; + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object diff --git a/include/effects/Brightness.h b/include/effects/Brightness.h index 5f25b94a..5e36671f 100644 --- a/include/effects/Brightness.h +++ b/include/effects/Brightness.h @@ -77,16 +77,24 @@ namespace openshot /// @param new_contrast The curve to adjust the contrast (3 is typical, 20 is a lot, 100 is max. 0 is invalid) Brightness(Keyframe new_brightness, Keyframe new_contrast); - /// @brief This method is required for all derived classes of EffectBase, and returns a + /// @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. + std::shared_ptr GetFrame(int64_t frame_number) override { return GetFrame(std::shared_ptr (new Frame()), frame_number); } + + /// @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 a frame_number is passed in which - /// tells the effect which settings to use from its keyframes (starting at 1). + /// 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 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) override; + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object diff --git a/include/effects/ChromaKey.h b/include/effects/ChromaKey.h index fcc8c3b1..a59e582d 100644 --- a/include/effects/ChromaKey.h +++ b/include/effects/ChromaKey.h @@ -74,16 +74,24 @@ namespace openshot /// @param fuzz The fuzz factor (or threshold) ChromaKey(Color color, Keyframe fuzz); - /// @brief This method is required for all derived classes of EffectBase, and returns a + /// @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. + std::shared_ptr GetFrame(int64_t frame_number) override { return GetFrame(std::shared_ptr (new Frame()), frame_number); } + + /// @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 a frame_number is passed in which - /// tells the effect which settings to use from its keyframes (starting at 1). + /// 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 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) override; + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object diff --git a/include/effects/ColorShift.h b/include/effects/ColorShift.h index 4ef56dc6..b6c596a9 100644 --- a/include/effects/ColorShift.h +++ b/include/effects/ColorShift.h @@ -81,16 +81,24 @@ namespace openshot /// @param alpha_y The curve to adjust the Alpha y shift (between -1 and 1, percentage) ColorShift(Keyframe red_x, Keyframe red_y, Keyframe green_x, Keyframe green_y, Keyframe blue_x, Keyframe blue_y, Keyframe alpha_x, Keyframe alpha_y); - /// @brief This method is required for all derived classes of EffectBase, and returns a + /// @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. + std::shared_ptr GetFrame(int64_t frame_number) override { return GetFrame(std::shared_ptr (new Frame()), frame_number); } + + /// @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 a frame_number is passed in which - /// tells the effect which settings to use from its keyframes (starting at 1). + /// 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 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) override; + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object diff --git a/include/effects/Crop.h b/include/effects/Crop.h index f5ba07f2..ccdba3f1 100644 --- a/include/effects/Crop.h +++ b/include/effects/Crop.h @@ -76,16 +76,24 @@ namespace openshot /// @param bottom The curve to adjust the bottom bar size (between 0 and 1) Crop(Keyframe left, Keyframe top, Keyframe right, Keyframe bottom); - /// @brief This method is required for all derived classes of EffectBase, and returns a + /// @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. + std::shared_ptr GetFrame(int64_t frame_number) override { return GetFrame(std::shared_ptr (new Frame()), frame_number); } + + /// @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 a frame_number is passed in which - /// tells the effect which settings to use from its keyframes (starting at 1). + /// 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 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) override; + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object diff --git a/include/effects/Deinterlace.h b/include/effects/Deinterlace.h index 97c77853..83a9f2b2 100644 --- a/include/effects/Deinterlace.h +++ b/include/effects/Deinterlace.h @@ -70,16 +70,24 @@ namespace openshot /// Default constructor Deinterlace(bool isOdd); - /// @brief This method is required for all derived classes of EffectBase, and returns a + /// @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. + std::shared_ptr GetFrame(int64_t frame_number) override { return GetFrame(std::shared_ptr (new Frame()), frame_number); } + + /// @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 a frame_number is passed in which - /// tells the effect which settings to use from its keyframes (starting at 1). + /// 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 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) override; + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object diff --git a/include/effects/Hue.h b/include/effects/Hue.h index 833bf087..e561bbf7 100644 --- a/include/effects/Hue.h +++ b/include/effects/Hue.h @@ -67,16 +67,24 @@ namespace openshot /// @param hue The curve to adjust the hue shift (between 0 and 1) Hue(Keyframe hue); - /// @brief This method is required for all derived classes of EffectBase, and returns a + /// @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. + std::shared_ptr GetFrame(int64_t frame_number) override { return GetFrame(std::shared_ptr (new Frame()), frame_number); } + + /// @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 a frame_number is passed in which - /// tells the effect which settings to use from its keyframes (starting at 1). + /// 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 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) override; + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object diff --git a/include/effects/Mask.h b/include/effects/Mask.h index 8156b843..910f1308 100644 --- a/include/effects/Mask.h +++ b/include/effects/Mask.h @@ -89,16 +89,24 @@ namespace openshot /// @param mask_contrast The curve to adjust the contrast of the wipe's mask (3 is typical, 20 is a lot, 0 is invalid) Mask(ReaderBase *mask_reader, Keyframe mask_brightness, Keyframe mask_contrast); - /// @brief This method is required for all derived classes of EffectBase, and returns a + /// @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. + std::shared_ptr GetFrame(int64_t frame_number) override { return GetFrame(std::shared_ptr (new Frame()), frame_number); } + + /// @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 a frame_number is passed in which - /// tells the effect which settings to use from its keyframes (starting at 1). + /// 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 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) override; + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object diff --git a/include/effects/Negate.h b/include/effects/Negate.h index c691a86c..cab98f0a 100644 --- a/include/effects/Negate.h +++ b/include/effects/Negate.h @@ -58,16 +58,24 @@ namespace openshot /// Default constructor Negate(); - /// @brief This method is required for all derived classes of EffectBase, and returns a + /// @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. + std::shared_ptr GetFrame(int64_t frame_number) override { return GetFrame(std::shared_ptr (new Frame()), frame_number); } + + /// @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 a frame_number is passed in which - /// tells the effect which settings to use from its keyframes (starting at 1). + /// 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 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) override; + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object diff --git a/include/effects/Pixelate.h b/include/effects/Pixelate.h index 793f4d46..8090847f 100644 --- a/include/effects/Pixelate.h +++ b/include/effects/Pixelate.h @@ -75,16 +75,24 @@ namespace openshot /// @param bottom The curve to adjust the bottom margin size (between 0 and 1) Pixelate(Keyframe pixelization, Keyframe left, Keyframe top, Keyframe right, Keyframe bottom); - /// @brief This method is required for all derived classes of EffectBase, and returns a + /// @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. + std::shared_ptr GetFrame(int64_t frame_number) override { return GetFrame(std::shared_ptr (new Frame()), frame_number); } + + /// @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 a frame_number is passed in which - /// tells the effect which settings to use from its keyframes (starting at 1). + /// 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 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) override; + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object diff --git a/include/effects/Saturation.h b/include/effects/Saturation.h index cc697631..b07a1700 100644 --- a/include/effects/Saturation.h +++ b/include/effects/Saturation.h @@ -80,16 +80,24 @@ namespace openshot /// @param saturation_B The curve to adjust blue saturation of the frame's image (0.0 = greyscale, 1.0 = normal, 2.0 = double saturation) Saturation(Keyframe saturation, Keyframe saturation_R, Keyframe saturation_G, Keyframe saturation_B); - /// @brief This method is required for all derived classes of EffectBase, and returns a + /// @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. + std::shared_ptr GetFrame(int64_t frame_number) override { return GetFrame(std::shared_ptr (new Frame()), frame_number); } + + /// @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 a frame_number is passed in which - /// tells the effect which settings to use from its keyframes (starting at 1). + /// 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 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) override; + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object diff --git a/include/effects/Shift.h b/include/effects/Shift.h index 7a7efbea..b2c3242d 100644 --- a/include/effects/Shift.h +++ b/include/effects/Shift.h @@ -70,16 +70,24 @@ namespace openshot /// @param y The curve to adjust the y shift (between -1 and 1, percentage) Shift(Keyframe x, Keyframe y); - /// @brief This method is required for all derived classes of EffectBase, and returns a + /// @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. + std::shared_ptr GetFrame(int64_t frame_number) override { return GetFrame(std::shared_ptr (new Frame()), frame_number); } + + /// @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 a frame_number is passed in which - /// tells the effect which settings to use from its keyframes (starting at 1). + /// 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 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) override; + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object diff --git a/include/effects/Wave.h b/include/effects/Wave.h index d4759c24..3b922eb3 100644 --- a/include/effects/Wave.h +++ b/include/effects/Wave.h @@ -76,16 +76,24 @@ namespace openshot /// @param speed_y The curve to adjust the vertical speed (0 to 10) Wave(Keyframe wavelength, Keyframe amplitude, Keyframe multiplier, Keyframe shift_x, Keyframe speed_y); - /// @brief This method is required for all derived classes of EffectBase, and returns a + /// @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. + std::shared_ptr GetFrame(int64_t frame_number) override { return GetFrame(std::shared_ptr (new Frame()), frame_number); } + + /// @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 a frame_number is passed in which - /// tells the effect which settings to use from its keyframes (starting at 1). + /// 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 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) override; + /// @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. + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 04121c22..8cc2b6f2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -178,6 +178,7 @@ set(OPENSHOT_SOURCES QtPlayer.cpp QtTextReader.cpp Settings.cpp + TimelineBase.cpp Timeline.cpp) # Video effects diff --git a/src/ChunkReader.cpp b/src/ChunkReader.cpp index c194ce33..fb45e8f6 100644 --- a/src/ChunkReader.cpp +++ b/src/ChunkReader.cpp @@ -222,7 +222,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 +229,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/src/ChunkWriter.cpp b/src/ChunkWriter.cpp index c7752cd5..8a8e559c 100644 --- a/src/ChunkWriter.cpp +++ b/src/ChunkWriter.cpp @@ -159,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++) { @@ -231,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/src/Clip.cpp b/src/Clip.cpp index 0a38c6b4..fbea9e70 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -79,13 +79,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); @@ -109,7 +102,7 @@ void Clip::init_settings() has_video = Keyframe(-1.0); // Initialize Clip cache - final_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels); + cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels); } // Init reader's rotation (if any) @@ -177,7 +170,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(...) { } } @@ -186,7 +179,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(...) { } } @@ -198,13 +191,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(...) { } } @@ -316,8 +309,8 @@ 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) @@ -326,25 +319,19 @@ std::shared_ptr Clip::GetFrame(int64_t requested_frame) if (reader) { // Adjust out of bounds frame number - requested_frame = adjust_frame_number_minimum(requested_frame); + frame_number = adjust_frame_number_minimum(frame_number); - // 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)); - if (time.GetLength() > 1) - new_frame_number = time_mapped_number; - - // Get the # of audio samples from the time mapped Frame instance - std::shared_ptr time_mapped_original_frame = GetOrCreateFrame(new_frame_number); - return GetFrame(requested_frame, reader->info.width, reader->info.height, time_mapped_original_frame->GetAudioSamplesCount()); + // 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."); } -// Get an openshot::Frame object for a specific frame number of this reader. -std::shared_ptr Clip::GetFrame(int64_t requested_frame, int width, int height, int samples) +// 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) @@ -353,33 +340,33 @@ std::shared_ptr Clip::GetFrame(int64_t requested_frame, int width, int he 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 = final_cache.GetFrame(requested_frame); + std::shared_ptr cached_frame = cache.GetFrame(frame_number); if (cached_frame) { // Debug output - ZmqLogger::Instance()->AppendDebugMethod("Clip::GetFrame", "returned cached frame", requested_frame); + 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; @@ -387,16 +374,6 @@ std::shared_ptr Clip::GetFrame(int64_t requested_frame, int width, int he std::shared_ptr original_frame; original_frame = GetOrCreateFrame(new_frame_number); - // Create a new frame - auto frame = std::make_shared( - 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::make_shared(*original_frame->GetImage())); @@ -416,11 +393,24 @@ std::shared_ptr Clip::GetFrame(int64_t requested_frame, int width, int he // 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 - final_cache.Add(frame); + cache.Add(frame); // Return processed 'frame' return frame; @@ -692,17 +682,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; try { // Debug output 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) { // ... @@ -719,7 +718,7 @@ std::shared_ptr Clip::GetOrCreateFrame(int64_t number) 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", estimated_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(estimated_samples_in_frame); @@ -808,11 +807,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); @@ -843,10 +837,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(); @@ -906,7 +896,7 @@ void Clip::SetJsonValue(const Json::Value root) { ClipBase::SetJsonValue(root); // Clear cache - final_cache.Clear(); + cache.Clear(); // Set data from Json (if key is found) if (!root["gravity"].isNull()) @@ -939,14 +929,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()) @@ -1025,13 +1007,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 @@ -1051,20 +1033,20 @@ 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 @@ -1091,6 +1073,9 @@ 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); @@ -1098,7 +1083,7 @@ void Clip::AddEffect(EffectBase* effect) sort_effects(); // Clear cache - final_cache.Clear(); + cache.Clear(); } // Remove an effect from the clip @@ -1107,7 +1092,7 @@ void Clip::RemoveEffect(EffectBase* effect) effects.remove(effect); // Clear cache - final_cache.Clear(); + cache.Clear(); } // Apply effects to the source frame (if any) @@ -1180,7 +1165,7 @@ void Clip::apply_keyframes(std::shared_ptr frame, int width, int height) source_size.scale(width, height, Qt::KeepAspectRatio); // Debug output - ZmqLogger::Instance()->AppendDebugMethod("Clip::add_keyframes (Scale: SCALE_FIT)", "frame->number", frame->number, "source_width", source_size.width(), "source_height", source_size.height()); + 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): { @@ -1188,7 +1173,7 @@ void Clip::apply_keyframes(std::shared_ptr frame, int width, int height) source_size.scale(width, height, Qt::IgnoreAspectRatio); // Debug output - ZmqLogger::Instance()->AppendDebugMethod("Clip::add_keyframes (Scale: SCALE_STRETCH)", "frame->number", frame->number, "source_width", source_size.width(), "source_height", source_size.height()); + 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): { @@ -1202,7 +1187,7 @@ void Clip::apply_keyframes(std::shared_ptr frame, int width, int height) source_size.scale(height_size.width(), height_size.height(), Qt::KeepAspectRatio); // Debug output - ZmqLogger::Instance()->AppendDebugMethod("Clip::add_keyframes (Scale: SCALE_CROP)", "frame->number", frame->number, "source_width", source_size.width(), "source_height", source_size.height()); + 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): { @@ -1214,50 +1199,11 @@ void Clip::apply_keyframes(std::shared_ptr frame, int width, int height) source_size.scale(width * source_width_ratio, height * source_height_ratio, Qt::KeepAspectRatio); // Debug output - ZmqLogger::Instance()->AppendDebugMethod("Clip::add_keyframes (Scale: SCALE_NONE)", "frame->number", frame->number, "source_width", source_size.width(), "source_height", source_size.height()); + ZmqLogger::Instance()->AppendDebugMethod("Clip::apply_keyframes (Scale: SCALE_NONE)", "frame->number", frame->number, "source_width", source_size.width(), "source_height", source_size.height()); break; } } - float crop_x_value = crop_x.GetValue(frame->number); - float crop_y_value = crop_y.GetValue(frame->number); - float crop_w_value = crop_width.GetValue(frame->number); - float crop_h_value = crop_height.GetValue(frame->number); - switch(crop_gravity) - { - case (GRAVITY_TOP_LEFT): - // This is only here to prevent unused-enum warnings - break; - case (GRAVITY_TOP): - crop_x_value += 0.5; - break; - case (GRAVITY_TOP_RIGHT): - crop_x_value += 1.0; - break; - case (GRAVITY_LEFT): - crop_y_value += 0.5; - break; - case (GRAVITY_CENTER): - crop_x_value += 0.5; - crop_y_value += 0.5; - break; - case (GRAVITY_RIGHT): - crop_x_value += 1.0; - crop_y_value += 0.5; - break; - case (GRAVITY_BOTTOM_LEFT): - crop_y_value += 1.0; - break; - case (GRAVITY_BOTTOM): - crop_x_value += 0.5; - crop_y_value += 1.0; - break; - case (GRAVITY_BOTTOM_RIGHT): - crop_x_value += 1.0; - crop_y_value += 1.0; - break; - } - /* GRAVITY LOCATION - Initialize X & Y to the correct values (before applying location curves) */ float x = 0.0; // left float y = 0.0; // top @@ -1304,7 +1250,7 @@ void Clip::apply_keyframes(std::shared_ptr frame, int width, int height) } // Debug output - ZmqLogger::Instance()->AppendDebugMethod("Clip::add_keyframes (Gravity)", "frame->number", frame->number, "source_clip->gravity", gravity, "scaled_source_width", scaled_source_width, "scaled_source_height", scaled_source_height); + 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 @@ -1319,7 +1265,7 @@ void Clip::apply_keyframes(std::shared_ptr frame, int width, int height) QTransform transform; // Transform source image (if needed) - ZmqLogger::Instance()->AppendDebugMethod("Clip::add_keyframes (Build QTransform - if needed)", "frame->number", frame->number, "x", x, "y", y, "r", r, "sx", sx, "sy", sy); + 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 @@ -1348,7 +1294,7 @@ void Clip::apply_keyframes(std::shared_ptr frame, int width, int height) } // Debug output - ZmqLogger::Instance()->AppendDebugMethod("Clip::add_keyframes (Transform: Composite Image Layer: Prepare)", "frame->number", frame->number, "transformed", transformed); + 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; @@ -1367,31 +1313,34 @@ void Clip::apply_keyframes(std::shared_ptr frame, int width, int height) painter.setCompositionMode(QPainter::CompositionMode_SourceOver); painter.drawImage(0, 0, *source_image); - // 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; + if (timeline) { + Timeline *t = (Timeline *) timeline; - case (FRAME_DISPLAY_CLIP): - frame_number_str << frame->number; - break; + // 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_TIMELINE): - frame_number_str << "N/A"; - break; + case (FRAME_DISPLAY_CLIP): + frame_number_str << frame->number; + break; - case (FRAME_DISPLAY_BOTH): - frame_number_str << "N/A" << " (" << 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())); } - - // Draw frame number on top of image - painter.setPen(QColor("#ffffff")); - painter.drawText(20, 20, QString(frame_number_str.str().c_str())); } painter.end(); diff --git a/src/EffectBase.cpp b/src/EffectBase.cpp index 05ed97c2..fcf00645 100644 --- a/src/EffectBase.cpp +++ b/src/EffectBase.cpp @@ -138,3 +138,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/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 5b7b7ddd..dcdad2c0 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -1268,15 +1268,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; + int max_width = info.width; + int max_height = info.height; Clip *parent = (Clip *) GetParentClip(); 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; diff --git a/src/Qt/PlayerDemo.cpp b/src/Qt/PlayerDemo.cpp index e5f0e11d..54813b37 100644 --- a/src/Qt/PlayerDemo.cpp +++ b/src/Qt/PlayerDemo.cpp @@ -105,7 +105,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 +114,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 +124,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/src/QtImageReader.cpp b/src/QtImageReader.cpp index 78c2b009..86040bd4 100644 --- a/src/QtImageReader.cpp +++ b/src/QtImageReader.cpp @@ -175,15 +175,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; + int max_width = info.width; + int max_height = info.height; Clip* parent = (Clip*) GetParentClip(); 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; diff --git a/src/ReaderBase.cpp b/src/ReaderBase.cpp index 6799d95e..653756c5 100644 --- a/src/ReaderBase.cpp +++ b/src/ReaderBase.cpp @@ -63,7 +63,7 @@ ReaderBase::ReaderBase() info.audio_timebase = Fraction(); // Init parent clip - parent = NULL; + clip = NULL; } // Display file information @@ -249,3 +249,13 @@ void ReaderBase::SetJsonValue(const Json::Value root) { } } } + +/// Parent clip object of this reader (which can be unparented and NULL) +openshot::ClipBase* ReaderBase::ParentClip() { + return clip; +} + +/// Set parent clip object of this reader +void ReaderBase::ParentClip(openshot::ClipBase* new_clip) { + clip = new_clip; +} diff --git a/src/Settings.cpp b/src/Settings.cpp index e48fd981..d946d227 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -45,8 +45,6 @@ Settings *Settings::Instance() m_pInstance = new Settings; m_pInstance->HARDWARE_DECODER = 0; m_pInstance->HIGH_QUALITY_SCALING = false; - m_pInstance->MAX_WIDTH = 0; - m_pInstance->MAX_HEIGHT = 0; m_pInstance->WAIT_FOR_VIDEO_PROCESSING_TASK = false; m_pInstance->OMP_THREADS = 12; m_pInstance->FF_THREADS = 8; diff --git a/src/Timeline.cpp b/src/Timeline.cpp index ac36be06..afa85f99 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -52,6 +52,8 @@ Timeline::Timeline(int width, int height, Fraction fps, int sample_rate, int cha // Init FileInfo struct (clear all values) info.width = width; info.height = height; + preview_width = info.width; + preview_height = info.height; info.fps = fps; info.sample_rate = sample_rate; info.channels = channels; @@ -241,6 +243,9 @@ Timeline::~Timeline() { // Add an openshot::Clip to the timeline void Timeline::AddClip(Clip* clip) { + // Assign timeline to clip + clip->ParentTimeline(this); + // All clips should be converted to the frame rate of this timeline if (auto_map_clips) // Apply framemapper (or update existing framemapper) @@ -256,6 +261,9 @@ void Timeline::AddClip(Clip* clip) // Add an effect to the timeline void Timeline::AddEffect(EffectBase* effect) { + // Assign timeline to effect + effect->ParentTimeline(this); + // Add effect to list effects.push_back(effect); @@ -441,7 +449,7 @@ std::shared_ptr Timeline::GetOrCreateFrame(Clip* clip, int64_t number) // Attempt to get a frame (but this could fail if a reader has just been closed) #pragma omp critical (T_GetOtCreateFrame) - new_frame = std::shared_ptr(clip->GetFrame(number, Settings::Instance()->MAX_WIDTH, Settings::Instance()->MAX_HEIGHT, samples_in_frame)); + new_frame = std::shared_ptr(clip->GetFrame(number)); // Return real frame return new_frame; @@ -458,7 +466,7 @@ std::shared_ptr Timeline::GetOrCreateFrame(Clip* clip, int64_t number) ZmqLogger::Instance()->AppendDebugMethod("Timeline::GetOrCreateFrame (create blank)", "number", number, "samples_in_frame", samples_in_frame); // Create blank frame - new_frame = std::make_shared(number, Settings::Instance()->MAX_WIDTH, Settings::Instance()->MAX_HEIGHT, "#000000", samples_in_frame, info.channels); + new_frame = std::make_shared(number, preview_width, preview_height, "#000000", samples_in_frame, info.channels); #pragma omp critical (T_GetOtCreateFrame) { new_frame->SampleRate(info.sample_rate); @@ -560,29 +568,8 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in // Skip the rest of the image processing for performance reasons return; - // Debug output - ZmqLogger::Instance()->AppendDebugMethod("Timeline::add_layer (Get Source Image)", "source_frame->number", source_frame->number, "source_clip->Waveform()", source_clip->Waveform(), "clip_frame_number", clip_frame_number); - - // Get actual frame image data - source_image = source_frame->GetImage(); - - // Debug output - ZmqLogger::Instance()->AppendDebugMethod("Timeline::add_layer (Transform: Composite Image Layer: Prepare)", "source_frame->number", source_frame->number, "new_frame->GetImage()->width()", new_frame->GetImage()->width(), "source_image->width()", source_image->width()); - - /* COMPOSITE SOURCE IMAGE (LAYER) ONTO FINAL IMAGE */ - std::shared_ptr new_image; - new_image = new_frame->GetImage(); - - // Load timeline's new frame image into a QPainter - QPainter painter(new_image.get()); - - // Composite a new layer onto the image - painter.setCompositionMode(QPainter::CompositionMode_SourceOver); - painter.drawImage(0, 0, *source_image, 0, 0, source_image->width(), source_image->height()); - painter.end(); - // Add new QImage to frame - new_frame->AddImage(new_image); + new_frame->AddImage(source_frame->GetImage()); // Debug output ZmqLogger::Instance()->AppendDebugMethod("Timeline::add_layer (Transform: Composite Image Layer: Completed)", "source_frame->number", source_frame->number, "new_frame->GetImage()->width()", new_frame->GetImage()->width()); @@ -737,10 +724,9 @@ std::shared_ptr Timeline::GetFrame(int64_t requested_frame) // Get clip frame # long clip_start_frame = (clip->Start() * info.fps.ToDouble()) + 1; long clip_frame_number = frame_number - clip_start_position + clip_start_frame; - int samples_in_frame = Frame::GetSamplesPerFrame(frame_number, info.fps, info.sample_rate, info.channels); // Cache clip object - clip->GetFrame(clip_frame_number, Settings::Instance()->MAX_WIDTH, Settings::Instance()->MAX_HEIGHT, samples_in_frame); + clip->GetFrame(clip_frame_number); } } } @@ -758,7 +744,7 @@ std::shared_ptr Timeline::GetFrame(int64_t requested_frame) int samples_in_frame = Frame::GetSamplesPerFrame(frame_number, info.fps, info.sample_rate, info.channels); // Create blank frame (which will become the requested frame) - std::shared_ptr new_frame(std::make_shared(frame_number, Settings::Instance()->MAX_WIDTH, Settings::Instance()->MAX_HEIGHT, "#000000", samples_in_frame, info.channels)); + std::shared_ptr new_frame(std::make_shared(frame_number, preview_width, preview_height, "#000000", samples_in_frame, info.channels)); #pragma omp critical (T_GetFrame) { new_frame->AddAudioSilence(samples_in_frame); @@ -772,7 +758,7 @@ std::shared_ptr Timeline::GetFrame(int64_t requested_frame) // Add Background Color to 1st layer (if animated or not black) if ((color.red.GetCount() > 1 || color.green.GetCount() > 1 || color.blue.GetCount() > 1) || (color.red.GetValue(frame_number) != 0.0 || color.green.GetValue(frame_number) != 0.0 || color.blue.GetValue(frame_number) != 0.0)) - new_frame->AddColor(Settings::Instance()->MAX_WIDTH, Settings::Instance()->MAX_HEIGHT, color.GetColorHex(frame_number)); + new_frame->AddColor(preview_width, preview_height, color.GetColorHex(frame_number)); // Debug output ZmqLogger::Instance()->AppendDebugMethod("Timeline::GetFrame (Loop through clips)", "frame_number", frame_number, "clips.size()", clips.size(), "nearby_clips.size()", nearby_clips.size()); @@ -1036,6 +1022,10 @@ void Timeline::SetJsonValue(const Json::Value root) { info.video_length = info.fps.ToFloat() * info.duration; } + // Update preview settings + preview_width = info.width; + preview_height = info.height; + // Re-open if needed if (was_open) Open(); @@ -1264,6 +1254,12 @@ void Timeline::apply_json_to_effects(Json::Value change, EffectBase* existing_ef // Add Effect to Timeline AddEffect(e); + + // Clear cache on parent clip (if any) + Clip* parent_clip = (Clip*) e->ParentClip(); + if (parent_clip && parent_clip->GetCache()) { + parent_clip->GetCache()->Clear(); + } } } else if (change_type == "update") { @@ -1276,6 +1272,12 @@ void Timeline::apply_json_to_effects(Json::Value change, EffectBase* existing_ef int64_t old_ending_frame = ((existing_effect->Position() + existing_effect->Duration()) * info.fps.ToDouble()) + 1; final_cache->Remove(old_starting_frame - 8, old_ending_frame + 8); + // Clear cache on parent clip (if any) + Clip* parent_clip = (Clip*) existing_effect->ParentClip(); + if (parent_clip && parent_clip->GetCache()) { + parent_clip->GetCache()->Clear(); + } + // Update effect properties from JSON existing_effect->SetJsonValue(change["value"]); } @@ -1290,6 +1292,12 @@ void Timeline::apply_json_to_effects(Json::Value change, EffectBase* existing_ef int64_t old_ending_frame = ((existing_effect->Position() + existing_effect->Duration()) * info.fps.ToDouble()) + 1; final_cache->Remove(old_starting_frame - 8, old_ending_frame + 8); + // Clear cache on parent clip (if any) + Clip* parent_clip = (Clip*) existing_effect->ParentClip(); + if (parent_clip && parent_clip->GetCache()) { + parent_clip->GetCache()->Clear(); + } + // Remove effect from timeline RemoveEffect(existing_effect); } @@ -1308,7 +1316,7 @@ void Timeline::apply_json_to_timeline(Json::Value change) { sub_key = change["key"][(uint)1].asString(); // Clear entire cache - final_cache->Clear(); + ClearAllCache(); // Determine type of change operation if (change_type == "insert" || change_type == "update") { @@ -1332,12 +1340,16 @@ void Timeline::apply_json_to_timeline(Json::Value change) { info.duration = change["value"].asDouble(); info.video_length = info.fps.ToFloat() * info.duration; } - else if (root_key == "width") + else if (root_key == "width") { // Set width info.width = change["value"].asInt(); - else if (root_key == "height") + preview_width = info.width; + } + else if (root_key == "height") { // Set height info.height = change["value"].asInt(); + preview_height = info.height; + } else if (root_key == "fps" && sub_key == "" && change["value"].isObject()) { // Set fps fraction if (!change["value"]["num"].isNull()) @@ -1429,6 +1441,7 @@ void Timeline::ClearAllCache() { for (auto clip : clips) { // Clear cache on clip + clip->GetCache()->Clear(); clip->Reader()->GetCache()->Clear(); // Clear nested Reader (if any) @@ -1451,7 +1464,7 @@ void Timeline::SetMaxSize(int width, int height) { // Scale QSize up to proposed size display_ratio_size.scale(proposed_size, Qt::KeepAspectRatio); - // Set max size - Settings::Instance()->MAX_WIDTH = display_ratio_size.width(); - Settings::Instance()->MAX_HEIGHT = display_ratio_size.height(); + // Update preview settings + preview_width = display_ratio_size.width(); + preview_height = display_ratio_size.height(); } diff --git a/src/TimelineBase.cpp b/src/TimelineBase.cpp new file mode 100644 index 00000000..f75e1ddb --- /dev/null +++ b/src/TimelineBase.cpp @@ -0,0 +1,33 @@ +/** + * @file + * @brief Source file for Timeline 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 "../include/TimelineBase.h" + +using namespace openshot; diff --git a/src/bindings/python/openshot.i b/src/bindings/python/openshot.i index 53e514c1..b5be39c4 100644 --- a/src/bindings/python/openshot.i +++ b/src/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" @@ -203,6 +204,7 @@ %include "KeyFrame.h" %include "RendererBase.h" %include "Settings.h" +%include "TimelineBase.h" %include "Timeline.h" %include "ZmqLogger.h" %include "AudioDeviceInfo.h" diff --git a/src/bindings/ruby/openshot.i b/src/bindings/ruby/openshot.i index 2f24d220..d36990dd 100644 --- a/src/bindings/ruby/openshot.i +++ b/src/bindings/ruby/openshot.i @@ -103,6 +103,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 +193,7 @@ namespace std { %include "KeyFrame.h" %include "RendererBase.h" %include "Settings.h" +%include "TimelineBase.h" %include "Timeline.h" %include "ZmqLogger.h" %include "AudioDeviceInfo.h"