2012-10-03 01:55:24 -05:00
|
|
|
/**
|
2013-09-09 23:32:16 -05:00
|
|
|
* @file
|
|
|
|
|
* @brief Header file for Timeline class
|
2013-09-12 17:52:10 -05:00
|
|
|
* @author Jonathan Thomas <jonathan@openshot.org>
|
|
|
|
|
*
|
|
|
|
|
* @section LICENSE
|
|
|
|
|
*
|
2014-03-29 18:49:22 -05:00
|
|
|
* Copyright (c) 2008-2014 OpenShot Studios, LLC
|
|
|
|
|
* <http://www.openshotstudios.com/>. 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 <http://www.openshot.org/>.
|
2013-09-12 17:52:10 -05:00
|
|
|
*
|
2014-03-29 18:49:22 -05:00
|
|
|
* OpenShot Library (libopenshot) is free software: you can redistribute it
|
|
|
|
|
* and/or modify it under the terms of the GNU Affero General Public License
|
|
|
|
|
* as published by the Free Software Foundation, either version 3 of the
|
|
|
|
|
* License, or (at your option) any later version.
|
2013-09-12 17:52:10 -05:00
|
|
|
*
|
2014-03-29 18:49:22 -05:00
|
|
|
* 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 Affero General Public License for more details.
|
2013-09-12 17:52:10 -05:00
|
|
|
*
|
2014-03-29 18:49:22 -05:00
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
* along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*
|
|
|
|
|
* Also, if your software can interact with users remotely through a computer
|
|
|
|
|
* network, you should also make sure that it provides a way for users to
|
|
|
|
|
* get its source. For example, if your program is a web application, its
|
|
|
|
|
* interface could display a "Source" link that leads users to an archive
|
|
|
|
|
* of the code. There are many ways you could offer source, and different
|
|
|
|
|
* solutions will be better for different programs; see section 13 for the
|
|
|
|
|
* specific requirements.
|
|
|
|
|
*
|
|
|
|
|
* You should also get your employer (if you work as a programmer) or school,
|
|
|
|
|
* if any, to sign a "copyright disclaimer" for the program, if necessary.
|
|
|
|
|
* For more information on this, and how to apply and follow the GNU AGPL, see
|
|
|
|
|
* <http://www.gnu.org/licenses/>.
|
2012-10-03 01:55:24 -05:00
|
|
|
*/
|
|
|
|
|
|
2013-09-12 17:52:10 -05:00
|
|
|
#ifndef OPENSHOT_TIMELINE_H
|
|
|
|
|
#define OPENSHOT_TIMELINE_H
|
|
|
|
|
|
2012-10-05 17:05:33 -05:00
|
|
|
#include <list>
|
2012-10-14 03:43:52 -05:00
|
|
|
#include <tr1/memory>
|
2012-11-07 17:45:13 -06:00
|
|
|
#include "Magick++.h"
|
2012-11-12 17:21:21 -06:00
|
|
|
#include "Cache.h"
|
2012-11-29 23:11:50 -06:00
|
|
|
#include "Color.h"
|
2012-10-05 17:05:33 -05:00
|
|
|
#include "Clip.h"
|
2014-01-05 23:28:21 -06:00
|
|
|
#include "Point.h"
|
2013-09-28 22:00:52 -05:00
|
|
|
#include "EffectBase.h"
|
2014-01-10 17:24:12 -06:00
|
|
|
#include "Effects.h"
|
2012-10-14 02:36:05 -05:00
|
|
|
#include "Fraction.h"
|
2012-10-05 01:58:27 -05:00
|
|
|
#include "Frame.h"
|
2012-10-03 01:55:24 -05:00
|
|
|
#include "KeyFrame.h"
|
2014-04-02 16:48:27 -05:00
|
|
|
#include "OpenMPUtilities.h"
|
2014-01-10 17:24:12 -06:00
|
|
|
#include "ReaderBase.h"
|
2014-01-05 22:37:11 -06:00
|
|
|
|
2012-10-03 01:55:24 -05:00
|
|
|
using namespace std;
|
|
|
|
|
using namespace openshot;
|
|
|
|
|
|
|
|
|
|
namespace openshot {
|
|
|
|
|
|
2012-10-10 01:58:13 -05:00
|
|
|
/// Comparison method for sorting clip pointers (by Position and Layer)
|
2013-09-10 12:59:06 -05:00
|
|
|
struct CompareClips{
|
2013-10-01 17:19:53 -05:00
|
|
|
bool operator()( Clip* lhs, Clip* rhs){
|
2013-10-06 16:55:38 -05:00
|
|
|
if( lhs->Position() < rhs->Position() ) return true;
|
|
|
|
|
if( lhs->Position() == rhs->Position() ) return lhs->Layer() < rhs->Layer();
|
|
|
|
|
return false;
|
2013-10-01 17:19:53 -05:00
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
/// Comparison method for sorting effect pointers (by Position, Layer, and Order)
|
|
|
|
|
struct CompareEffects{
|
|
|
|
|
bool operator()( EffectBase* lhs, EffectBase* rhs){
|
2013-10-06 16:55:38 -05:00
|
|
|
if( lhs->Position() < rhs->Position() ) return true;
|
|
|
|
|
if( lhs->Position() == rhs->Position() ) return lhs->Layer() < rhs->Layer();
|
|
|
|
|
if( lhs->Position() == rhs->Position() && lhs->Layer() == rhs->Layer() ) return lhs->Order() < rhs->Order();
|
|
|
|
|
return false;
|
2012-10-05 17:05:33 -05:00
|
|
|
}};
|
|
|
|
|
|
2012-10-03 01:55:24 -05:00
|
|
|
/**
|
2013-09-09 23:32:16 -05:00
|
|
|
* @brief This class represents a timeline
|
2012-10-03 01:55:24 -05:00
|
|
|
*
|
2013-09-14 22:52:29 -05:00
|
|
|
* The timeline is one of the <b>most important</b> features of a video editor, and controls all
|
2012-10-03 01:55:24 -05:00
|
|
|
* aspects of how video, image, and audio clips are combined together, and how the final
|
|
|
|
|
* video output will be rendered. It has a collection of layers and clips, that arrange,
|
2013-09-14 22:52:29 -05:00
|
|
|
* sequence, and generate the final video output.
|
2013-09-12 17:52:10 -05:00
|
|
|
*
|
2013-09-14 22:52:29 -05:00
|
|
|
* The <b>following graphic</b> displays a timeline, and how clips can be arranged, scaled, and layered together. It
|
|
|
|
|
* also demonstrates how the viewport can be scaled smaller than the canvas, which can be used to zoom and pan around the
|
|
|
|
|
* canvas (i.e. pan & scan).
|
|
|
|
|
* \image html /doc/images/Timeline_Layers.png
|
|
|
|
|
*
|
|
|
|
|
* The <b>following graphic</b> displays how the playhead determines which frames to combine and layer.
|
|
|
|
|
* \image html /doc/images/Playhead.png
|
|
|
|
|
*
|
|
|
|
|
* Lets take a look at what the code looks like:
|
2013-09-12 17:52:10 -05:00
|
|
|
* @code
|
|
|
|
|
* // Create a Timeline
|
|
|
|
|
* Timeline t(1280, // width
|
|
|
|
|
* 720, // height
|
2014-01-05 23:12:56 -06:00
|
|
|
* Fraction(25,1), // framerate
|
2013-09-12 17:52:10 -05:00
|
|
|
* 44100, // sample rate
|
|
|
|
|
* 2 // channels
|
|
|
|
|
* );
|
|
|
|
|
*
|
|
|
|
|
* // Create some clips
|
|
|
|
|
* Clip c1(new ImageReader("MyAwesomeLogo.jpeg"));
|
|
|
|
|
* Clip c2(new FFmpegReader("BackgroundVideo.webm"));
|
|
|
|
|
*
|
2013-09-12 23:41:49 -05:00
|
|
|
* // CLIP 1 (logo) - Set some clip properties (with Keyframes)
|
2013-09-13 17:11:38 -05:00
|
|
|
* c1.Position(0.0); // Set the position or location (in seconds) on the timeline
|
|
|
|
|
* c1.gravity = GRAVITY_LEFT; // Set the alignment / gravity of the clip (position on the screen)
|
|
|
|
|
* c1.scale = SCALE_CROP; // Set the scale mode (how the image is resized to fill the screen)
|
|
|
|
|
* c1.Layer(1); // Set the layer of the timeline (higher layers cover up images of lower layers)
|
|
|
|
|
* c1.Start(0.0); // Set the starting position of the video (trim the left side of the video)
|
|
|
|
|
* c1.End(16.0); // Set the ending position of the video (trim the right side of the video)
|
|
|
|
|
* c1.alpha.AddPoint(1, 0.0); // Set the alpha to transparent on frame #1
|
|
|
|
|
* c1.alpha.AddPoint(500, 0.0); // Keep the alpha transparent until frame #500
|
|
|
|
|
* c1.alpha.AddPoint(565, 1.0); // Animate the alpha from transparent to visible (between frame #501 and #565)
|
2013-09-12 17:52:10 -05:00
|
|
|
*
|
2013-09-12 23:41:49 -05:00
|
|
|
* // CLIP 2 (background video) - Set some clip properties (with Keyframes)
|
2013-09-13 17:11:38 -05:00
|
|
|
* c2.Position(0.0); // Set the position or location (in seconds) on the timeline
|
|
|
|
|
* c2.Start(10.0); // Set the starting position of the video (trim the left side of the video)
|
|
|
|
|
* c2.Layer(0); // Set the layer of the timeline (higher layers cover up images of lower layers)
|
|
|
|
|
* c2.alpha.AddPoint(1, 1.0); // Set the alpha to visible on frame #1
|
|
|
|
|
* c2.alpha.AddPoint(150, 0.0); // Animate the alpha to transparent (between frame 2 and frame #150)
|
|
|
|
|
* c2.alpha.AddPoint(360, 0.0, LINEAR); // Keep the alpha transparent until frame #360
|
|
|
|
|
* c2.alpha.AddPoint(384, 1.0); // Animate the alpha to visible (between frame #360 and frame #384)
|
2013-09-12 17:52:10 -05:00
|
|
|
*
|
|
|
|
|
* // Add clips to timeline
|
|
|
|
|
* t.AddClip(&c1);
|
|
|
|
|
* t.AddClip(&c2);
|
|
|
|
|
*
|
|
|
|
|
* // Open the timeline reader
|
|
|
|
|
* t.Open();
|
|
|
|
|
*
|
|
|
|
|
* // Get frame number 1 from the timeline (This will generate a new frame, made up from the previous clips and settings)
|
|
|
|
|
* tr1::shared_ptr<Frame> f = t.GetFrame(1);
|
|
|
|
|
*
|
|
|
|
|
* // Now that we have an openshot::Frame object, lets have some fun!
|
|
|
|
|
* f->Display(); // Display the frame on the screen
|
|
|
|
|
*
|
|
|
|
|
* // Close the timeline reader
|
|
|
|
|
* t.Close();
|
|
|
|
|
* @endcode
|
2012-10-03 01:55:24 -05:00
|
|
|
*/
|
2013-09-08 16:40:57 -05:00
|
|
|
class Timeline : public ReaderBase {
|
2012-10-03 01:55:24 -05:00
|
|
|
private:
|
2013-12-18 21:55:43 -06:00
|
|
|
bool is_open; ///<Is Timeline Open?
|
2012-10-05 17:05:33 -05:00
|
|
|
list<Clip*> clips; ///<List of clips on this timeline
|
2012-12-03 22:55:46 -06:00
|
|
|
list<Clip*> closing_clips; ///<List of clips that need to be closed
|
2012-10-09 02:09:44 -05:00
|
|
|
map<Clip*, Clip*> open_clips; ///<List of 'opened' clips on this timeline
|
2013-09-28 22:00:52 -05:00
|
|
|
list<EffectBase*> effects; ///<List of clips on this timeline
|
2012-11-12 17:21:21 -06:00
|
|
|
Cache final_cache; ///<Final cache of timeline frames
|
2012-10-05 17:05:33 -05:00
|
|
|
|
2012-11-16 17:29:12 -06:00
|
|
|
/// Process a new layer of video or audio
|
2012-11-29 17:28:22 -06:00
|
|
|
void add_layer(tr1::shared_ptr<Frame> new_frame, Clip* source_clip, int clip_frame_number, int timeline_frame_number);
|
2012-11-16 17:29:12 -06:00
|
|
|
|
2014-01-08 01:43:58 -06:00
|
|
|
/// Apply JSON Diffs to various objects contained in this timeline
|
|
|
|
|
void apply_json_to_clips(Json::Value change) throw(InvalidJSONKey); ///<Apply JSON diff to clips
|
|
|
|
|
void apply_json_to_effects(Json::Value change) throw(InvalidJSONKey); ///<Apply JSON diff to effects
|
|
|
|
|
void apply_json_to_timeline(Json::Value change) throw(InvalidJSONKey); ///<Apply JSON diff to timeline properties
|
|
|
|
|
|
2012-10-05 17:05:33 -05:00
|
|
|
/// Calculate time of a frame number, based on a framerate
|
2014-01-05 22:37:11 -06:00
|
|
|
float calculate_time(int number, Fraction rate);
|
2012-10-03 01:55:24 -05:00
|
|
|
|
2013-10-06 18:11:33 -05:00
|
|
|
/// Apply effects to the source frame (if any)
|
|
|
|
|
tr1::shared_ptr<Frame> apply_effects(tr1::shared_ptr<Frame> frame, int timeline_frame_number, int layer);
|
|
|
|
|
|
2012-11-16 17:29:12 -06:00
|
|
|
/// Compare 2 floating point numbers for equality
|
|
|
|
|
bool isEqual(double a, double b);
|
2012-11-07 17:45:13 -06:00
|
|
|
|
2012-10-09 02:09:44 -05:00
|
|
|
/// Update the list of 'opened' clips
|
|
|
|
|
void update_open_clips(Clip *clip, bool is_open);
|
|
|
|
|
|
2012-12-03 22:55:46 -06:00
|
|
|
/// Update the list of 'closed' clips
|
|
|
|
|
void update_closed_clips();
|
|
|
|
|
|
2012-10-03 01:55:24 -05:00
|
|
|
public:
|
|
|
|
|
|
2013-09-12 17:52:10 -05:00
|
|
|
/// @brief Default Constructor for the timeline (which sets the canvas width and height and FPS)
|
|
|
|
|
/// @param width The width of the timeline (and thus, the generated openshot::Frame objects)
|
|
|
|
|
/// @param height The height of the timeline (and thus, the generated openshot::Frame objects)
|
|
|
|
|
/// @param fps The frames rate of the timeline
|
|
|
|
|
/// @param sample_rate The sample rate of the timeline's audio
|
|
|
|
|
/// @param channels The number of audio channels of the timeline
|
2014-01-05 22:37:11 -06:00
|
|
|
Timeline(int width, int height, Fraction fps, int sample_rate, int channels);
|
2012-10-03 01:55:24 -05:00
|
|
|
|
2013-09-12 17:52:10 -05:00
|
|
|
/// @brief Add an openshot::Clip to the timeline
|
|
|
|
|
/// @param clip Add an openshot::Clip to the timeline. A clip can contain any type of Reader.
|
2013-10-01 17:19:53 -05:00
|
|
|
void AddClip(Clip* clip) throw(ReaderClosed);
|
2012-10-10 01:07:47 -05:00
|
|
|
|
2013-09-28 22:00:52 -05:00
|
|
|
/// @brief Add an effect to the timeline
|
|
|
|
|
/// @param effect Add an effect to the timeline. An effect can modify the audio or video of an openshot::Frame.
|
|
|
|
|
void AddEffect(EffectBase* effect);
|
2013-02-13 02:46:55 -06:00
|
|
|
|
2013-09-28 22:00:52 -05:00
|
|
|
/// Return a list of clips on the timeline
|
|
|
|
|
list<Clip*> Clips() { return clips; };
|
|
|
|
|
|
|
|
|
|
/// Close the timeline reader (and any resources it was consuming)
|
2012-10-10 01:07:47 -05:00
|
|
|
void Close();
|
|
|
|
|
|
2013-09-28 22:00:52 -05:00
|
|
|
/// Return the list of effects on the timeline
|
|
|
|
|
list<EffectBase*> Effects() { return effects; };
|
|
|
|
|
|
2012-10-05 01:58:27 -05:00
|
|
|
/// Get an openshot::Frame object for a specific frame number of this timeline.
|
|
|
|
|
///
|
|
|
|
|
/// @returns The requested frame (containing the image)
|
2013-09-12 17:52:10 -05:00
|
|
|
/// @param requested_frame The frame number that is requested.
|
2012-10-14 03:43:52 -05:00
|
|
|
tr1::shared_ptr<Frame> GetFrame(int requested_frame) throw(ReaderClosed);
|
2012-10-03 01:55:24 -05:00
|
|
|
|
2012-10-05 01:58:27 -05:00
|
|
|
// Curves for the viewport
|
|
|
|
|
Keyframe viewport_scale; ///<Curve representing the scale of the viewport (0 to 100)
|
|
|
|
|
Keyframe viewport_x; ///<Curve representing the x coordinate for the viewport
|
|
|
|
|
Keyframe viewport_y; ///<Curve representing the y coordinate for the viewport
|
2012-10-10 01:07:47 -05:00
|
|
|
|
2012-11-29 17:28:22 -06:00
|
|
|
// Background color
|
|
|
|
|
Color color; ///<Background color of timeline canvas
|
|
|
|
|
|
2013-12-18 21:55:43 -06:00
|
|
|
/// Determine if reader is open or closed
|
|
|
|
|
bool IsOpen() { return is_open; };
|
|
|
|
|
|
2013-12-07 21:09:55 -06:00
|
|
|
/// Get and Set JSON methods
|
|
|
|
|
string Json(); ///< Generate JSON string of this object
|
|
|
|
|
void SetJson(string value) throw(InvalidJSON); ///< Load JSON string into this object
|
|
|
|
|
Json::Value JsonValue(); ///< Generate Json::JsonValue for this object
|
2014-01-05 22:37:11 -06:00
|
|
|
void SetJsonValue(Json::Value root) throw(InvalidFile, ReaderClosed); ///< Load Json::JsonValue into this object
|
2013-12-07 21:09:55 -06:00
|
|
|
|
2014-01-08 01:43:58 -06:00
|
|
|
/// @brief Apply a special formatted JSON object, which represents a change to the timeline (add, update, delete)
|
|
|
|
|
/// This is primarily designed to keep the timeline (and its child objects... such as clips and effects) in sync
|
|
|
|
|
/// with another application... such as OpenShot Video Editor (http://www.openshot.org).
|
|
|
|
|
/// @param value A JSON string containing a key, value, and type of change.
|
|
|
|
|
void ApplyJsonDiff(string value) throw(InvalidJSON, InvalidJSONKey);
|
|
|
|
|
|
2012-10-10 01:07:47 -05:00
|
|
|
/// Open the reader (and start consuming resources)
|
|
|
|
|
void Open();
|
|
|
|
|
|
2013-09-28 22:00:52 -05:00
|
|
|
/// @brief Remove an openshot::Clip from the timeline
|
|
|
|
|
/// @param clip Remove an openshot::Clip from the timeline.
|
|
|
|
|
void RemoveClip(Clip* clip);
|
|
|
|
|
|
|
|
|
|
/// @brief Remove an effect from the timeline
|
|
|
|
|
/// @param effect Remove an effect from the timeline.
|
|
|
|
|
void RemoveEffect(EffectBase* effect);
|
|
|
|
|
|
2012-10-10 01:07:47 -05:00
|
|
|
/// Sort clips by position on the timeline
|
|
|
|
|
void SortClips();
|
|
|
|
|
|
2013-10-01 17:19:53 -05:00
|
|
|
/// Sort effects by position on the timeline
|
|
|
|
|
void SortEffects();
|
|
|
|
|
|
2012-10-03 01:55:24 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|