diff --git a/include/Clip.h b/include/Clip.h index 987a447f..e000857c 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -72,9 +72,6 @@ namespace openshot { // File Reader object FileReaderBase* file_reader; - // Internal frame mapper (to map between different frame rates) - FrameMapper* frame_map; - /// Adjust frame number minimum value int adjust_frame_number_minimum(int frame_number); @@ -84,9 +81,6 @@ namespace openshot { /// Get file extension string get_file_extension(string path); - /// Get the new frame number, based on the Framemapper, or return the number passed in - int get_framerate_mapped_frame(int original_frame_number); - /// Get the new frame number, based on a time map curve (used to increase speed, change direction, etc...) int get_time_mapped_frame(int original_frame_number); @@ -122,9 +116,6 @@ namespace openshot { /// @param[requested_frame] number The frame number that is requested. tr1::shared_ptr GetFrame(int requested_frame) throw(ReaderClosed); - /// Map frame rate of this clip to a different frame rate - void MapFrames(Framerate fps, Pulldown_Method pulldown); - /// Open the internal reader void Open() throw(InvalidFile); diff --git a/include/Frame.h b/include/Frame.h index a8adda65..5d0c7332 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -15,6 +15,7 @@ #include #include #include +#include #include "Magick++.h" #include "JuceLibraryCode/JuceHeader.h" #include "AudioBufferSource.h" @@ -34,9 +35,9 @@ namespace openshot class Frame { private: - Magick::Image *image; - Magick::Image *wave_image; - juce::AudioSampleBuffer *audio; + tr1::shared_ptr image; + tr1::shared_ptr wave_image; + tr1::shared_ptr audio; Fraction pixel_ratio; int sample_rate; int channels; @@ -59,9 +60,6 @@ namespace openshot /// Constructor - image & audio Frame(int number, int width, int height, string color, int samples, int channels); - /// Destructor - ~Frame(); - /// Copy constructor Frame ( const Frame &other ); @@ -75,7 +73,7 @@ namespace openshot void AddImage(int width, int height, const string map, const Magick::StorageType type, const void *pixels_); /// Add (or replace) pixel data to the frame - void AddImage(Magick::Image* new_image); + void AddImage(tr1::shared_ptr new_image); /// Add audio samples to a specific channel void AddAudio(int destChannel, int destStartSample, const float* source, int numSamples, float gainToApplyToSource); @@ -95,9 +93,6 @@ namespace openshot /// Copy data and pointers from another Frame instance void DeepCopy(const Frame& other); - /// Deallocate image and audio memory - void DeletePointers(); - /// Display the frame image to the screen (primarily used for debugging reasons) void Display(); @@ -123,7 +118,7 @@ namespace openshot int64 GetBytes(); /// Get pointer to Magick++ image object - Magick::Image* GetImage(); + tr1::shared_ptr GetImage(); /// Get pixel data (as packets) const Magick::PixelPacket* GetPixels(); @@ -135,7 +130,7 @@ namespace openshot int GetHeight(); /// Get an audio waveform image - Magick::Image* GetWaveform(int width, int height); + tr1::shared_ptr GetWaveform(int width, int height); /// Get an audio waveform image pixels const Magick::PixelPacket* GetWaveformPixels(int width, int height); diff --git a/include/FrameMapper.h b/include/FrameMapper.h index af21d8f2..788cfb7c 100644 --- a/include/FrameMapper.h +++ b/include/FrameMapper.h @@ -11,7 +11,10 @@ #include #include #include +#include +#include "../include/Cache.h" #include "../include/FileReaderBase.h" +#include "../include/Frame.h" #include "../include/FrameRate.h" #include "../include/Exceptions.h" #include "../include/KeyFrame.h" @@ -66,6 +69,8 @@ namespace openshot int frame_end; int sample_end; + + int total; }; /** @@ -97,9 +102,8 @@ namespace openshot * assert(frame2.Odd.Frame == 2); * \endcode */ - class FrameMapper { + class FrameMapper : public FileReaderBase { private: - int m_length; // Length in frames of a video file vector fields; // List of all fields vector frames; // List of all frames bool field_toggle; // Internal odd / even toggle (used when building the mapping) @@ -107,6 +111,7 @@ namespace openshot Framerate target; // The target frame rate Pulldown_Method pulldown; // The pull-down technique FileReaderBase *reader; // The source video reader + Cache final_cache; // Cache of actual Frame objects // Internal methods used by init void AddField(int frame); @@ -125,8 +130,19 @@ namespace openshot /// Default constructor for FrameMapper class FrameMapper(FileReaderBase *reader, Framerate target, Pulldown_Method pulldown); + /// Close the internal reader + void Close(); + /// Get a frame based on the target frame rate and the new frame number of a frame - MappedFrame GetFrame(int TargetFrameNumber) throw(OutOfBoundsFrame); + MappedFrame GetMappedFrame(int TargetFrameNumber) throw(OutOfBoundsFrame); + + /// This method is required for all derived classes of FileReaderBase, and return the + /// openshot::Frame object, which contains the image and audio information for that + /// frame of video. + /// + /// @returns The requested frame of video + /// @param[in] number The frame number that is requested. + tr1::shared_ptr GetFrame(int requested_frame) throw(ReaderClosed); /// Get the target framerate Framerate TargetFPS() { return target; }; @@ -181,6 +197,9 @@ namespace openshot */ void MapTime(Keyframe new_time) throw(OutOfBoundsFrame); + /// Open the internal reader + void Open() throw(InvalidFile); + /// Print all of the original frames and which new frames they map to void PrintMapping(); diff --git a/src/Clip.cpp b/src/Clip.cpp index 6922c143..ce5adbea 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -50,7 +50,6 @@ void Clip::init_settings() perspective_c4_y = Keyframe(-1.0); // Default pointers - frame_map = NULL; file_reader = NULL; } @@ -154,10 +153,7 @@ float Clip::End() { // Determine the FPS fo this clip float fps = 24.0; - if (frame_map) - // frame mapper - fps = frame_map->TargetFPS().GetFPS(); - else if (file_reader) + if (file_reader) // file reader fps = file_reader->info.fps.ToFloat(); @@ -175,11 +171,8 @@ tr1::shared_ptr Clip::GetFrame(int requested_frame) throw(ReaderClosed) // Adjust out of bounds frame number requested_frame = adjust_frame_number_minimum(requested_frame); - // Get mapped frame number (or just return the same number). This is used to change framerates. - int frame_number = get_framerate_mapped_frame(requested_frame); - // Get time mapped frame number (used to increase speed, change direction, etc...) - frame_number = adjust_frame_number_minimum(get_time_mapped_frame(frame_number)); + int frame_number = adjust_frame_number_minimum(get_time_mapped_frame(requested_frame)); // Now that we have re-mapped what frame number is needed, go and get the frame pointer tr1::shared_ptr frame = file_reader->GetFrame(frame_number); @@ -191,20 +184,6 @@ tr1::shared_ptr Clip::GetFrame(int requested_frame) throw(ReaderClosed) return frame; } -// Map frame rate of this clip to a different frame rate -void Clip::MapFrames(Framerate fps, Pulldown_Method pulldown) -{ - // Check for a valid file reader (required to re-map it's frame rate) - if (file_reader) - { - // Get original framerate - Framerate original_fps(file_reader->info.fps.num, file_reader->info.fps.den); - - // Create and Set FrameMapper object - frame_map = new FrameMapper(file_reader, fps, pulldown); - } -} - // Get file extension string Clip::get_file_extension(string path) { @@ -212,20 +191,6 @@ string Clip::get_file_extension(string path) return path.substr(path.find_last_of(".") + 1); } -// Get the new frame number, based on the Framemapper, or return the number passed in -int Clip::get_framerate_mapped_frame(int original_frame_number) -{ - // Check for a frame mapper (which is optinal) - if (frame_map) - { - // Get new frame number - return frame_map->GetFrame(original_frame_number).Odd.Frame; - - } else - // return passed in parameter - return original_frame_number; -} - // Get the new frame number, based on a time map curve (used to increase speed, change direction, etc...) int Clip::get_time_mapped_frame(int original_frame_number) { diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp index b209d10a..426ac402 100644 --- a/src/DummyReader.cpp +++ b/src/DummyReader.cpp @@ -24,7 +24,7 @@ void DummyReader::Open() throw(InvalidFile) image_frame = tr1::shared_ptr(new Frame(1, width, height, "#000000", sample_rate, channels)); // Add Image data to frame - image_frame->AddImage(new Magick::Image(Magick::Geometry(width, height), Magick::Color("#000000"))); + image_frame->AddImage(tr1::shared_ptr(new Magick::Image(Magick::Geometry(width, height), Magick::Color("#000000")))); // Update image properties info.has_audio = false; diff --git a/src/Frame.cpp b/src/Frame.cpp index 426c3be0..598e8072 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -10,11 +10,11 @@ using namespace std; using namespace openshot; // Constructor - blank frame (300x200 blank image, 48kHz audio silence) -Frame::Frame() : number(1), image(0), audio(0), pixel_ratio(1,1), sample_rate(48000), channels(2), wave_image(NULL) +Frame::Frame() : number(1), pixel_ratio(1,1), sample_rate(48000), channels(2) { // Init the image magic and audio buffer - image = new Magick::Image(Magick::Geometry(1,1), Magick::Color("red")); - audio = new juce::AudioSampleBuffer(channels, 1600); + image = tr1::shared_ptr(new Magick::Image(Magick::Geometry(1,1), Magick::Color("red"))); + audio = tr1::shared_ptr(new juce::AudioSampleBuffer(channels, 1600)); // initialize the audio samples to zero (silence) audio->clear(); @@ -22,11 +22,11 @@ Frame::Frame() : number(1), image(0), audio(0), pixel_ratio(1,1), sample_rate(48 // Constructor - image only (48kHz audio silence) Frame::Frame(int number, int width, int height, string color) - : number(number), image(0), audio(0), pixel_ratio(1,1), sample_rate(48000), channels(2), wave_image(NULL) + : number(number), pixel_ratio(1,1), sample_rate(48000), channels(2) { // Init the image magic and audio buffer - image = new Magick::Image(Magick::Geometry(1, 1), Magick::Color(color)); - audio = new juce::AudioSampleBuffer(channels, 1600); + image = tr1::shared_ptr(new Magick::Image(Magick::Geometry(1, 1), Magick::Color(color))); + audio = tr1::shared_ptr(new juce::AudioSampleBuffer(channels, 1600)); // initialize the audio samples to zero (silence) audio->clear(); @@ -34,11 +34,11 @@ Frame::Frame(int number, int width, int height, string color) // Constructor - image only from pixel array (48kHz audio silence) Frame::Frame(int number, int width, int height, const string map, const Magick::StorageType type, const void *pixels) - : number(number), image(0), audio(0), pixel_ratio(1,1), sample_rate(48000), channels(2), wave_image(NULL) + : number(number), pixel_ratio(1,1), sample_rate(48000), channels(2) { // Init the image magic and audio buffer - image = new Magick::Image(width, height, map, type, pixels); - audio = new juce::AudioSampleBuffer(channels, 1600); + image = tr1::shared_ptr(new Magick::Image(width, height, map, type, pixels)); + audio = tr1::shared_ptr(new juce::AudioSampleBuffer(channels, 1600)); // initialize the audio samples to zero (silence) audio->clear(); @@ -46,11 +46,11 @@ Frame::Frame(int number, int width, int height, const string map, const Magick:: // Constructor - audio only (300x200 blank image) Frame::Frame(int number, int samples, int channels) : - number(number), image(0), audio(0), pixel_ratio(1,1), sample_rate(48000), channels(channels), wave_image(NULL) + number(number), pixel_ratio(1,1), sample_rate(48000), channels(channels) { // Init the image magic and audio buffer - image = new Magick::Image(Magick::Geometry(1, 1), Magick::Color("white")); - audio = new juce::AudioSampleBuffer(channels, samples); + image = tr1::shared_ptr(new Magick::Image(Magick::Geometry(1, 1), Magick::Color("white"))); + audio = tr1::shared_ptr(new juce::AudioSampleBuffer(channels, samples)); // initialize the audio samples to zero (silence) audio->clear(); @@ -58,22 +58,16 @@ Frame::Frame(int number, int samples, int channels) : // Constructor - image & audio Frame::Frame(int number, int width, int height, string color, int samples, int channels) - : number(number), image(0), audio(0), pixel_ratio(1,1), sample_rate(48000), channels(channels), wave_image(NULL) + : number(number), pixel_ratio(1,1), sample_rate(48000), channels(channels) { // Init the image magic and audio buffer - image = new Magick::Image(Magick::Geometry(1, 1), Magick::Color(color)); - audio = new juce::AudioSampleBuffer(channels, samples); + image = tr1::shared_ptr(new Magick::Image(Magick::Geometry(1, 1), Magick::Color(color))); + audio = tr1::shared_ptr(new juce::AudioSampleBuffer(channels, samples)); // initialize the audio samples to zero (silence) audio->clear(); }; -// Destructor -Frame::~Frame() -{ - // deallocate image and audio memory - DeletePointers(); -} // Copy constructor Frame::Frame ( const Frame &other ) @@ -86,9 +80,6 @@ Frame::Frame ( const Frame &other ) Frame& Frame::operator= (const Frame& other) { if (this != &other) { - // deallocate image and audio memory - DeletePointers(); - // copy pointers and data DeepCopy(other); } @@ -101,26 +92,14 @@ Frame& Frame::operator= (const Frame& other) void Frame::DeepCopy(const Frame& other) { number = other.number; - image = new Magick::Image(*(other.image)); - audio = new juce::AudioSampleBuffer(*(other.audio)); + image = tr1::shared_ptr(new Magick::Image(*(other.image))); + audio = tr1::shared_ptr(new juce::AudioSampleBuffer(*(other.audio))); pixel_ratio = Fraction(other.pixel_ratio.num, other.pixel_ratio.den); sample_rate = other.sample_rate; channels = other.channels; if (other.wave_image) - wave_image = new Magick::Image(*(other.wave_image)); -} - -// Deallocate image and audio memory -void Frame::DeletePointers() -{ - // deallocate image memory - delete image; - image = NULL; - delete audio; - audio = NULL; - delete wave_image; - wave_image = NULL; + wave_image = tr1::shared_ptr(new Magick::Image(*(other.wave_image))); } // Display the frame image to the screen (primarily used for debugging reasons) @@ -152,7 +131,7 @@ void Frame::Display() } // Get an audio waveform image -Magick::Image* Frame::GetWaveform(int width, int height) +tr1::shared_ptr Frame::GetWaveform(int width, int height) { // Clear any existing waveform image ClearWaveform(); @@ -220,7 +199,7 @@ Magick::Image* Frame::GetWaveform(int width, int height) } // Create image - wave_image = new Magick::Image(Magick::Geometry(total_width, total_height), Magick::Color("#000000")); + wave_image = tr1::shared_ptr(new Magick::Image(Magick::Geometry(total_width, total_height), Magick::Color("#000000"))); // Draw the waveform wave_image->draw(lines); @@ -237,7 +216,7 @@ Magick::Image* Frame::GetWaveform(int width, int height) else { // No audio samples present - wave_image = new Magick::Image(Magick::Geometry(width, height), Magick::Color("#000000")); + wave_image = tr1::shared_ptr(new Magick::Image(Magick::Geometry(width, height), Magick::Color("#000000"))); // Add Channel Label lines.push_back(Magick::DrawableStrokeColor("#ffffff")); @@ -257,17 +236,14 @@ Magick::Image* Frame::GetWaveform(int width, int height) void Frame::ClearWaveform() { if (wave_image) - { - delete wave_image; - wave_image = NULL; - } + wave_image.reset(); } // Get an audio waveform image pixels const Magick::PixelPacket* Frame::GetWaveformPixels(int width, int height) { // Get audio wave form image - Magick::Image *wave_image = GetWaveform(width, height); + tr1::shared_ptr wave_image = GetWaveform(width, height); // Return array of pixel packets return wave_image->getConstPixels(0,0, wave_image->columns(), wave_image->rows()); @@ -297,7 +273,7 @@ float* Frame::GetAudioSamples(int channel) float* Frame::GetInterleavedAudioSamples(int new_sample_rate, AudioResampler* resampler, int* sample_count) { float *output = NULL; - AudioSampleBuffer *buffer = audio; + AudioSampleBuffer *buffer(audio.get()); int num_of_channels = audio->getNumChannels(); int num_of_samples = audio->getNumSamples(); @@ -311,7 +287,7 @@ float* Frame::GetInterleavedAudioSamples(int new_sample_rate, AudioResampler* re if (new_sample_rate != sample_rate) { // YES, RESAMPLE AUDIO - resampler->SetBuffer(audio, sample_rate, new_sample_rate); + resampler->SetBuffer(audio.get(), sample_rate, new_sample_rate); // Resample data, and return new buffer pointer buffer = resampler->GetResampledBuffer(); @@ -457,41 +433,20 @@ void Frame::Save(string path, float scale) // Add (or replace) pixel data to the frame (based on a solid color) void Frame::AddColor(int width, int height, string color) { - // Deallocate image memory - if (image) - { - delete image; - image = NULL; - } - // Create new image object, and fill with pixel data - image = new Magick::Image(Magick::Geometry(width, height), Magick::Color(color)); + image = tr1::shared_ptr(new Magick::Image(Magick::Geometry(width, height), Magick::Color(color))); } // Add (or replace) pixel data to the frame void Frame::AddImage(int width, int height, const string map, const Magick::StorageType type, const void *pixels) { - // Deallocate image memory - if (image) - { - delete image; - image = NULL; - } - // Create new image object, and fill with pixel data - image = new Magick::Image(width, height, map, type, pixels); + image = tr1::shared_ptr(new Magick::Image(width, height, map, type, pixels)); } // Add (or replace) pixel data to the frame -void Frame::AddImage(Magick::Image* new_image) +void Frame::AddImage(tr1::shared_ptr new_image) { - // Deallocate image memory - if (image) - { - delete image; - image = NULL; - } - // assign image data image = new_image; } @@ -526,7 +481,7 @@ void Frame::Rotate(float degrees) void Frame::AddOverlay(Frame* frame) { // Get overlay image (if any) - Magick::Image* overlay = frame->GetImage(); + tr1::shared_ptr overlay = frame->GetImage(); // Composite image onto this image image->composite(*overlay, Magick::SouthEastGravity, Magick::OverCompositeOp); @@ -555,7 +510,7 @@ void Frame::AddOverlayNumber(int overlay_number) } // Get pointer to Magick++ image object -Magick::Image* Frame::GetImage() +tr1::shared_ptr Frame::GetImage() { return image; } @@ -578,7 +533,7 @@ void Frame::Play() deviceManager.addAudioCallback (&audioSourcePlayer); ScopedPointer my_source; - my_source = new AudioBufferSource(audio); + my_source = new AudioBufferSource(audio.get()); // Create TimeSliceThread for audio buffering TimeSliceThread my_thread("Audio buffer thread"); diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index e1762d4f..b3529323 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -10,13 +10,22 @@ using namespace std; using namespace openshot; FrameMapper::FrameMapper(FileReaderBase *reader, Framerate target, Pulldown_Method pulldown) : - reader(reader), target(target), pulldown(pulldown) + reader(reader), target(target), pulldown(pulldown), final_cache(820 * 1024) { + + // Init FileInfo struct (clear all values) + InitFileInfo(); + // Set the original frame rate from the reader original = Framerate(reader->info.fps.num, reader->info.fps.den); - // Set length from reader - m_length = reader->info.video_length; + // Set all info struct members equal to the internal reader + info = reader->info; + info.fps.num = target.GetFraction().num; + info.fps.den = target.GetFraction().den; + info.video_timebase.num = target.GetFraction().den; + info.video_timebase.den = target.GetFraction().num; + info.video_length = round(info.duration * info.fps.ToDouble()); // Used to toggle odd / even fields field_toggle = true; @@ -67,7 +76,7 @@ void FrameMapper::Init() // Loop through all fields in the original video file int frame = 1; - int number_of_fields = m_length * 2; + int number_of_fields = info.video_length * 2; for (int field = 1; field <= number_of_fields; field++) { @@ -91,7 +100,7 @@ void FrameMapper::Init() // Add both extra fields in the middle 'together' (i.e. 2:3:3:2 technique) AddField(frame); // add field for current frame - if (frame + 1 <= m_length) + if (frame + 1 <= info.video_length) // add field for next frame (if the next frame exists) AddField(Field(frame + 1, field_toggle)); } @@ -183,7 +192,7 @@ void FrameMapper::Init() } // Create the sample mapping struct - SampleRange Samples = {start_samples_frame, start_samples_position, end_samples_frame, end_samples_position}; + SampleRange Samples = {start_samples_frame, start_samples_position, end_samples_frame, end_samples_position, GetSamplesPerFrame(frame_number, target.GetFraction())}; // Reset the audio variables start_samples_frame = end_samples_frame; @@ -212,7 +221,7 @@ void FrameMapper::Init() fields.clear(); } -MappedFrame FrameMapper::GetFrame(int TargetFrameNumber) throw(OutOfBoundsFrame) +MappedFrame FrameMapper::GetMappedFrame(int TargetFrameNumber) throw(OutOfBoundsFrame) { // Check if frame number is valid if(TargetFrameNumber < 1 || TargetFrameNumber > frames.size()) @@ -224,6 +233,73 @@ MappedFrame FrameMapper::GetFrame(int TargetFrameNumber) throw(OutOfBoundsFrame) return frames[TargetFrameNumber - 1]; } +// Get an openshot::Frame object for a specific frame number of this reader. +tr1::shared_ptr FrameMapper::GetFrame(int requested_frame) throw(ReaderClosed) +{ + // Check final cache, and just return the frame (if it's available) + if (final_cache.Exists(requested_frame)) + return final_cache.GetFrame(requested_frame); + + // Get the mapped frame + MappedFrame mapped = GetMappedFrame(requested_frame); + + // Init some basic properties about this frame + int samples_in_frame = GetSamplesPerFrame(requested_frame, target.GetFraction()); + + // Create a new frame + tr1::shared_ptr frame(new Frame(requested_frame, 1, 1, "#000000", samples_in_frame, info.channels)); + + // Copy the image from the odd field (TODO: make this copy each field from the correct frames) + frame->AddImage(reader->GetFrame(mapped.Odd.Frame)->GetImage()); + + // Copy the samples + int samples_copied = 0; + int starting_frame = mapped.Samples.frame_start; + while (samples_copied < mapped.Samples.total) + { + // init number of samples to copy this iteration + int number_to_copy = 0; + + // Loop through each channel + for (int channel = 0; channel < info.channels; channel++) + { + // number of original samples on this frame + tr1::shared_ptr original_frame = reader->GetFrame(starting_frame); + int original_samples = original_frame->GetAudioSamplesCount(); + + if (starting_frame == mapped.Samples.frame_start) + { + // Starting frame (take the ending samples) + number_to_copy = (original_samples - mapped.Samples.sample_start) + 1; + cout << "Fixing to copy audio: frame: " << starting_frame << ", channel: " << channel << ", original_samples: " << original_samples << ", sample_start: " << mapped.Samples.sample_start << ", number_to_copy: " << number_to_copy << ", first value: " << original_frame->GetAudioSamples(channel)[0] << endl; + frame->AddAudio(channel, samples_copied, original_frame->GetAudioSamples(channel) + mapped.Samples.sample_start, 10, 1.0); + } + else if (starting_frame > mapped.Samples.frame_start && starting_frame < mapped.Samples.frame_end) + { + // Middle frame (take all samples) + number_to_copy = original_samples; + frame->AddAudio(channel, samples_copied, original_frame->GetAudioSamples(channel), number_to_copy, 1.0); + } + else + { + // Ending frame (take the beginning samples) + number_to_copy = mapped.Samples.sample_end; + frame->AddAudio(channel, samples_copied, original_frame->GetAudioSamples(channel), number_to_copy, 1.0); + } + } + + // increment frame + samples_copied += number_to_copy; + starting_frame++; + } + + // Add frame to final cache + final_cache.Add(frame->number, frame); + + // Return processed 'frame' + return final_cache.GetFrame(frame->number); +} + void FrameMapper::MapTime(Keyframe new_time) throw(OutOfBoundsFrame) { // New time-mapped frames vector @@ -305,3 +381,20 @@ void FrameMapper::PrintMapping() } } + +// Open the internal reader +void FrameMapper::Open() throw(InvalidFile) +{ + if (reader) + { + // Open the reader + reader->Open(); + } +} + +// Close the internal reader +void FrameMapper::Close() +{ + if (reader) + reader->Close(); +} diff --git a/src/ImageReader.cpp b/src/ImageReader.cpp index 164833f3..df69c85f 100644 --- a/src/ImageReader.cpp +++ b/src/ImageReader.cpp @@ -34,7 +34,7 @@ void ImageReader::Open() throw(InvalidFile) image_frame = tr1::shared_ptr(new Frame(1, source->size().width(), source->size().height(), "#000000", 0, 2)); // Add Image data to frame - image_frame->AddImage(source); + image_frame->AddImage(tr1::shared_ptr(source)); // Update image properties info.has_audio = false; diff --git a/src/Main.cpp b/src/Main.cpp index 80461b54..ce0ebab6 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -17,78 +17,78 @@ void FrameReady(int number) int main() { - openshot::FFmpegReader r1("/home/jonathan/Videos/sintel-1024-stereo.mp4"); - r1.Open(); - FrameMapper map(&r1, Framerate(2,1), PULLDOWN_NONE); - map.PrintMapping(); - - return 0; +// openshot::FFmpegReader r1("/home/jonathan/Videos/sintel-1024-stereo.mp4"); +// r1.Open(); +// FrameMapper map(&r1, Framerate(30,1), PULLDOWN_NONE); +// map.PrintMapping(); +// +// return 0; - // Create timeline - Timeline t(640, 360, Framerate(24,1)); - - // Add some clips - Clip c1("/home/jonathan/Videos/sintel-1024-stereo.mp4"); - c1.Position(0.0); - -// c1.time.AddPoint(1, 50); -// c1.time.AddPoint(100, 1); -// c1.time.AddPoint(200, 90); -// c1.time.PrintValues(); - - //c1.time.AddPoint(500, 500, LINEAR); - c1.time.AddPoint(1, 300); - c1.time.AddPoint(200, 500, LINEAR); - c1.time.AddPoint(400, 100); - c1.time.AddPoint(500, 500); - - // Add clips - t.AddClip(&c1); - - - // Create a writer - FFmpegWriter w("/home/jonathan/output.webm"); - w.DisplayInfo(); - - // Set options - 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); - - // 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; +// // Create timeline +// Timeline t(640, 360, Framerate(24,1)); +// +// // Add some clips +// Clip c1("/home/jonathan/Videos/sintel-1024-stereo.mp4"); +// c1.Position(0.0); +// +//// c1.time.AddPoint(1, 50); +//// c1.time.AddPoint(100, 1); +//// c1.time.AddPoint(200, 90); +//// c1.time.PrintValues(); +// +// //c1.time.AddPoint(500, 500, LINEAR); +// c1.time.AddPoint(1, 300); +// c1.time.AddPoint(200, 500, LINEAR); +// c1.time.AddPoint(400, 100); +// c1.time.AddPoint(500, 500); +// +// // Add clips +// t.AddClip(&c1); +// +// +// // Create a writer +// FFmpegWriter w("/home/jonathan/output.webm"); +// w.DisplayInfo(); +// +// // Set options +// 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); +// +// // 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; @@ -127,7 +127,7 @@ int main() // openshot::FFmpegReader r("../../src/examples/piano.wav"); // openshot::FFmpegReader r("/home/jonathan/Videos/big-buck-bunny_trailer.webm"); - openshot::FFmpegReader r("/home/jonathan/Videos/sintel-1024-stereo.mp4"); + openshot::FFmpegReader r1("/home/jonathan/Videos/sintel-1024-stereo.mp4"); // openshot::FFmpegReader r("/home/jonathan/Videos/OpenShot_Now_In_3d.mp4"); // openshot::FFmpegReader r("/home/jonathan/Videos/sintel_trailer-720p.mp4"); // openshot::FFmpegReader r("/home/jonathan/Aptana Studio Workspace/OpenShotLibrary/src/examples/piano.wav"); @@ -136,63 +136,66 @@ int main() // openshot::FFmpegReader r("/home/jonathan/Videos/60fps.mp4"); // openshot::FFmpegReader r("/home/jonathan/Aptana Studio Workspace/OpenShotLibrary/src/examples/asdf.wdf"); -// // Display debug info -// r.Open(); -// r.DisplayInfo(); -// -// // Create a writer -// FFmpegWriter w("/home/jonathan/output.webm"); -// w.DisplayInfo(); -// -// // Set options -// 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(); -// -// // 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 <= 2000; 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(); + + openshot::FrameMapper r(&r1, Framerate(30,1), PULLDOWN_NONE); + + // Display debug info + r.Open(); + r.DisplayInfo(); + + // Create a writer + FFmpegWriter w("/home/jonathan/output.webm"); + w.DisplayInfo(); + + // Set options + w.SetAudioOptions(true, "libvorbis", 44100, 2, 128000, false); + w.SetVideoOptions(true, "libvpx", Fraction(30, 1), 640, 360, 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 <= 2000; 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; diff --git a/tests/FrameMapper_Tests.cpp b/tests/FrameMapper_Tests.cpp index 82d792c9..faf33ebf 100644 --- a/tests/FrameMapper_Tests.cpp +++ b/tests/FrameMapper_Tests.cpp @@ -15,7 +15,7 @@ TEST(FrameMapper_Get_Valid_Frame) try { // Should find this frame - MappedFrame f = mapping.GetFrame(125); + MappedFrame f = mapping.GetMappedFrame(125); CHECK(true); // success } catch (OutOfBoundsFrame &e) @@ -34,7 +34,7 @@ TEST(FrameMapper_Invalid_Frame_Too_Small) FrameMapper mapping(&r, Framerate(30000, 1001), PULLDOWN_CLASSIC); // Check invalid frame number - CHECK_THROW(mapping.GetFrame(0), OutOfBoundsFrame); + CHECK_THROW(mapping.GetMappedFrame(0), OutOfBoundsFrame); } @@ -47,7 +47,7 @@ TEST(FrameMapper_Invalid_Frame_Too_Large) FrameMapper mapping(&r, Framerate(30000, 1001), PULLDOWN_CLASSIC); // Check invalid frame number - CHECK_THROW(mapping.GetFrame(126), OutOfBoundsFrame); + CHECK_THROW(mapping.GetMappedFrame(126), OutOfBoundsFrame); } TEST(FrameMapper_24_fps_to_30_fps_Pulldown_Classic) @@ -57,8 +57,8 @@ TEST(FrameMapper_24_fps_to_30_fps_Pulldown_Classic) // Create mapping 24 fps and 29.97 fps FrameMapper mapping(&r, Framerate(30000, 1001), PULLDOWN_CLASSIC); - MappedFrame frame2 = mapping.GetFrame(2); - MappedFrame frame3 = mapping.GetFrame(3); + MappedFrame frame2 = mapping.GetMappedFrame(2); + MappedFrame frame3 = mapping.GetMappedFrame(3); // Check for 3 fields of frame 2 CHECK_EQUAL(2, frame2.Odd.Frame); @@ -74,9 +74,9 @@ TEST(FrameMapper_24_fps_to_30_fps_Pulldown_Advanced) // Create mapping 24 fps and 29.97 fps FrameMapper mapping(&r, Framerate(30000, 1001), PULLDOWN_ADVANCED); - MappedFrame frame2 = mapping.GetFrame(2); - MappedFrame frame3 = mapping.GetFrame(3); - MappedFrame frame4 = mapping.GetFrame(4); + MappedFrame frame2 = mapping.GetMappedFrame(2); + MappedFrame frame3 = mapping.GetMappedFrame(3); + MappedFrame frame4 = mapping.GetMappedFrame(4); // Check for advanced pulldown (only 1 fake frame) CHECK_EQUAL(2, frame2.Odd.Frame); @@ -94,8 +94,8 @@ TEST(FrameMapper_24_fps_to_30_fps_Pulldown_None) // Create mapping 24 fps and 29.97 fps FrameMapper mapping(&r, Framerate(30000, 1001), PULLDOWN_NONE); - MappedFrame frame4 = mapping.GetFrame(4); - MappedFrame frame5 = mapping.GetFrame(5); + MappedFrame frame4 = mapping.GetMappedFrame(4); + MappedFrame frame5 = mapping.GetMappedFrame(5); // Check for advanced pulldown (only 1 fake frame) CHECK_EQUAL(4, frame4.Odd.Frame); @@ -111,9 +111,9 @@ TEST(FrameMapper_30_fps_to_24_fps_Pulldown_Classic) // Create mapping between 29.97 fps and 24 fps FrameMapper mapping(&r, Framerate(24, 1), PULLDOWN_CLASSIC); - MappedFrame frame3 = mapping.GetFrame(3); - MappedFrame frame4 = mapping.GetFrame(4); - MappedFrame frame5 = mapping.GetFrame(5); + MappedFrame frame3 = mapping.GetMappedFrame(3); + MappedFrame frame4 = mapping.GetMappedFrame(4); + MappedFrame frame5 = mapping.GetMappedFrame(5); // Check for advanced pulldown (only 1 fake frame) CHECK_EQUAL(4, frame3.Odd.Frame); @@ -131,9 +131,9 @@ TEST(FrameMapper_30_fps_to_24_fps_Pulldown_Advanced) // Create mapping between 29.97 fps and 24 fps FrameMapper mapping(&r, Framerate(24, 1), PULLDOWN_ADVANCED); - MappedFrame frame2 = mapping.GetFrame(2); - MappedFrame frame3 = mapping.GetFrame(3); - MappedFrame frame4 = mapping.GetFrame(4); + MappedFrame frame2 = mapping.GetMappedFrame(2); + MappedFrame frame3 = mapping.GetMappedFrame(3); + MappedFrame frame4 = mapping.GetMappedFrame(4); // Check for advanced pulldown (only 1 fake frame) CHECK_EQUAL(2, frame2.Odd.Frame); @@ -151,8 +151,8 @@ TEST(FrameMapper_30_fps_to_24_fps_Pulldown_None) // Create mapping between 29.97 fps and 24 fps FrameMapper mapping(&r, Framerate(24, 1), PULLDOWN_NONE); - MappedFrame frame4 = mapping.GetFrame(4); - MappedFrame frame5 = mapping.GetFrame(5); + MappedFrame frame4 = mapping.GetMappedFrame(4); + MappedFrame frame5 = mapping.GetMappedFrame(5); // Check for advanced pulldown (only 1 fake frame) CHECK_EQUAL(4, frame4.Odd.Frame); @@ -180,21 +180,21 @@ TEST(FrameMapper_MapTime) mapping.MapTime(kf); // Check for OutOfBoundsFrames - CHECK_THROW(mapping.GetFrame(0), OutOfBoundsFrame); - CHECK_THROW(mapping.GetFrame(101), OutOfBoundsFrame); + CHECK_THROW(mapping.GetMappedFrame(0), OutOfBoundsFrame); + CHECK_THROW(mapping.GetMappedFrame(101), OutOfBoundsFrame); // Check to see if time remapping worked correctly - CHECK_EQUAL(1, mapping.GetFrame(1).Odd.Frame); - CHECK_EQUAL(2, mapping.GetFrame(2).Odd.Frame); - CHECK_EQUAL(39, mapping.GetFrame(39).Odd.Frame); - CHECK_EQUAL(40, mapping.GetFrame(40).Odd.Frame); - CHECK_EQUAL(39, mapping.GetFrame(41).Odd.Frame); - CHECK_EQUAL(38, mapping.GetFrame(42).Odd.Frame); - CHECK_EQUAL(21, mapping.GetFrame(59).Odd.Frame); - CHECK_EQUAL(20, mapping.GetFrame(60).Odd.Frame); - CHECK_EQUAL(22, mapping.GetFrame(61).Odd.Frame); - CHECK_EQUAL(24, mapping.GetFrame(62).Odd.Frame); - CHECK_EQUAL(90, mapping.GetFrame(95).Odd.Frame); - CHECK_EQUAL(100, mapping.GetFrame(100).Odd.Frame); + CHECK_EQUAL(1, mapping.GetMappedFrame(1).Odd.Frame); + CHECK_EQUAL(2, mapping.GetMappedFrame(2).Odd.Frame); + CHECK_EQUAL(39, mapping.GetMappedFrame(39).Odd.Frame); + CHECK_EQUAL(40, mapping.GetMappedFrame(40).Odd.Frame); + CHECK_EQUAL(39, mapping.GetMappedFrame(41).Odd.Frame); + CHECK_EQUAL(38, mapping.GetMappedFrame(42).Odd.Frame); + CHECK_EQUAL(21, mapping.GetMappedFrame(59).Odd.Frame); + CHECK_EQUAL(20, mapping.GetMappedFrame(60).Odd.Frame); + CHECK_EQUAL(22, mapping.GetMappedFrame(61).Odd.Frame); + CHECK_EQUAL(24, mapping.GetMappedFrame(62).Odd.Frame); + CHECK_EQUAL(90, mapping.GetMappedFrame(95).Odd.Frame); + CHECK_EQUAL(100, mapping.GetMappedFrame(100).Odd.Frame); }