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);