diff --git a/include/OpenShot.h b/include/OpenShot.h
index b2e9482b..5255b6cc 100644
--- a/include/OpenShot.h
+++ b/include/OpenShot.h
@@ -122,5 +122,9 @@
#include "TextReader.h"
#include "Timeline.h"
+/* Effects */
+#include "effects/ChromaKey.h"
+#include "effects/Negate.h"
+
#endif
diff --git a/include/Timeline.h b/include/Timeline.h
index dfc49e8d..9c931af6 100644
--- a/include/Timeline.h
+++ b/include/Timeline.h
@@ -158,6 +158,9 @@ namespace openshot {
/// Calculate time of a frame number, based on a framerate
float calculate_time(int number, Framerate rate);
+ /// Apply effects to the source frame (if any)
+ tr1::shared_ptr apply_effects(tr1::shared_ptr frame, int timeline_frame_number, int layer);
+
/// Calculate the # of samples per video frame (for a specific frame number)
int GetSamplesPerFrame(int frame_number);
diff --git a/src/Main.cpp b/src/Main.cpp
index c05d4209..4f4d7945 100644
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -46,42 +46,85 @@ using namespace tr1;
int main(int argc, char* argv[])
{
// Create a empty clip
- Timeline t1(720, 480, Framerate(24,1), 44100, 2);
- DummyReader dr1(Framerate(24,1),720,480, 41000, 2, 10.0);
+ Timeline timeline_animation(720, 480, Framerate(24,1), 44100, 2);
- // Change some properties
- Clip c1a(&dr1);
- c1a.Layer(1);
- c1a.Position(5.0);
- c1a.Start(5);
- c1a.End(10.5);
- t1.AddClip(&c1a);
+ // Add Sky Layer
+ ImageReader sky_reader("/home/jonathan/Animation/sky.png");
+ Clip clip_sky(&sky_reader);
+ clip_sky.Layer(0);
+ clip_sky.Position(0.0);
+ clip_sky.End(30);
+ timeline_animation.AddClip(&clip_sky);
- Clip c2a(&dr1);
- c2a.Layer(1);
- c2a.Position(5.0);
- c2a.Start(1);
- c2a.End(10.5);
- t1.AddClip(&c2a);
+ // Add Hills Layer
+ ImageReader hills_reader("/home/jonathan/Animation/hills.png");
+ Clip clip_hills(&hills_reader);
+ clip_hills.Layer(2);
+ clip_hills.Position(0.0);
+ clip_hills.End(30);
+ clip_hills.gravity = GRAVITY_BOTTOM;
+ clip_hills.scale = SCALE_CROP;
+ clip_hills.location_y = Keyframe(0.40);
+ timeline_animation.AddClip(&clip_hills);
- Clip c3a(&dr1);
- c3a.Layer(1);
- c3a.Position(5.0);
- c3a.Start(3);
- c3a.End(10.5);
- t1.AddClip(&c3a);
+ // Add Sun Layer
+ ImageReader sun_reader("/home/jonathan/Animation/sun.png");
+ Clip clip_sun(&sun_reader);
+ clip_sun.Layer(3);
+ clip_sun.Position(0.0);
+ clip_sun.End(30);
+ clip_sun.gravity = GRAVITY_TOP_RIGHT;
+ clip_sun.scale = SCALE_NONE;
+ clip_sun.location_y = Keyframe(0.025);
+ clip_sun.location_x = Keyframe(-0.025);
+ timeline_animation.AddClip(&clip_sun);
+ // Add Cloud 1 Layer
+ ImageReader cloud_reader("/home/jonathan/Animation/cloud.png");
+ Clip clip_cloud(&cloud_reader);
+ clip_cloud.Layer(4);
+ clip_cloud.Position(0.0);
+ clip_cloud.End(30);
+ clip_cloud.gravity = GRAVITY_TOP_LEFT;
+ clip_cloud.scale = SCALE_NONE;
+ clip_cloud.location_y = Keyframe(0.025);
+ clip_cloud.location_x = Keyframe(0.025);
+ timeline_animation.AddClip(&clip_cloud);
- list::iterator clip_itr;
- list myClips = t1.Clips();
- for (clip_itr=myClips.begin(); clip_itr != myClips.end(); ++clip_itr)
- {
- // Get clip object from the iterator
- Clip *clip = (*clip_itr);
+ // Add Cloud 2 Layer
+ ImageReader cloud_reader2("/home/jonathan/Animation/cloud.png");
+ Clip clip_cloud2(&cloud_reader2);
+ clip_cloud2.Layer(4);
+ clip_cloud2.Position(0.0);
+ clip_cloud2.End(30);
+ clip_cloud2.gravity = GRAVITY_TOP_LEFT;
+ clip_cloud2.scale = SCALE_NONE;
+ clip_cloud2.location_y = Keyframe(0.2);
+ clip_cloud2.location_x = Keyframe(0.25);
+ timeline_animation.AddClip(&clip_cloud2);
- // Open or Close this clip, based on if it's intersecting or not
- cout << clip->Start() << endl;
- }
+ // Add Cloud 3 Layer
+ ImageReader cloud_reader3("/home/jonathan/Animation/cloud.png");
+ Clip clip_cloud3(&cloud_reader3);
+ clip_cloud3.Layer(4);
+ clip_cloud3.Position(0.0);
+ clip_cloud3.End(30);
+ clip_cloud3.gravity = GRAVITY_TOP_LEFT;
+ clip_cloud3.scale = SCALE_NONE;
+ clip_cloud3.alpha = Keyframe(0.2);
+ clip_cloud3.location_y = Keyframe(0.025);
+ clip_cloud3.location_x = Keyframe(0.65);
+ timeline_animation.AddClip(&clip_cloud3);
+
+ // Add Effect to cloud layer
+ Negate effect;
+ effect.Position(0);
+ effect.End(30.0);
+ effect.Layer(3);
+ timeline_animation.AddEffect(&effect);
+
+ // View frames
+ timeline_animation.GetFrame(1)->Display();
return 0;
diff --git a/src/Timeline.cpp b/src/Timeline.cpp
index d5506876..a51be1d7 100644
--- a/src/Timeline.cpp
+++ b/src/Timeline.cpp
@@ -103,6 +103,44 @@ float Timeline::calculate_time(int number, Framerate rate)
return float(number - 1) / raw_fps;
}
+// Apply effects to the source frame (if any)
+tr1::shared_ptr Timeline::apply_effects(tr1::shared_ptr frame, int timeline_frame_number, int layer)
+{
+ // Calculate time of frame
+ float requested_time = calculate_time(timeline_frame_number, fps);
+
+ // Find Effects at this position and layer
+ list::iterator effect_itr;
+ for (effect_itr=effects.begin(); effect_itr != effects.end(); ++effect_itr)
+ {
+ // Get clip object from the iterator
+ EffectBase *effect = (*effect_itr);
+
+ // Have we gone past the requested time?
+ if (effect->Position() > requested_time)
+ break;
+
+ // Does clip intersect the current requested time
+ float effect_duration = effect->End() - effect->Start();
+ bool does_effect_intersect = (effect->Position() <= requested_time && effect->Position() + effect_duration >= requested_time && effect->Layer() == layer);
+
+ // Clip is visible
+ if (does_effect_intersect)
+ {
+ // Determine the frame needed for this clip (based on the position on the timeline)
+ float time_diff = (requested_time - effect->Position()) + effect->Start();
+ int effect_frame_number = round(time_diff * fps.GetFPS()) + 1;
+
+ // Apply the effect to this frame
+ frame = effect->GetFrame(frame, effect_frame_number);
+ }
+
+ } // end effect loop
+
+ // Return modified frame
+ return frame;
+}
+
// Process a new layer of video or audio
void Timeline::add_layer(tr1::shared_ptr new_frame, Clip* source_clip, int clip_frame_number, int timeline_frame_number)
{
@@ -116,6 +154,9 @@ void Timeline::add_layer(tr1::shared_ptr new_frame, Clip* source_clip, in
if (!source_frame)
return;
+ /* Apply effects to the source frame (if any) */
+ source_frame = apply_effects(source_frame, timeline_frame_number, source_clip->Layer());
+
tr1::shared_ptr source_image;
/* COPY AUDIO - with correct volume */
@@ -158,8 +199,6 @@ void Timeline::add_layer(tr1::shared_ptr new_frame, Clip* source_clip, in
int source_width = source_image->columns();
int source_height = source_image->rows();
- /* APPLY EFFECTS */
-
/* ALPHA & OPACITY */
if (source_clip->alpha.GetValue(clip_frame_number) != 0)
{
@@ -410,18 +449,19 @@ tr1::shared_ptr Timeline::GetFrame(int requested_frame) throw(ReaderClose
else
{
// Minimum number of packets to process (for performance reasons)
- int minimum_frames = omp_get_num_procs();
+ //int minimum_frames = omp_get_num_procs() / 2;
+ int minimum_frames = 1;
//omp_set_num_threads(1);
omp_set_nested(true);
- #pragma omp parallel
+ #pragma xx omp parallel
{
- #pragma omp single
+ #pragma xx omp single
{
// Loop through all requested frames
for (int frame_number = requested_frame; frame_number < requested_frame + minimum_frames; frame_number++)
{
- #pragma omp task firstprivate(frame_number)
+ #pragma xx omp task firstprivate(frame_number)
{
// Create blank frame (which will become the requested frame)
tr1::shared_ptr new_frame(tr1::shared_ptr(new Frame(frame_number, width, height, "#000000", GetSamplesPerFrame(frame_number), channels)));
@@ -437,6 +477,10 @@ tr1::shared_ptr Timeline::GetFrame(int requested_frame) throw(ReaderClose
// Get clip object from the iterator
Clip *clip = (*clip_itr);
+ // Have we gone past the requested time?
+ if (clip->Position() > requested_time)
+ break;
+
// Does clip intersect the current requested time
float clip_duration = clip->End() - clip->Start();
bool does_clip_intersect = (clip->Position() <= requested_time && clip->Position() + clip_duration >= requested_time);