diff --git a/include/Frame.h b/include/Frame.h index 61117437..d394752a 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -83,6 +83,9 @@ namespace openshot /// Add audio samples to a specific channel void AddAudio(int destChannel, int destStartSample, const float* source, int numSamples, float gainToApplyToSource); + /// Composite a new image on top of the existing image + void AddImage(tr1::shared_ptr new_image, float alpha); + /// Experimental method to add effects to this frame void AddEffect(string name); diff --git a/src/Clip.cpp b/src/Clip.cpp index 9564e10c..db4f1cab 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -302,11 +302,6 @@ tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame, // Get the length of the resampled buffer resampled_buffer_size = audio_cache->getNumSamples(); -// if (frame_number == 15) -// for (int channel = 0; channel < channels; channel++) -// for (int s = 0; s < resampled_buffer_size; s++) -// cout << s << "\t" << audio_cache->getSampleData(channel, s)[0] << endl; - // Just take the samples we need for the requested frame int start = (number_of_samples * (time.GetRepeatFraction(frame_number).num - 1)); if (start > 0) @@ -326,6 +321,13 @@ tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame, // Clean up buffer = NULL; + + // Determine next unique frame (after these repeating frames) + int next_unique_frame = time.GetInt(frame_number + (time.GetRepeatFraction(frame_number).den - time.GetRepeatFraction(frame_number).num) + 1); + if (next_unique_frame != new_frame_number) + // Overlay the next frame on top of this frame (to create a smoother slow motion effect) + new_frame->AddImage(file_reader->GetFrame(next_unique_frame)->GetImage(), float(time.GetRepeatFraction(frame_number).num) / float(time.GetRepeatFraction(frame_number).den)); + } else if (abs(delta) > 1 && abs(delta) < 100) { diff --git a/src/Frame.cpp b/src/Frame.cpp index 3c9279c0..11af0b2c 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -490,6 +490,33 @@ void Frame::AddImage(tr1::shared_ptr new_image, bool only_odd_lin height = image->rows(); } +// Composite a new image on top of the existing image +void Frame::AddImage(tr1::shared_ptr new_image, float alpha) +{ + // Replace image (if needed) + if (image->columns() == 1) + image = new_image; + else + { + // Calculate opacity of new image + int new_opacity = 65535.0f * (1.0 - alpha); + if (new_opacity < 0) + new_opacity = 0; // completely invisible + else if (new_opacity > 65535) + new_opacity = 65535; + + // Set opacity + new_image->opacity(new_opacity); + + // Composite image on top of current image + image->composite(*new_image.get(), 0, 0, Magick::DissolveCompositeOp); + } + + // Update height and width + width = image->columns(); + height = image->rows(); +} + // Add audio samples to a specific channel void Frame::AddAudio(int destChannel, int destStartSample, const float* source, int numSamples, float gainToApplyToSource = 1.0f) { diff --git a/src/Main.cpp b/src/Main.cpp index 7e5b4453..375b709b 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -16,101 +16,105 @@ void FrameReady(int number) int main() { -// // Create timeline -// Timeline t(640, 360, Framerate(24,1)); + // Create timeline + Timeline t(640, 360, Framerate(24,1)); + + // Add some clips + Clip c1(new FFmpegReader("/home/jonathan/Videos/sintel-1024-stereo.mp4")); + c1.Position(0.0); + + // LINEAR Reverse + //c1.time.AddPoint(1, 500, LINEAR); + //c1.time.AddPoint(500, 1, LINEAR); + + // LINEAR Slow Reverse (sounds wavy, due to periodic repeated frames) + //c1.time.AddPoint(1, 500, LINEAR); + //c1.time.AddPoint(500, 100, LINEAR); + + // LINEAR Slow Reverse X2 (smooth) + //c1.time.AddPoint(1, 500, LINEAR); + //c1.time.AddPoint(500, 250, LINEAR); + + // LINEAR Slow Reverse X4 (smooth) + c1.time.AddPoint(1, 500, LINEAR); + c1.time.AddPoint(750, 250, LINEAR); + + // LINEAR Fast Reverse (sounds wavy, due to periodic repeated frames) + //c1.time.AddPoint(1, 600, LINEAR); + //c1.time.AddPoint(500, 1, LINEAR); + + // LINEAR Slow Forward + //c1.time.AddPoint(1, 1000, LINEAR); + //c1.time.AddPoint(500, 1, LINEAR); + +// // BEZIER Reverse +// openshot::Point p1(1,500); +// p1.handle_left = Coordinate(1,500); +// p1.handle_right = Coordinate(250,500); // -// // Add some clips -// Clip c1(new FFmpegReader("/home/jonathan/Videos/sintel_trailer-720p.mp4")); -// c1.Position(0.0); +// openshot::Point p2(500,100); +// p1.handle_left = Coordinate(500,350); +// p1.handle_right = Coordinate(500,100); // -// // LINEAR Reverse -// //c1.time.AddPoint(1, 500, LINEAR); -// //c1.time.AddPoint(500, 1, LINEAR); -// -// // LINEAR Slow Reverse (sounds wavy, due to periodic repeated frames) -// //c1.time.AddPoint(1, 500, LINEAR); -// //c1.time.AddPoint(500, 100, LINEAR); -// -// // LINEAR Slow Reverse X2 (smooth) +// c1.time.AddPoint(p1); +// c1.time.AddPoint(p2); + // c1.time.AddPoint(1, 500, LINEAR); -// c1.time.AddPoint(500, 250, LINEAR); -// -// // LINEAR Fast Reverse (sounds wavy, due to periodic repeated frames) -// //c1.time.AddPoint(1, 600, LINEAR); -// //c1.time.AddPoint(500, 1, LINEAR); -// -// // LINEAR Slow Forward -// //c1.time.AddPoint(1, 1000, LINEAR); -// //c1.time.AddPoint(500, 1, LINEAR); -// -//// // BEZIER Reverse -//// openshot::Point p1(1,500); -//// p1.handle_left = Coordinate(1,500); -//// p1.handle_right = Coordinate(250,500); -//// -//// openshot::Point p2(500,100); -//// p1.handle_left = Coordinate(500,350); -//// p1.handle_right = Coordinate(500,100); -//// -//// c1.time.AddPoint(p1); -//// c1.time.AddPoint(p2); -// -//// c1.time.AddPoint(1, 500, LINEAR); -//// c1.time.AddPoint(500, 1, LINEAR); -//// c1.time.AddPoint(1, 500, LINEAR); -//// c1.time.AddPoint(200, 200); -//// c1.time.AddPoint(500, 500, LINEAR); -// c1.time.PrintValues(); -// -// // Add clips -// t.AddClip(&c1); -// -// -// // Create a writer -// FFmpegWriter w("/home/jonathan/output.webm"); -// w.DisplayInfo(); -// -// // Set options -// //w.SetAudioOptions(true, "libmp3lame", 44100, 2, 128000, false); -// w.SetAudioOptions(true, "libvorbis", 44100, 2, 128000, false); -// w.SetVideoOptions(true, "libvpx", Fraction(24, 1), 640, 360, Fraction(1,1), false, false, 2000000); -// -// // Prepare Streams -// w.PrepareStreams(); -// -// // Write header -// w.WriteHeader(); -// -// // Output stream info -// w.OutputStreamInfo(); -// -// for (int frame = 1; frame <= 500; frame++) -// { -// tr1::shared_ptr f = t.GetFrame(frame); -// if (f) -// { -// //f->AddOverlayNumber(0); -// //if (frame >= 1 && frame <= 22) -// // f->DisplayWaveform(); -// -// // Write frame -// //cout << "queue frame " << frame << endl; -// cout << "queue frame " << frame << " (" << f->number << ", " << f << ")" << endl; -// w.WriteFrame(f); -// } -// } -// -// // Write Footer -// w.WriteTrailer(); -// -// // Close writer & reader -// w.Close(); -// -// // Close timeline -// t.Close(); -// -// cout << "Successfully Finished Timeline DEMO" << endl; -// return 0; +// c1.time.AddPoint(500, 1, LINEAR); +// c1.time.AddPoint(1, 500, LINEAR); +// c1.time.AddPoint(200, 200); +// c1.time.AddPoint(500, 500, LINEAR); + c1.time.PrintValues(); + + // Add clips + t.AddClip(&c1); + + + // Create a writer + FFmpegWriter w("/home/jonathan/output.webm"); + w.DisplayInfo(); + + // Set options + //w.SetAudioOptions(true, "libmp3lame", 44100, 2, 128000, false); + w.SetAudioOptions(true, "libvorbis", 44100, 2, 128000, false); + w.SetVideoOptions(true, "libvpx", Fraction(24, 1), 640, 360, Fraction(1,1), false, false, 2000000); + + // Prepare Streams + w.PrepareStreams(); + + // Write header + w.WriteHeader(); + + // Output stream info + w.OutputStreamInfo(); + + for (int frame = 1; frame <= 100; frame++) + { + tr1::shared_ptr f = t.GetFrame(frame); + if (f) + { + //f->AddOverlayNumber(0); + //if (frame >= 1 && frame <= 22) + // f->DisplayWaveform(); + + // Write frame + //cout << "queue frame " << frame << endl; + cout << "queue frame " << frame << " (" << f->number << ", " << f << ")" << endl; + w.WriteFrame(f); + } + } + + // Write Footer + w.WriteTrailer(); + + // Close writer & reader + w.Close(); + + // Close timeline + t.Close(); + + cout << "Successfully Finished Timeline DEMO" << endl; + return 0; @@ -174,63 +178,63 @@ int main() - // Create a writer - FFmpegWriter w("/home/jonathan/output.webm"); - w.DisplayInfo(); - - // Set options - w.SetAudioOptions(true, "libvorbis", 44100, 2, 128000, false); - //w.SetAudioOptions(true, "libmp3lame", 44100, 2, 128000, false); - - w.SetVideoOptions(true, "libvpx", Fraction(24,1), 320, 240, Fraction(1,1), false, false, 2000000); - //w.SetVideoOptions(true, "libx264", Fraction(24,1), 320, 240, Fraction(1,1), false, false, 2000000); - //w.SetVideoOptions(true, "libtheora", Fraction(24,1), 320, 240, Fraction(1,1), false, false, 2000000); - - // Prepare Streams - w.PrepareStreams(); - - // Set Options -// w.SetOption(VIDEO_STREAM, "quality", "good"); -// w.SetOption(VIDEO_STREAM, "g", "120"); -// w.SetOption(VIDEO_STREAM, "qmin", "11"); -// w.SetOption(VIDEO_STREAM, "qmax", "51"); -// w.SetOption(VIDEO_STREAM, "profile", "0"); -// w.SetOption(VIDEO_STREAM, "speed", "0"); -// w.SetOption(VIDEO_STREAM, "level", "216"); -// w.SetOption(VIDEO_STREAM, "rc_lookahead", "16"); -// w.SetOption(VIDEO_STREAM, "rc_min_rate", "100000"); -// w.SetOption(VIDEO_STREAM, "rc_max_rate", "24000000"); -// w.SetOption(VIDEO_STREAM, "slices", "4"); -// w.SetOption(VIDEO_STREAM, "arnr_max_frames", "7"); -// w.SetOption(VIDEO_STREAM, "arnr_strength", "5"); -// w.SetOption(VIDEO_STREAM, "arnr_type", "3"); - - // Write header - w.WriteHeader(); - - // Output stream info - w.OutputStreamInfo(); - - //Frame *f = r.GetFrame(1); - - //for (int frame = 131; frame >= 1; frame--) - for (int frame = 1; frame <= 300; frame++) - { - tr1::shared_ptr f = r.GetFrame(frame); - //f->AddOverlayNumber(0); - //f->Display(); - - // Write frame - cout << "queue frame " << frame << endl; - w.WriteFrame(f); - } - - // Write Footer - w.WriteTrailer(); - - // Close writer & reader - w.Close(); - r.Close(); +// // Create a writer +// FFmpegWriter w("/home/jonathan/output.webm"); +// w.DisplayInfo(); +// +// // Set options +// w.SetAudioOptions(true, "libvorbis", 44100, 2, 128000, false); +// //w.SetAudioOptions(true, "libmp3lame", 44100, 2, 128000, false); +// +// w.SetVideoOptions(true, "libvpx", Fraction(24,1), 320, 240, Fraction(1,1), false, false, 2000000); +// //w.SetVideoOptions(true, "libx264", Fraction(24,1), 320, 240, Fraction(1,1), false, false, 2000000); +// //w.SetVideoOptions(true, "libtheora", Fraction(24,1), 320, 240, Fraction(1,1), false, false, 2000000); +// +// // Prepare Streams +// w.PrepareStreams(); +// +// // Set Options +//// w.SetOption(VIDEO_STREAM, "quality", "good"); +//// w.SetOption(VIDEO_STREAM, "g", "120"); +//// w.SetOption(VIDEO_STREAM, "qmin", "11"); +//// w.SetOption(VIDEO_STREAM, "qmax", "51"); +//// w.SetOption(VIDEO_STREAM, "profile", "0"); +//// w.SetOption(VIDEO_STREAM, "speed", "0"); +//// w.SetOption(VIDEO_STREAM, "level", "216"); +//// w.SetOption(VIDEO_STREAM, "rc_lookahead", "16"); +//// w.SetOption(VIDEO_STREAM, "rc_min_rate", "100000"); +//// w.SetOption(VIDEO_STREAM, "rc_max_rate", "24000000"); +//// w.SetOption(VIDEO_STREAM, "slices", "4"); +//// w.SetOption(VIDEO_STREAM, "arnr_max_frames", "7"); +//// w.SetOption(VIDEO_STREAM, "arnr_strength", "5"); +//// w.SetOption(VIDEO_STREAM, "arnr_type", "3"); +// +// // Write header +// w.WriteHeader(); +// +// // Output stream info +// w.OutputStreamInfo(); +// +// //Frame *f = r.GetFrame(1); +// +// //for (int frame = 131; frame >= 1; frame--) +// for (int frame = 1; frame <= 300; frame++) +// { +// tr1::shared_ptr f = r.GetFrame(frame); +// //f->AddOverlayNumber(0); +// //f->Display(); +// +// // Write frame +// cout << "queue frame " << frame << endl; +// w.WriteFrame(f); +// } +// +// // Write Footer +// w.WriteTrailer(); +// +// // Close writer & reader +// w.Close(); +// r.Close(); cout << "Successfully executed Main.cpp!" << endl;