gtkglsink: Add overlay composition support
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Sat, 15 Aug 2015 13:12:27 +0000 (15:12 +0200)
committerNicolas Dufresne <nicolas.dufresne@collabora.com>
Sat, 15 Aug 2015 13:55:08 +0000 (15:55 +0200)
Rendering composition overlay in GL with additional high resolution
overlay being added.

ext/gtk/gstgtkglsink.c
ext/gtk/gstgtkglsink.h
ext/gtk/gtkgstglwidget.c

index cecad05..16797d3 100644 (file)
@@ -38,6 +38,8 @@ static gboolean gst_gtk_gl_sink_stop (GstBaseSink * bsink);
 static gboolean gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query);
 static gboolean gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink,
     GstQuery * query);
+static GstCaps *gst_gtk_gl_sink_get_caps (GstBaseSink * bsink,
+    GstCaps * filter);
 
 static GstStaticPadTemplate gst_gtk_gl_sink_template =
 GST_STATIC_PAD_TEMPLATE ("sink",
@@ -66,6 +68,7 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass)
   gstbasesink_class->propose_allocation = gst_gtk_gl_sink_propose_allocation;
   gstbasesink_class->start = gst_gtk_gl_sink_start;
   gstbasesink_class->stop = gst_gtk_gl_sink_stop;
+  gstbasesink_class->get_caps = gst_gtk_gl_sink_get_caps;
 
   gstgtkbasesink_class->create_widget = gtk_gst_gl_widget_new;
   gstgtkbasesink_class->window_title = "Gtk+ GL renderer";
@@ -133,6 +136,31 @@ gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query)
   return res;
 }
 
+static void
+_size_changed_cb (GtkWidget * widget, GdkRectangle * rectangle,
+    GstGtkGLSink * gtk_sink)
+{
+  gint scale_factor, width, height;
+  gboolean reconfigure;
+
+  scale_factor = gtk_widget_get_scale_factor (widget);
+  width = scale_factor * gtk_widget_get_allocated_width (widget);
+  height = scale_factor * gtk_widget_get_allocated_height (widget);
+
+  GST_OBJECT_LOCK (gtk_sink);
+  reconfigure =
+      (width != gtk_sink->display_width || height != gtk_sink->display_height);
+  gtk_sink->display_width = width;
+  gtk_sink->display_height = height;
+  GST_OBJECT_UNLOCK (gtk_sink);
+
+  if (reconfigure) {
+    GST_DEBUG_OBJECT (gtk_sink, "Sending reconfigure event on sinkpad.");
+    gst_pad_push_event (GST_BASE_SINK (gtk_sink)->sinkpad,
+        gst_event_new_reconfigure ());
+  }
+}
+
 static gboolean
 gst_gtk_gl_sink_start (GstBaseSink * bsink)
 {
@@ -146,6 +174,11 @@ gst_gtk_gl_sink_start (GstBaseSink * bsink)
   /* After this point, gtk_sink->widget will always be set */
   gst_widget = GTK_GST_GL_WIDGET (base_sink->widget);
 
+  /* Track the allocation size */
+  g_signal_connect (gst_widget, "size-allocate", G_CALLBACK (_size_changed_cb),
+      gtk_sink);
+  _size_changed_cb (GTK_WIDGET (gst_widget), NULL, gtk_sink);
+
   if (!gtk_gst_gl_widget_init_winsys (gst_widget))
     return FALSE;
 
@@ -191,6 +224,8 @@ gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
   GstCaps *caps;
   guint size;
   gboolean need_pool;
+  GstStructure *allocation_meta = NULL;
+  gint display_width, display_height;
 
   if (!gtk_sink->display || !gtk_sink->context)
     return FALSE;
@@ -222,6 +257,25 @@ gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
     gst_object_unref (pool);
   }
 
+  GST_OBJECT_LOCK (gtk_sink);
+  display_width = gtk_sink->display_width;
+  display_height = gtk_sink->display_height;
+  GST_OBJECT_UNLOCK (gtk_sink);
+
+  if (display_width != 0 && display_height != 0) {
+    GST_DEBUG_OBJECT (gtk_sink, "sending alloc query with size %dx%d",
+        display_width, display_height);
+    allocation_meta = gst_structure_new ("GstVideoOverlayCompositionMeta",
+        "width", G_TYPE_UINT, display_width,
+        "height", G_TYPE_UINT, display_height, NULL);
+  }
+
+  gst_query_add_allocation_meta (query,
+      GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, allocation_meta);
+
+  if (allocation_meta)
+    gst_structure_free (allocation_meta);
+
   /* we also support various metadata */
   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
 
@@ -247,3 +301,28 @@ config_failed:
     return FALSE;
   }
 }
+
+static GstCaps *
+gst_gtk_gl_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
+{
+  GstCaps *tmp = NULL;
+  GstCaps *result = NULL;
+
+  tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
+
+  if (filter) {
+    GST_DEBUG_OBJECT (bsink, "intersecting with filter caps %" GST_PTR_FORMAT,
+        filter);
+
+    result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (tmp);
+  } else {
+    result = tmp;
+  }
+
+  result = gst_gl_overlay_compositor_add_caps (result);
+
+  GST_DEBUG_OBJECT (bsink, "returning caps: %" GST_PTR_FORMAT, result);
+
+  return result;
+}
index dee1024..789cf33 100644 (file)
@@ -60,6 +60,10 @@ struct _GstGtkGLSink
 
   GstGLUpload          *upload;
   GstBuffer            *uploaded_buffer;
+
+  /* read/write with object lock */
+  gint                  display_width;
+  gint                  display_height;
 };
 
 /**
index dc24535..cdce3aa 100644 (file)
@@ -71,6 +71,7 @@ struct _GtkGstGLWidgetPrivate
   GLint attr_position;
   GLint attr_texture;
   GLuint current_tex;
+  GstGLOverlayCompositor *overlay_compositor;
 };
 
 static const GLfloat vertices[] = {
@@ -140,6 +141,9 @@ gtk_gst_gl_widget_init_redisplay (GtkGstGLWidget * gst_widget)
 
   gl->BindBuffer (GL_ARRAY_BUFFER, 0);
 
+  priv->overlay_compositor =
+      gst_gl_overlay_compositor_new (priv->other_context);
+
   priv->initted = TRUE;
 }
 
@@ -237,6 +241,8 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context)
       goto done;
     }
 
+    gst_gl_overlay_compositor_upload_overlays (priv->overlay_compositor,
+        buffer);
 
     sync_meta = gst_buffer_get_gl_sync_meta (buffer);
     if (sync_meta) {
@@ -260,6 +266,7 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context)
       base_widget->buffer, context);
 
   _redraw_texture (GTK_GST_GL_WIDGET (widget), priv->current_tex);
+  gst_gl_overlay_compositor_draw_overlays (priv->overlay_compositor);
 
 done:
   if (priv->other_context)
@@ -350,6 +357,9 @@ _reset_gl (GtkGstGLWidget * gst_widget)
     priv->shader = NULL;
   }
 
+  if (priv->overlay_compositor)
+    gst_object_unref (priv->overlay_compositor);
+
   gst_gl_context_activate (priv->other_context, FALSE);
 
   gst_object_unref (priv->other_context);