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