From d91d0f1c0a23dc682ebcf7a06bde0540e3e8225a Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 3 Feb 2024 11:32:07 +0100 Subject: [PATCH] gstreamer: Pass viewport along Obtain the viewport from gstreamer, and pass it to the paintable implemenation, which adds a clip node around the texture to enforce the viewport. --- modules/media/gtkgstpaintable.c | 52 +++++++++++++++++++------- modules/media/gtkgstpaintableprivate.h | 4 +- modules/media/gtkgstsink.c | 22 +++++++---- 3 files changed, 55 insertions(+), 23 deletions(-) diff --git a/modules/media/gtkgstpaintable.c b/modules/media/gtkgstpaintable.c index 8abf4a2a6e..e2cbf96041 100644 --- a/modules/media/gtkgstpaintable.c +++ b/modules/media/gtkgstpaintable.c @@ -24,6 +24,7 @@ #include #include +#include #include @@ -33,6 +34,7 @@ struct _GtkGstPaintable GdkPaintable *image; double pixel_aspect_ratio; + graphene_rect_t viewport; GdkGLContext *context; }; @@ -51,7 +53,24 @@ gtk_gst_paintable_paintable_snapshot (GdkPaintable *paintable, GtkGstPaintable *self = GTK_GST_PAINTABLE (paintable); if (self->image) - gdk_paintable_snapshot (self->image, snapshot, width, height); + { + float sx, sy; + + gtk_snapshot_save (snapshot); + + sx = gdk_paintable_get_intrinsic_width (self->image) / self->viewport.size.width; + sy = gdk_paintable_get_intrinsic_height (self->image) / self->viewport.size.height; + + gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height)); + + gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (-self->viewport.origin.x * width / self->viewport.size.width, + -self->viewport.origin.y * height / self->viewport.size.height)); + + gdk_paintable_snapshot (self->image, snapshot, width * sx, height * sy); + + gtk_snapshot_pop (snapshot); + gtk_snapshot_restore (snapshot); + } } static GdkPaintable * @@ -71,8 +90,7 @@ gtk_gst_paintable_paintable_get_intrinsic_width (GdkPaintable *paintable) GtkGstPaintable *self = GTK_GST_PAINTABLE (paintable); if (self->image) - return round (self->pixel_aspect_ratio * - gdk_paintable_get_intrinsic_width (self->image)); + return round (self->pixel_aspect_ratio * self->viewport.size.width); return 0; } @@ -83,7 +101,7 @@ gtk_gst_paintable_paintable_get_intrinsic_height (GdkPaintable *paintable) GtkGstPaintable *self = GTK_GST_PAINTABLE (paintable); if (self->image) - return gdk_paintable_get_intrinsic_height (self->image); + return ceil (self->viewport.size.height); return 0; } @@ -94,8 +112,7 @@ gtk_gst_paintable_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable) GtkGstPaintable *self = GTK_GST_PAINTABLE (paintable); if (self->image) - return self->pixel_aspect_ratio * - gdk_paintable_get_intrinsic_aspect_ratio (self->image); + return self->viewport.size.width / self->viewport.size.height; return 0.0; }; @@ -237,9 +254,10 @@ gtk_gst_paintable_unrealize (GtkGstPaintable *self, } static void -gtk_gst_paintable_set_paintable (GtkGstPaintable *self, - GdkPaintable *paintable, - double pixel_aspect_ratio) +gtk_gst_paintable_set_paintable (GtkGstPaintable *self, + GdkPaintable *paintable, + double pixel_aspect_ratio, + const graphene_rect_t *viewport) { gboolean size_changed; @@ -250,13 +268,15 @@ gtk_gst_paintable_set_paintable (GtkGstPaintable *self, self->pixel_aspect_ratio * gdk_paintable_get_intrinsic_width (self->image) != pixel_aspect_ratio * gdk_paintable_get_intrinsic_width (paintable) || gdk_paintable_get_intrinsic_height (self->image) != gdk_paintable_get_intrinsic_height (paintable) || - gdk_paintable_get_intrinsic_aspect_ratio (self->image) != gdk_paintable_get_intrinsic_aspect_ratio (paintable)) + gdk_paintable_get_intrinsic_aspect_ratio (self->image) != gdk_paintable_get_intrinsic_aspect_ratio (paintable) || + !graphene_rect_equal (viewport, &self->viewport)) size_changed = TRUE; else size_changed = FALSE; g_set_object (&self->image, paintable); self->pixel_aspect_ratio = pixel_aspect_ratio; + self->viewport = *viewport; if (size_changed) gdk_paintable_invalidate_size (GDK_PAINTABLE (self)); @@ -270,6 +290,7 @@ struct _SetTextureInvocation { GtkGstPaintable *paintable; GdkTexture *texture; double pixel_aspect_ratio; + graphene_rect_t viewport; }; static void @@ -288,15 +309,17 @@ gtk_gst_paintable_set_texture_invoke (gpointer data) gtk_gst_paintable_set_paintable (invoke->paintable, GDK_PAINTABLE (invoke->texture), - invoke->pixel_aspect_ratio); + invoke->pixel_aspect_ratio, + &invoke->viewport); return G_SOURCE_REMOVE; } void -gtk_gst_paintable_queue_set_texture (GtkGstPaintable *self, - GdkTexture *texture, - double pixel_aspect_ratio) +gtk_gst_paintable_queue_set_texture (GtkGstPaintable *self, + GdkTexture *texture, + double pixel_aspect_ratio, + const graphene_rect_t *viewport) { SetTextureInvocation *invoke; @@ -304,6 +327,7 @@ gtk_gst_paintable_queue_set_texture (GtkGstPaintable *self, invoke->paintable = g_object_ref (self); invoke->texture = g_object_ref (texture); invoke->pixel_aspect_ratio = pixel_aspect_ratio; + invoke->viewport = *viewport; g_main_context_invoke_full (NULL, G_PRIORITY_DEFAULT, diff --git a/modules/media/gtkgstpaintableprivate.h b/modules/media/gtkgstpaintableprivate.h index 44d5a31e61..71854afad3 100644 --- a/modules/media/gtkgstpaintableprivate.h +++ b/modules/media/gtkgstpaintableprivate.h @@ -20,6 +20,7 @@ #pragma once #include +#include G_BEGIN_DECLS @@ -35,6 +36,7 @@ void gtk_gst_paintable_unrealize (GtkGstPaintable GdkSurface *surface); void gtk_gst_paintable_queue_set_texture (GtkGstPaintable *self, GdkTexture *texture, - double pixel_aspect_ratio); + double pixel_aspect_ratio, + const graphene_rect_t *viewport); G_END_DECLS diff --git a/modules/media/gtkgstsink.c b/modules/media/gtkgstsink.c index 49010ba6aa..525d67c71c 100644 --- a/modules/media/gtkgstsink.c +++ b/modules/media/gtkgstsink.c @@ -358,13 +358,19 @@ video_frame_free (GstVideoFrame *frame) } static GdkTexture * -gtk_gst_sink_texture_from_buffer (GtkGstSink *self, - GstBuffer *buffer, - double *pixel_aspect_ratio) +gtk_gst_sink_texture_from_buffer (GtkGstSink *self, + GstBuffer *buffer, + double *pixel_aspect_ratio, + graphene_rect_t *viewport) { GstVideoFrame *frame = g_new (GstVideoFrame, 1); GdkTexture *texture; + viewport->origin.x = 0; + viewport->origin.y = 0; + viewport->size.width = GST_VIDEO_INFO_WIDTH (&self->v_info); + viewport->size.height = GST_VIDEO_INFO_HEIGHT (&self->v_info); + #ifdef HAVE_GSTREAMER_DRM if (gst_is_dmabuf_memory (gst_buffer_peek_memory (buffer, 0))) { @@ -384,9 +390,8 @@ gtk_gst_sink_texture_from_buffer (GtkGstSink *self, gdk_dmabuf_texture_builder_set_display (builder, gdk_gl_context_get_display (self->gdk_context)); gdk_dmabuf_texture_builder_set_fourcc (builder, self->drm_info.drm_fourcc); gdk_dmabuf_texture_builder_set_modifier (builder, self->drm_info.drm_modifier); - // Padded width/height is set into the vmeta, perhaps we should import using these ? - gdk_dmabuf_texture_builder_set_width (builder, GST_VIDEO_INFO_WIDTH (&self->v_info)); - gdk_dmabuf_texture_builder_set_height (builder, GST_VIDEO_INFO_HEIGHT (&self->v_info)); + gdk_dmabuf_texture_builder_set_width (builder, vmeta->width); + gdk_dmabuf_texture_builder_set_height (builder, vmeta->height); gdk_dmabuf_texture_builder_set_n_planes (builder, vmeta->n_planes); for (i = 0; i < vmeta->n_planes; i++) @@ -491,6 +496,7 @@ gtk_gst_sink_show_frame (GstVideoSink *vsink, GtkGstSink *self; GdkTexture *texture; double pixel_aspect_ratio; + graphene_rect_t viewport; GST_TRACE ("rendering buffer:%p", buf); @@ -498,10 +504,10 @@ gtk_gst_sink_show_frame (GstVideoSink *vsink, GST_OBJECT_LOCK (self); - texture = gtk_gst_sink_texture_from_buffer (self, buf, &pixel_aspect_ratio); + texture = gtk_gst_sink_texture_from_buffer (self, buf, &pixel_aspect_ratio, &viewport); if (texture) { - gtk_gst_paintable_queue_set_texture (self->paintable, texture, pixel_aspect_ratio); + gtk_gst_paintable_queue_set_texture (self->paintable, texture, pixel_aspect_ratio, &viewport); g_object_unref (texture); }