diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp
index 7160f24a..2b0ff5cf 100644
--- a/src/FFmpegReader.cpp
+++ b/src/FFmpegReader.cpp
@@ -205,10 +205,10 @@ void FFmpegReader::UpdateAudioInfo()
if (!info.has_video)
{
// Set a few important default video settings (so audio can be divided into frames)
- info.fps.num = 30;
+ info.fps.num = 24;
info.fps.den = 1;
info.video_timebase.num = 1;
- info.video_timebase.den = 30;
+ info.video_timebase.den = 24;
info.video_length = info.duration * info.fps.ToDouble();
}
diff --git a/src/Main.cpp b/src/Main.cpp
index b29d9452..b8ec90be 100644
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -31,32 +31,52 @@ int main()
Timeline t(640, 360, Framerate(24,1), 44100, 2);
// Add some clips
- Clip c1(new FFmpegReader("/home/jonathan/Videos/sintel_trailer-720p.mp4"));
- Clip c2(new ImageReader("/home/jonathan/apps/videcho_site/media/logos/watermark.png"));
- c1.Position(1.0);
- c2.Position(1.0);
+ Clip c1(new FFmpegReader("/home/jonathan/Videos/sintel-1024-stereo.mp4"));
+ //Clip c2(new ImageReader("/home/jonathan/Desktop/watermark.svg"));
+ Clip c2(new ImageReader("/home/jonathan/Desktop/icon.png"));
+ //Clip c3(new FFmpegReader("/home/jonathan/Desktop/IncognitoCory_-_April_Song.mp3"));
+ c1.Position(0.0);
+ c1.gravity = GRAVITY_CENTER;
+ c1.scale = SCALE_CROP;
+ c1.End(20);
+
+ c2.Position(0.0);
c2.Layer(1);
+ c2.gravity = GRAVITY_BOTTOM_RIGHT;
+ c2.scale = SCALE_NONE;
+ c2.End(20);
- c1.rotation.AddPoint(1, 1);
- c1.rotation.AddPoint(300, 360);
+ //c1.rotation.AddPoint(1, 1);
+ //c1.rotation.AddPoint(300, 360);
- //c1.alpha.AddPoint(1, 0);
- //c1.alpha.AddPoint(300, 1);
+ //c2.scale_x.AddPoint(1, 1);
+ //c2.scale_x.AddPoint(300, 3.5);
- c2.alpha.AddPoint(1, 1);
- c2.alpha.AddPoint(30, 0);
- c2.alpha.AddPoint(100, 0, LINEAR);
- c2.alpha.AddPoint(150, 1);
- c2.End(6.25);
+ //c2.scale_y.AddPoint(1, 1);
+ //c2.scale_y.AddPoint(300, 3.5);
+
+ //c1.scale_x.AddPoint(1, 1);
+ //c1.scale_x.AddPoint(300, 1.5);
+
+ //c1.scale_y.AddPoint(1, 1);
+ //c1.scale_y.AddPoint(300, 1.5);
+
+ //c1.alpha.AddPoint(1, 1);
+ //c1.alpha.AddPoint(30, 0);
+
+ //c2.alpha.AddPoint(1, 1);
+ //c2.alpha.AddPoint(30, 0);
+ //c2.alpha.AddPoint(100, 0, LINEAR);
+ //c2.alpha.AddPoint(150, 1);
c2.location_x.AddPoint(1, 0);
- c2.location_x.AddPoint(300, 530);
+ c2.location_x.AddPoint(300, -1.0);
- c2.location_y.AddPoint(1, 0);
- c2.location_y.AddPoint(300, 300);
+ //c2.location_y.AddPoint(1, 0);
+ //c2.location_y.AddPoint(300, 1);
- c2.rotation.AddPoint(60, 1, LINEAR);
- c2.rotation.AddPoint(150, 360);
+ //c2.rotation.AddPoint(1, 0);
+ //c2.rotation.AddPoint(300, 360);
// LINEAR Reverse
@@ -105,6 +125,7 @@ int main()
// Add clips
t.AddClip(&c1);
t.AddClip(&c2);
+ //t.AddClip(&c3);
// Create a writer
diff --git a/src/Timeline.cpp b/src/Timeline.cpp
index eb752503..cc6360d8 100644
--- a/src/Timeline.cpp
+++ b/src/Timeline.cpp
@@ -43,42 +43,109 @@ void Timeline::add_layer(tr1::shared_ptr new_frame, Clip* source_clip, in
tr1::shared_ptr source_frame = source_clip->GetFrame(clip_frame_number);
tr1::shared_ptr source_image = source_frame->GetImage();
- // Replace image (needed if this is the 1st layer)
+ // Get some basic image properties
+ int source_width = source_image->columns();
+ int source_height = source_image->rows();
+
+
+ /* CREATE BACKGROUND COLOR - needed if this is the 1st layer */
if (new_frame->GetImage()->columns() == 1)
new_frame->AddColor(width, height, "#000000");
- // Apply image effects
- //if (source_clip->rotation.GetValue(clip_frame_number) != 0)
- // source_image->rotate(source_clip->rotation.GetValue(clip_frame_number));
+ /* COPY AUDIO */
+ for (int channel = 0; channel < source_frame->GetAudioChannelsCount(); channel++)
+ new_frame->AddAudio(channel, 0, source_frame->GetAudioSamples(channel), source_frame->GetAudioSamplesCount(), 1.0f);
+
+ /* ALPHA & OPACITY */
if (source_clip->alpha.GetValue(clip_frame_number) != 0)
{
- // Calculate opacity of new image
+ // Calculate & set opacity of new image
int new_opacity = 65535.0f * source_clip->alpha.GetValue(clip_frame_number);
if (new_opacity < 0) new_opacity = 0; // completely invisible
source_image->opacity(new_opacity);
}
- // Copy audio from source frame
- for (int channel = 0; channel < source_frame->GetAudioChannelsCount(); channel++)
- new_frame->AddAudio(channel, 0, source_frame->GetAudioSamples(channel), source_frame->GetAudioSamplesCount(), 1.0f);
+ /* RESIZE SOURCE IMAGE - based on scale type */
+ Magick::Geometry new_size(width, height);
+ switch (source_clip->scale)
+ {
+ case (SCALE_FIT):
+ new_size.aspect(false); // respect aspect ratio
+ source_image->resize(new_size);
+ source_width = source_image->size().width();
+ source_height = source_image->size().height();
+ break;
+ case (SCALE_STRETCH):
+ new_size.aspect(true); // ignore aspect ratio
+ source_image->resize(new_size);
+ source_width = source_image->size().width();
+ source_height = source_image->size().height();
+ break;
+ case (SCALE_CROP):
+ Magick::Geometry width_size(width, round(width / (float(source_width) / float(source_height))));
+ Magick::Geometry height_size(round(height / (float(source_height) / float(source_width))), height);
+ new_size.aspect(false); // respect aspect ratio
+ if (width_size.width() >= width && width_size.height() >= height)
+ source_image->resize(width_size); // width is larger, so resize to it
+ else
+ source_image->resize(height_size); // height is larger, so resize to it
+ source_width = source_image->size().width();
+ source_height = source_image->size().height();
+ break;
+ }
- // Location, Rotation, and Scale
- float r = source_clip->rotation.GetValue(clip_frame_number);
- float x = source_clip->location_x.GetValue(clip_frame_number);
- float y = source_clip->location_y.GetValue(clip_frame_number);
- float sx = source_clip->scale_x.GetValue(clip_frame_number);
- float sy = source_clip->scale_y.GetValue(clip_frame_number);
+ /* GRAVITY LOCATION - Initialize X & Y to the correct values (before applying location curves) */
+ float x = 0.0; // left
+ float y = 0.0; // top
+ switch (source_clip->gravity)
+ {
+ case (GRAVITY_TOP):
+ x = (width - source_width) / 2.0; // center
+ break;
+ case (GRAVITY_TOP_RIGHT):
+ x = width - source_width; // right
+ break;
+ case (GRAVITY_LEFT):
+ y = (height - source_height) / 2.0; // center
+ break;
+ case (GRAVITY_CENTER):
+ x = (width - source_width) / 2.0; // center
+ y = (height - source_height) / 2.0; // center
+ break;
+ case (GRAVITY_RIGHT):
+ x = width - source_width; // right
+ y = (height - source_height) / 2.0; // center
+ break;
+ case (GRAVITY_BOTTOM_LEFT):
+ y = (height - source_height); // bottom
+ break;
+ case (GRAVITY_BOTTOM):
+ x = (width - source_width) / 2.0; // center
+ y = (height - source_height); // bottom
+ break;
+ case (GRAVITY_BOTTOM_RIGHT):
+ x = width - source_width; // right
+ y = (height - source_height); // bottom
+ break;
+ }
- // Resize source canvas the same size as timeline canvas
- Magick::Geometry source_original_size = source_image->size();
- source_image->size(Magick::Geometry(width, height, 0,0,false,false));
+ /* RESIZE SOURCE CANVAS - to the same size as timeline canvas */
+ source_image->borderColor(Magick::Color("none"));
+ source_image->border(Magick::Geometry(1, 1, 0, 0, false, false)); // prevent stretching of edge pixels (during the canvas resize)
+ source_image->size(Magick::Geometry(width, height, 0, 0, false, false)); // resize the canvas (to prevent clipping)
- // Set the location (X,Y), rotation, and X-Scale, Y-Scale of the source image
- // X,Y Scale Angle NewX,NewY
- double distort_args[7] = {source_original_size.width()/2,source_original_size.height()/2, sx,sy, r, x,y };
+ /* LOCATION, ROTATION, AND SCALE */
+ float r = source_clip->rotation.GetValue(clip_frame_number); // rotate in degrees
+ x += width * source_clip->location_x.GetValue(clip_frame_number); // move in percentage of final width
+ y += height * source_clip->location_y.GetValue(clip_frame_number); // move in percentage of final height
+ float sx = source_clip->scale_x.GetValue(clip_frame_number); // percentage X scale
+ float sy = source_clip->scale_y.GetValue(clip_frame_number); // percentage Y scale
+
+ // origin X,Y Scale Angle NewX,NewY
+ double distort_args[7] = {0,0, sx,sy, r, x-1,y-1 };
source_image->distort(Magick::ScaleRotateTranslateDistortion, 7, distort_args, false);
- // Composite images together
+ /* COMPOSITE SOURCE IMAGE (LAYER) ONTO FINAL IMAGE */
tr1::shared_ptr new_image = new_frame->GetImage();
new_image->composite(*source_image.get(), 0, 0, Magick::BlendCompositeOp);
}