summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2025-05-31 02:40:14 +0200
committerCarl Hetherington <cth@carlh.net>2025-06-17 00:04:03 +0200
commit2d2245b1e5824aae958e54b33670a461323f9bd6 (patch)
tree99a2ac57fcd25ab34463409a44ce64ffe88f4253
parent0237f40ca78f5d08fb8d1ce9c10a6ca1a3762837 (diff)
Support content crop in the GL backend.
-rw-r--r--src/wx/gl_video_view.cc36
-rw-r--r--src/wx/gl_video_view.h2
2 files changed, 28 insertions, 10 deletions
diff --git a/src/wx/gl_video_view.cc b/src/wx/gl_video_view.cc
index f9096be82..4ca5af21a 100644
--- a/src/wx/gl_video_view.cc
+++ b/src/wx/gl_video_view.cc
@@ -655,7 +655,7 @@ GLVideoView::set_image(shared_ptr<const PlayerVideo> pv)
video = Image::ensure_alignment(video, Image::Alignment::COMPACT);
/** If _optimisation is J2K we render a XYZ image, doing the colourspace
- * conversion, scaling and video range conversion in the GL shader.
+ * conversion, cropping, scaling and video range conversion in the GL shader.
* Similarly for MPEG2 we do YUV -> RGB and scaling in the shader.
* Otherwise we render a RGB image without any shader-side processing.
*/
@@ -682,6 +682,7 @@ GLVideoView::set_image(shared_ptr<const PlayerVideo> pv)
auto const inter_position = pv->inter_position();
auto const inter_size = pv->inter_size();
auto const out_size = pv->out_size();
+ auto const crop = pv->crop();
auto const crop_guess = _viewer->crop_guess();
auto x_offset = std::max(0, (canvas_width - out_size.width) / 2);
@@ -692,13 +693,15 @@ GLVideoView::set_image(shared_ptr<const PlayerVideo> pv)
_last_inter_position.set_next(inter_position);
_last_inter_size.set_next(inter_size);
_last_out_size.set_next(out_size);
+ _last_crop.set_next(crop);
_last_crop_guess.set_next(crop_guess);
class Rectangle
{
public:
- Rectangle(wxSize canvas_size, float x, float y, dcp::Size size)
+ Rectangle(wxSize canvas_size, float x, float y, dcp::Size size, Crop crop)
: _canvas_size(canvas_size)
+ , _crop(crop)
{
auto const x1 = x_pixels_to_gl(x);
auto const y1 = y_pixels_to_gl(y);
@@ -750,29 +753,34 @@ GLVideoView::set_image(shared_ptr<const PlayerVideo> pv)
private:
/* @param x x position in pixels where 0 is left and canvas_width is right on screen */
float x_pixels_to_gl(int x) const {
- return (x * 2.0f / _canvas_size.GetWidth()) - 1.0f;
+ return ((x - _crop.left) * 2.0f / (_canvas_size.GetWidth() - _crop.right - _crop.left) - 1.0f);
}
/* @param y y position in pixels where 0 is top and canvas_height is bottom on screen */
float y_pixels_to_gl(int y) const {
- return 1.0f - (y * 2.0f / _canvas_size.GetHeight());
+ return 1.0f - ((y - _crop.top) * 2.0f / (_canvas_size.GetHeight() - _crop.bottom - _crop.top));
}
wxSize _canvas_size;
+ Crop _crop;
float _vertices[20];
};
- auto const sizing_changed = _last_canvas_size.changed() || _last_inter_position.changed() || _last_inter_size.changed() || _last_out_size.changed();
+ auto const sizing_changed = _last_canvas_size.changed() ||
+ _last_inter_position.changed() ||
+ _last_inter_size.changed() ||
+ _last_out_size.changed() ||
+ _last_crop.changed();
if (sizing_changed) {
const auto video = _optimisation == Optimisation::NONE
- ? Rectangle(canvas_size, x_offset, y_offset, out_size)
- : Rectangle(canvas_size, inter_position.x + x_offset, inter_position.y + y_offset, inter_size);
+ ? Rectangle(canvas_size, x_offset, y_offset, out_size, crop)
+ : Rectangle(canvas_size, inter_position.x + x_offset, inter_position.y + y_offset, inter_size, crop);
glBufferSubData(GL_ARRAY_BUFFER, array_buffer_video_offset, video.size(), video.vertices());
check_gl_error("glBufferSubData (video)");
- const auto outline_content = Rectangle(canvas_size, inter_position.x + x_offset, inter_position.y + y_offset, inter_size);
+ const auto outline_content = Rectangle(canvas_size, inter_position.x + x_offset, inter_position.y + y_offset, inter_size, crop);
glBufferSubData(GL_ARRAY_BUFFER, array_buffer_outline_content_offset, outline_content.size(), outline_content.vertices());
check_gl_error("glBufferSubData (outline_content)");
}
@@ -782,14 +790,22 @@ GLVideoView::set_image(shared_ptr<const PlayerVideo> pv)
canvas_size,
inter_position.x + x_offset + inter_size.width * crop_guess->x,
inter_position.y + y_offset + inter_size.height * crop_guess->y,
- dcp::Size(inter_size.width * crop_guess->width, inter_size.height * crop_guess->height)
+ dcp::Size(inter_size.width * crop_guess->width, inter_size.height * crop_guess->height),
+ crop
);
glBufferSubData(GL_ARRAY_BUFFER, array_buffer_crop_guess_offset, crop_guess_rectangle.size(), crop_guess_rectangle.vertices());
check_gl_error("glBufferSubData (crop_guess_rectangle)");
}
if (_have_subtitle_to_render) {
- const auto subtitle = Rectangle(canvas_size, inter_position.x + x_offset + text->position.x, inter_position.y + y_offset + text->position.y, text->image->size());
+ const auto subtitle = Rectangle(
+ canvas_size,
+ inter_position.x + x_offset + text->position.x,
+ inter_position.y + y_offset + text->position.y,
+ text->image->size(),
+ crop
+ );
+
glBufferSubData(GL_ARRAY_BUFFER, array_buffer_subtitle_offset, subtitle.size(), subtitle.vertices());
check_gl_error("glBufferSubData (subtitle)");
}
diff --git a/src/wx/gl_video_view.h b/src/wx/gl_video_view.h
index dc048e6b0..d915636af 100644
--- a/src/wx/gl_video_view.h
+++ b/src/wx/gl_video_view.h
@@ -19,6 +19,7 @@
*/
+#include "lib/crop.h"
#include <dcp/warnings.h>
LIBDCP_DISABLE_WARNINGS
#include <wx/glcanvas.h>
@@ -134,6 +135,7 @@ private:
Last<Position<int>> _last_inter_position;
Last<dcp::Size> _last_inter_size;
Last<dcp::Size> _last_out_size;
+ Last<Crop> _last_crop;
Last<boost::optional<dcpomatic::Rect<float>>> _last_crop_guess;
boost::atomic<wxSize> _canvas_size;