Improved image caching logic, to better estimate max image sizes possible, based on clip scale and keyframe settings... so we are always dealing with the smallest possible frame sizes for performance (without losing quality)

This commit is contained in:
Jonathan Thomas
2016-09-17 17:14:27 -05:00
parent 183b0714e2
commit 1743558f99
5 changed files with 78 additions and 6 deletions

View File

@@ -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();

View File

@@ -597,13 +597,32 @@ tr1::shared_ptr<Frame> 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);

View File

@@ -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)
{

View File

@@ -123,6 +123,11 @@ tr1::shared_ptr<Frame> 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

View File

@@ -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