diff --git a/include/KeyFrame.h b/include/KeyFrame.h index 5a5565a0..8a3fcfd5 100644 --- a/include/KeyFrame.h +++ b/include/KeyFrame.h @@ -141,6 +141,9 @@ namespace openshot { /// Get current point (or closest point) from the X coordinate (i.e. the frame number) Point GetClosestPoint(Point p); + /// Get max point (by Y coordinate) + Point GetMaxPoint(); + // Get the number of values (i.e. coordinates on the X axis) long int GetLength(); diff --git a/src/Clip.cpp b/src/Clip.cpp index a93db20a..2ce820e9 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -597,13 +597,32 @@ tr1::shared_ptr Clip::GetOrCreateFrame(long int number) // Debug output ZmqLogger::Instance()->AppendDebugMethod("Clip::GetOrCreateFrame (from reader)", "number", number, "samples_in_frame", samples_in_frame, "", -1, "", -1, "", -1, "", -1); - // Set max image size (used for performance optimization) - if (scale_x.GetValue(number) > 1.000001 || scale_y.GetValue(number) > 1.000001) - // Scaling larger, use original image size (slower but better quality) + // Determine the max size of this clips source image (based on the timeline's size, the scaling mode, + // and the scaling keyframes). This is a performance improvement, to keep the images as small as possible, + // without loosing quality. + if (scale == SCALE_FIT || scale == SCALE_STRETCH) { + // Best fit or Stretch scaling (based on max timeline size * scaling keyframes) + float max_scale_x = scale_x.GetMaxPoint().co.Y; + float max_scale_y = scale_y.GetMaxPoint().co.Y; + reader->SetMaxSize(max_width * max_scale_x, max_height * max_scale_y); + + } else if (scale == SCALE_CROP) { + // Cropping scale mode (based on max timeline size * cropped size * scaling keyframes) + float max_scale_x = scale_x.GetMaxPoint().co.Y; + float max_scale_y = scale_y.GetMaxPoint().co.Y; + QSize width_size(max_width * max_scale_x, round(max_width / (float(reader->info.width) / float(reader->info.height)))); + QSize height_size(round(max_height / (float(reader->info.height) / float(reader->info.width))), max_height * max_scale_y); + + // respect aspect ratio + if (width_size.width() >= max_width && width_size.height() >= max_height) + reader->SetMaxSize(width_size.width(), width_size.height()); + else + reader->SetMaxSize(height_size.width(), height_size.height()); + + } else { + // No scaling, use original image size (slower) reader->SetMaxSize(0, 0); - else - // No scaling applied, use max_size (usually the size of the timeline) - reader->SetMaxSize(max_width, max_height); + } // Attempt to get a frame (but this could fail if a reader has just been closed) new_frame = reader->GetFrame(number); diff --git a/src/KeyFrame.cpp b/src/KeyFrame.cpp index 6c3777df..4bb4b062 100644 --- a/src/KeyFrame.cpp +++ b/src/KeyFrame.cpp @@ -220,6 +220,25 @@ Point Keyframe::GetClosestPoint(Point p) { return closest; } +// Get max point (by Y coordinate) +Point Keyframe::GetMaxPoint() { + Point maxPoint(-1, -1); + + // loop through points, and find the largest Y value + for (long int x = 0; x < Points.size(); x++) { + // Get each point + Point existing_point = Points[x]; + + // Is point larger than max point + if (existing_point.co.Y >= maxPoint.co.Y) { + // New max point found + maxPoint = existing_point; + } + } + + return maxPoint; +} + // Get the value at a specific index float Keyframe::GetValue(long int index) { diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp index 5bfecc59..8ee56374 100644 --- a/src/QtImageReader.cpp +++ b/src/QtImageReader.cpp @@ -123,6 +123,11 @@ tr1::shared_ptr QtImageReader::GetFrame(long int requested_frame) throw(R // A max_width/max_height = 0 means do not scale (probably because we are scaling the image larger than 100%) if (max_width != 0 && max_height != 0 && max_width < info.width && max_height < info.height) { + // Remove cache that is no longer valid (if needed) + if (cached_image && !(cached_image->width() == max_width || cached_image->height() == max_height)) + // Expire this cache + cached_image.reset(); + // Scale image smaller (or use a previous scaled image) if (!cached_image) { // Create a scoped lock, allowing only a single thread to run the following code at one time diff --git a/tests/KeyFrame_Tests.cpp b/tests/KeyFrame_Tests.cpp index 4d970465..0a8739c2 100644 --- a/tests/KeyFrame_Tests.cpp +++ b/tests/KeyFrame_Tests.cpp @@ -244,6 +244,32 @@ TEST(Keyframe_Get_Closest_Point) } + +TEST(Keyframe_Get_Max_Point) +{ + // Create a keyframe curve + Keyframe kf; + kf.AddPoint(1, 1.0); + + // Spot check values from the curve + CHECK_EQUAL(kf.GetMaxPoint().co.Y, 1.0); + + kf.AddPoint(2, 0.0); + + // Spot check values from the curve + CHECK_EQUAL(kf.GetMaxPoint().co.Y, 1.0); + + kf.AddPoint(3, 2.0); + + // Spot check values from the curve + CHECK_EQUAL(kf.GetMaxPoint().co.Y, 2.0); + + kf.AddPoint(4, 1.0); + + // Spot check values from the curve + CHECK_EQUAL(kf.GetMaxPoint().co.Y, 2.0); +} + TEST(Keyframe_Scale_Keyframe) { // Create a keyframe curve with 2 points