Skip to content

Commit 6bef760

Browse files
committed
Fix qtblend requesting huge images witrh nested compositions/filters
1 parent 687e7c9 commit 6bef760

File tree

2 files changed

+133
-121
lines changed

2 files changed

+133
-121
lines changed

src/modules/qt/filter_qtblend.cpp

Lines changed: 73 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ static int filter_get_image(mlt_frame frame,
6363
// Destination rect
6464
mlt_rect rect = {0,
6565
0,
66-
normalized_width * mlt_profile_scale_width(profile, *width),
67-
normalized_height * mlt_profile_scale_height(profile, *height),
66+
normalized_width,
67+
normalized_height,
6868
1.0};
6969
int b_width = mlt_properties_get_int(frame_properties, "meta.media.width");
7070
int b_height = mlt_properties_get_int(frame_properties, "meta.media.height");
@@ -92,82 +92,83 @@ static int filter_get_image(mlt_frame frame,
9292
rect.w *= normalized_width;
9393
rect.h *= normalized_height;
9494
}
95-
if (qtblendRescaled) {
96-
// Another qtblend filter was already applied
97-
// In this case, the *width and *height are set to the source resolution to ensure we don't lose too much details on multiple scaling operations
98-
// We requested a image with full media resolution, adjust rect to profile
99-
// Check if we have consumer scaling enabled since we cannot use *width and *height
100-
double consumerScale = mlt_properties_get_double(frame_properties,
101-
"qtblend_preview_scaling");
102-
// Consumer scaling was already applied to b_width/b_height
103-
// Always request an image that follows the consumer aspect ratio
104-
double consumer_dar = normalized_width * consumer_ar / normalized_height;
105-
int tmpWidth = b_width;
106-
int tmpHeight = b_height;
107-
double scaleFactor = qMax(*width / rect.w, *height / rect.h);
108-
if (scaleFactor > 1.) {
109-
// Use the highest necessary resolution image
110-
tmpWidth *= scaleFactor;
111-
tmpHeight *= scaleFactor;
112-
}
113-
if (consumer_dar > b_dar) {
114-
*width = qBound(qRound(normalized_width * consumerScale),
115-
tmpWidth,
116-
MLT_QTBLEND_MAX_DIMENSION);
117-
*height = qRound(*width * consumer_ar * normalized_height / normalized_width);
118-
} else {
119-
*height = qBound(qRound(normalized_height * consumerScale),
120-
tmpHeight,
121-
MLT_QTBLEND_MAX_DIMENSION);
122-
*width = qRound(*height * normalized_width / normalized_height / consumer_ar);
123-
}
124-
// Adjust rect to new scaling
125-
double scale = (double) *width / normalized_width;
126-
if (scale != 1.0) {
127-
rect.x *= scale;
128-
rect.w *= scale;
129-
}
130-
scale = (double) *height / normalized_height;
131-
if (scale != 1.0) {
132-
rect.y *= scale;
133-
rect.h *= scale;
134-
}
95+
}
96+
if (qtblendRescaled) {
97+
// Another qtblend filter was already applied
98+
// In this case, the *width and *height are set to the source resolution to ensure we don't lose too much details on multiple scaling operations
99+
// We requested a image with full media resolution, adjust rect to profile
100+
// Check if we have consumer scaling enabled since we cannot use *width and *height
101+
double consumerScaleX = MIN(1., mlt_properties_get_double(frame_properties,
102+
"qtblend_preview_scalingx"));
103+
double consumerScaleY = MIN(1., mlt_properties_get_double(frame_properties,
104+
"qtblend_preview_scalingy"));
105+
// Consumer scaling was already applied to b_width/b_height
106+
// Always request an image that follows the consumer aspect ratio
107+
double consumer_dar = normalized_width * consumer_ar / normalized_height;
108+
int tmpWidth = b_width;
109+
int tmpHeight = b_height;
110+
double scaleFactor = qMax(*width / rect.w, *height / rect.h);
111+
if (scaleFactor > 1.) {
112+
// Use the highest necessary resolution image
113+
tmpWidth *= scaleFactor;
114+
tmpHeight *= scaleFactor;
115+
}
116+
if (consumer_dar > b_dar) {
117+
*width = qBound(qRound(normalized_width * MIN(1., consumerScaleX)),
118+
tmpWidth,
119+
MLT_QTBLEND_MAX_DIMENSION);
120+
*height = qRound(*width * consumer_ar * normalized_height / normalized_width);
135121
} else {
136-
// First instance of a qtblend filter
137-
double scale = mlt_profile_scale_width(profile, *width);
138-
// Store consumer scaling for further uses
139-
mlt_properties_set_int(frame_properties, "qtblend_scaled", 1);
140-
mlt_properties_set_double(frame_properties, "qtblend_preview_scaling", scale);
141-
// Apply scaling
142-
if (scale != 1.0) {
143-
rect.x *= scale;
144-
rect.w *= scale;
145-
if (b_width < normalized_width) {
146-
// Adjust scale so that we don't request too small images
147-
scale = qBound(scale, normalized_width * scale / b_width, 1.);
148-
}
149-
// Apply consumer scaling to the source image
150-
b_width *= scale;
151-
b_height *= scale;
122+
*height = qBound(qRound(normalized_height * MIN(1., consumerScaleY)),
123+
tmpHeight,
124+
MLT_QTBLEND_MAX_DIMENSION);
125+
*width = qRound(*height * normalized_width / normalized_height / consumer_ar);
126+
}
127+
// Adjust rect to new scaling
128+
double scale = (double) *width / normalized_width;
129+
if (scale != 1.0) {
130+
rect.x *= scale;
131+
rect.w *= scale;
132+
}
133+
scale = (double) *height / normalized_height;
134+
if (scale != 1.0) {
135+
rect.y *= scale;
136+
rect.h *= scale;
137+
}
138+
} else {
139+
// First instance of a qtblend filter
140+
// Check if frame size is scaled)
141+
double scalex = mlt_profile_scale_width(profile, *width);
142+
double scaley = mlt_profile_scale_height(profile, *height);
143+
144+
// Store consumer scaling for further uses
145+
mlt_properties_set_int(frame_properties, "qtblend_scaled", 1);
146+
mlt_properties_set_double(frame_properties, "qtblend_preview_scalingx", scalex);
147+
mlt_properties_set_double(frame_properties, "qtblend_preview_scalingy", scaley);
148+
// Apply scaling
149+
if (scalex != 1.0) {
150+
rect.x *= scalex;
151+
rect.w *= scalex;
152+
if (b_width < normalized_width) {
153+
// Adjust scale so that we don't request too small images
154+
scalex = qBound(scalex, normalized_width * scalex / b_width, 1.);
152155
}
153-
scale = mlt_profile_scale_height(profile, *height);
154-
if (scale != 1.0) {
155-
rect.y *= scale;
156-
rect.h *= scale;
156+
// Apply consumer scaling to the source image
157+
if (scalex < 1.) {
158+
b_width *= scalex;
159+
b_height *= scalex;
157160
}
158161
}
159-
transform.translate(rect.x, rect.y);
160-
opacity = rect.o;
161-
hasAlpha = rect.o < 1 || rect.x != 0 || rect.y != 0 || rect.w != *width || rect.h != *height
162-
|| rect.w / b_dar < *height || rect.h * b_dar < *width || b_width < *width
163-
|| b_height < *height;
164-
} else {
165-
b_width = *width;
166-
b_height = *height;
167-
if (b_width < normalized_width || b_height < normalized_height) {
168-
hasAlpha = true;
162+
if (scaley != 1.0) {
163+
rect.y *= scaley;
164+
rect.h *= scaley;
169165
}
170166
}
167+
transform.translate(rect.x, rect.y);
168+
opacity = rect.o;
169+
hasAlpha = rect.o < 1 || rect.x != 0 || rect.y != 0 || rect.w != *width || rect.h != *height
170+
|| rect.w / b_dar < *height || rect.h * b_dar < *width || b_width < *width
171+
|| b_height < *height;
171172

172173
if (mlt_properties_get(properties, "rotation")) {
173174
double angle = mlt_properties_anim_get_double(properties, "rotation", position, length);

src/modules/qt/transition_qtblend.cpp

Lines changed: 60 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include <QPainter>
2626
#include <QTransform>
2727

28+
#define MLT_QTBLEND_MAX_DIMENSION (16000)
29+
2830
static int get_image(mlt_frame a_frame,
2931
uint8_t **image,
3032
mlt_image_format *format,
@@ -44,8 +46,6 @@ static int get_image(mlt_frame a_frame,
4446
bool hasAlpha = *format == mlt_image_rgba;
4547
double opacity = 1.0;
4648
QTransform transform;
47-
// reference rect
48-
mlt_rect rect;
4949

5050
// Determine length
5151
mlt_position length = mlt_transition_get_length(transition);
@@ -56,6 +56,15 @@ static int get_image(mlt_frame a_frame,
5656
mlt_profile profile = mlt_service_profile(MLT_TRANSITION_SERVICE(transition));
5757
int b_width = mlt_properties_get_int(b_properties, "meta.media.width");
5858
int b_height = mlt_properties_get_int(b_properties, "meta.media.height");
59+
int normalized_width = profile->width;
60+
int normalized_height = profile->height;
61+
62+
// reference rect
63+
mlt_rect rect = {0,
64+
0,
65+
normalized_width,
66+
normalized_height,
67+
1.0};
5968

6069
bool distort = mlt_properties_get_int(transition_properties, "distort");
6170
double consumer_ar = mlt_profile_sar(profile);
@@ -73,12 +82,14 @@ static int get_image(mlt_frame a_frame,
7382
}
7483
double b_ar = mlt_frame_get_aspect_ratio(b_frame);
7584
double b_dar = b_ar * b_width / b_height;
76-
double geometry_dar = consumer_ar * *width / *height;
77-
rect.w = -1;
78-
rect.h = -1;
85+
double geometry_dar = consumer_ar * normalized_width / normalized_height;
7986
double transformScale = 1.;
8087
// forceAlpha is true if some operation makes it mandatory to perform the alpha compositing, like padding or scaling
8188
bool forceAlpha = b_dar != geometry_dar;
89+
if (forceAlpha) {
90+
// Ensure we ask for an image with same dar as consumer
91+
b_width = geometry_dar * b_height;
92+
}
8293

8394
if (!distort && (b_height < *height || b_width < *width)) {
8495
// Source image is smaller than profile, request full frame
@@ -91,59 +102,58 @@ static int get_image(mlt_frame a_frame,
91102
b_height = *height;
92103
}
93104

94-
double scalex = mlt_profile_scale_width(profile, *width);
95-
double scaley = mlt_profile_scale_height(profile, *height);
96-
97-
if (scalex != 1.) {
98-
// We are using consumer scaling, fetch a lower resolution image too
99-
b_height *= scalex;
100-
b_width *= scaley;
101-
}
102-
int request_width = *width;
103-
int request_height = *height;
104-
105-
// Check transform
106105
if (mlt_properties_get(transition_properties, "rect")) {
107106
rect = mlt_properties_anim_get_rect(transition_properties, "rect", position, length);
108107
if (::strchr(mlt_properties_get(transition_properties, "rect"), '%')) {
109108
// We have percentage values, scale to frame size
110-
rect.x *= *width;
111-
rect.y *= *height;
112-
rect.w *= *width;
113-
rect.h *= *height;
114-
} else {
115-
// Adjust to preview scaling
116-
if (scalex != 1.0) {
117-
rect.x *= scalex;
118-
rect.w *= scalex;
119-
if (distort) {
120-
b_width *= scalex;
121-
}
122-
}
123-
if (scaley != 1.0) {
124-
rect.y *= scaley;
125-
rect.h *= scaley;
126-
if (distort) {
127-
b_height *= scaley;
128-
}
129-
}
109+
rect.x *= normalized_width;
110+
rect.y *= normalized_height;
111+
rect.w *= normalized_width;
112+
rect.h *= normalized_height;
130113
}
114+
} else {
115+
// Optimization, request profile sized image
116+
b_width = normalized_width;
117+
b_height = normalized_height;
118+
}
119+
int request_width = *width;
120+
int request_height = *height;
131121

132-
transform.translate(rect.x, rect.y);
133-
opacity = rect.o;
134-
if (!forceAlpha
135-
&& (opacity < 1 || rect.x != 0 || rect.y != 0 || (rect.x + rect.w != *width)
136-
|| (rect.y + rect.h != *height))) {
137-
// we will process operations on top frame, so also process b_frame
138-
forceAlpha = true;
122+
double scalex = mlt_profile_scale_width(profile, *width);
123+
double scaley = mlt_profile_scale_height(profile, *height);
124+
125+
// Adjust to preview scaling
126+
if (scalex != 1.0) {
127+
// We are using consumer scaling, fetch a lower resolution image too
128+
rect.x *= scalex;
129+
rect.w *= scalex;
130+
if (scalex < 1.) {
131+
b_width *= scalex;
139132
}
140-
// Ensure we don't request an image with a 0 width or height
141-
b_width = qMax(1, b_width);
142-
b_height = qMax(1, b_height);
143-
} else {
133+
}
134+
if (scaley != 1.0) {
135+
rect.y *= scaley;
136+
rect.h *= scaley;
137+
if (scaley < 1.) {
138+
b_height *= scaley;
139+
}
140+
}
141+
142+
transform.translate(rect.x, rect.y);
143+
opacity = rect.o;
144+
if (!forceAlpha
145+
&& (opacity < 1 || rect.x != 0 || rect.y != 0 || (rect.x + rect.w != *width)
146+
|| (rect.y + rect.h != *height))) {
147+
// we will process operations on top frame, so also process b_frame
148+
forceAlpha = true;
149+
}
150+
// Ensure we don't request an image with a 0 width or height
151+
b_width = qMax(1, b_width);
152+
b_height = qMax(1, b_height);
153+
/*} else {
144154
b_height = *height;
145155
b_width = *width;
146-
}
156+
}*/
147157

148158
if (mlt_frame_get_aspect_ratio(b_frame) == 0) {
149159
mlt_frame_set_aspect_ratio(b_frame, consumer_ar);
@@ -223,6 +233,7 @@ static int get_image(mlt_frame a_frame,
223233
*format = mlt_image_rgba;
224234
error = mlt_frame_get_image(b_frame, &b_image, format, &b_width, &b_height, 0);
225235
}
236+
226237
if (b_frame->convert_image && (*format != mlt_image_rgba)) {
227238
b_frame->convert_image(b_frame, &b_image, format, mlt_image_rgba);
228239
}

0 commit comments

Comments
 (0)