glimagesink: implement as a bin
authorMatthew Waters <matthew@centricular.com>
Fri, 20 Feb 2015 05:47:01 +0000 (16:47 +1100)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:31:57 +0000 (19:31 +0000)
glupload ! glcolorconvert ! sink

Some properties are manually forwarded.  The rest are available using
GstChildProxy.

The two signals are forwarded as well.

ext/gl/gstglimagesink.c
ext/gl/gstglimagesink.h
ext/gl/gstopengl.c

index f1a27f9c2491e508f76c9e4ef3657ee16f9a855d..8ea7d461920ee847bc9bb954431814fe08162733 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (C) 2003 Julien Moutte <julien@moutte.net>
  * Copyright (C) 2005,2006,2007 David A. Schleef <ds@schleef.org>
  * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
+ * Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -90,6 +91,7 @@
 #include <gst/video/navigation.h>
 
 #include "gstglimagesink.h"
+#include "gstglsinkbin.h"
 
 #if GST_GL_HAVE_PLATFORM_EGL
 #include <gst/gl/egl/gsteglimagememory.h>
 GST_DEBUG_CATEGORY (gst_debug_glimage_sink);
 #define GST_CAT_DEFAULT gst_debug_glimage_sink
 
+typedef GstGLSinkBin GstGLImageSinkBin;
+typedef GstGLSinkBinClass GstGLImageSinkBinClass;
+
+G_DEFINE_TYPE (GstGLImageSinkBin, gst_gl_image_sink_bin, GST_TYPE_GL_SINK_BIN);
+
+enum
+{
+  PROP_BIN_0,
+  PROP_BIN_FORCE_ASPECT_RATIO,
+  PROP_BIN_LAST_SAMPLE,
+};
+
+enum
+{
+  SIGNAL_BIN_0,
+  SIGNAL_BIN_CLIENT_DRAW,
+  SIGNAL_BIN_CLIENT_RESHAPE,
+  SIGNAL_BIN_LAST,
+};
+
+static guint gst_gl_image_sink_bin_signals[SIGNAL_BIN_LAST] = { 0 };
+
+static void
+gst_gl_image_sink_bin_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * param_spec)
+{
+  g_object_set_property (G_OBJECT (GST_GL_SINK_BIN (object)->sink),
+      param_spec->name, value);
+}
+
+static void
+gst_gl_image_sink_bin_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * param_spec)
+{
+  g_object_get_property (G_OBJECT (GST_GL_SINK_BIN (object)->sink),
+      param_spec->name, value);
+}
+
+static gboolean
+_on_client_reshape (GstGLImageSink * sink, GstGLContext * context,
+    guint width, guint height, gpointer data)
+{
+  gboolean ret;
+
+  g_signal_emit (data, gst_gl_image_sink_bin_signals[SIGNAL_BIN_CLIENT_RESHAPE],
+      0, context, width, height, &ret);
+
+  return ret;
+}
+
+static gboolean
+_on_client_draw (GstGLImageSink * sink, GstGLContext * context,
+    guint tex_id, guint width, guint height, gpointer data)
+{
+  gboolean ret;
+
+  g_signal_emit (data, gst_gl_image_sink_bin_signals[SIGNAL_BIN_CLIENT_DRAW], 0,
+      context, tex_id, width, height, &ret);
+
+  return ret;
+}
+
+static void
+gst_gl_image_sink_bin_init (GstGLImageSinkBin * self)
+{
+  GstGLImageSink *sink = g_object_new (GST_TYPE_GLIMAGE_SINK, NULL);
+
+  g_signal_connect (sink, "client-reshape", (GCallback) _on_client_reshape,
+      self);
+  g_signal_connect (sink, "client-draw", (GCallback) _on_client_draw, self);
+
+  gst_gl_sink_bin_finish_init_with_element (GST_GL_SINK_BIN (self),
+      GST_ELEMENT (sink));
+}
+
+static void
+gst_gl_image_sink_bin_class_init (GstGLImageSinkBinClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->get_property = gst_gl_image_sink_bin_get_property;
+  gobject_class->set_property = gst_gl_image_sink_bin_set_property;
+
+  g_object_class_install_property (gobject_class, PROP_BIN_FORCE_ASPECT_RATIO,
+      g_param_spec_boolean ("force-aspect-ratio",
+          "Force aspect ratio",
+          "When enabled, scaling will respect original aspect ratio", TRUE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_BIN_LAST_SAMPLE,
+      g_param_spec_boxed ("last-sample", "Last Sample",
+          "The last sample received in the sink", GST_TYPE_SAMPLE,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_gl_image_sink_bin_signals[SIGNAL_BIN_CLIENT_DRAW] =
+      g_signal_new ("client-draw", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
+      G_TYPE_BOOLEAN, 4, GST_GL_TYPE_CONTEXT,
+      G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
+
+  gst_gl_image_sink_bin_signals[SIGNAL_BIN_CLIENT_RESHAPE] =
+      g_signal_new ("client-reshape", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
+      G_TYPE_BOOLEAN, 3, GST_GL_TYPE_CONTEXT, G_TYPE_UINT, G_TYPE_UINT);
+}
+
 #define GST_GLIMAGE_SINK_GET_LOCK(glsink) \
   (GST_GLIMAGE_SINK(glsink)->drawing_lock)
 #define GST_GLIMAGE_SINK_LOCK(glsink) \
@@ -159,19 +267,12 @@ gst_glimage_sink_handle_events (GstVideoOverlay * overlay,
     gboolean handle_events);
 
 static GstStaticPadTemplate gst_glimage_sink_template =
-    GST_STATIC_PAD_TEMPLATE ("sink",
+GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
         (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
-            "RGBA") "; "
-#if GST_GL_HAVE_PLATFORM_EGL
-        GST_VIDEO_CAPS_MAKE_WITH_FEATURES
-        (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE, "RGBA") "; "
-#endif
-        GST_VIDEO_CAPS_MAKE_WITH_FEATURES
-        (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
-            "RGBA") "; " GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS))
+            "RGBA"))
     );
 
 enum
@@ -502,6 +603,46 @@ gst_glimage_sink_mouse_event_cb (GstGLWindow * window, char *event_name,
       event_name, button, posx, posy);
 }
 
+static gboolean
+_find_local_gl_context (GstGLImageSink * gl_sink)
+{
+  GstQuery *query;
+  GstContext *context;
+  const GstStructure *s;
+
+  if (gl_sink->context)
+    return TRUE;
+
+  query = gst_query_new_context ("gst.gl.local_context");
+  if (!gl_sink->context
+      && gst_gl_run_query (GST_ELEMENT (gl_sink), query, GST_PAD_SRC)) {
+    gst_query_parse_context (query, &context);
+    if (context) {
+      s = gst_context_get_structure (context);
+      gst_structure_get (s, "context", GST_GL_TYPE_CONTEXT, &gl_sink->context,
+          NULL);
+    }
+  }
+  if (!gl_sink->context
+      && gst_gl_run_query (GST_ELEMENT (gl_sink), query, GST_PAD_SINK)) {
+    gst_query_parse_context (query, &context);
+    if (context) {
+      s = gst_context_get_structure (context);
+      gst_structure_get (s, "context", GST_GL_TYPE_CONTEXT, &gl_sink->context,
+          NULL);
+    }
+  }
+
+  GST_ERROR_OBJECT (gl_sink, "found local context %p", gl_sink->context);
+
+  gst_query_unref (query);
+
+  if (gl_sink->context)
+    return TRUE;
+
+  return FALSE;
+}
+
 static gboolean
 _ensure_gl_setup (GstGLImageSink * gl_sink)
 {
@@ -574,6 +715,8 @@ _ensure_gl_setup (GstGLImageSink * gl_sink)
   } else
     GST_DEBUG_OBJECT (gl_sink, "Already have a context");
 
+  _find_local_gl_context (gl_sink);
+
   return TRUE;
 
 context_creation_error:
@@ -602,11 +745,39 @@ gst_glimage_sink_query (GstBaseSink * bsink, GstQuery * query)
   switch (GST_QUERY_TYPE (query)) {
     case GST_QUERY_CONTEXT:
     {
-      gboolean ret =
+      const gchar *context_type;
+      GstContext *context, *old_context;
+      gboolean ret;
+
+      ret =
           gst_gl_handle_context_query ((GstElement *) glimage_sink, query,
           &glimage_sink->display, &glimage_sink->other_context);
       if (glimage_sink->display)
         gst_gl_display_filter_gl_api (glimage_sink->display, SUPPORTED_GL_APIS);
+
+      gst_query_parse_context_type (query, &context_type);
+
+      if (g_strcmp0 (context_type, "gst.gl.local_context") == 0) {
+        GstStructure *s;
+
+        gst_query_parse_context (query, &old_context);
+
+        if (old_context)
+          context = gst_context_copy (old_context);
+        else
+          context = gst_context_new ("gst.gl.local_context", FALSE);
+
+        s = gst_context_writable_structure (context);
+        gst_structure_set (s, "context", GST_GL_TYPE_CONTEXT,
+            glimage_sink->context, NULL);
+        gst_query_set_context (query, context);
+        gst_context_unref (context);
+
+        ret = glimage_sink->context != NULL;
+      }
+      GST_DEBUG_OBJECT (glimage_sink, "context query of type %s %i",
+          context_type, ret);
+
       return ret;
     }
     case GST_QUERY_DRAIN:
@@ -623,7 +794,6 @@ gst_glimage_sink_query (GstBaseSink * bsink, GstQuery * query)
         gst_buffer_unref (buf);
 
       gst_buffer_replace (&glimage_sink->next_buffer, NULL);
-      gst_gl_upload_release_buffer (glimage_sink->upload);
 
       res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query);
       break;
@@ -646,11 +816,6 @@ gst_glimage_sink_stop (GstBaseSink * bsink)
     glimage_sink->pool = NULL;
   }
 
-  if (glimage_sink->gl_caps) {
-    gst_caps_unref (glimage_sink->gl_caps);
-    glimage_sink->gl_caps = NULL;
-  }
-
   return TRUE;
 }
 
@@ -711,16 +876,6 @@ gst_glimage_sink_change_state (GstElement * element, GstStateChange transition)
       GST_GLIMAGE_SINK_UNLOCK (glimage_sink);
       gst_buffer_replace (&glimage_sink->next_buffer, NULL);
 
-      if (glimage_sink->upload) {
-        gst_object_unref (glimage_sink->upload);
-        glimage_sink->upload = NULL;
-      }
-
-      if (glimage_sink->convert) {
-        gst_object_unref (glimage_sink->convert);
-        glimage_sink->convert = NULL;
-      }
-
       glimage_sink->window_id = 0;
       /* but do not reset glimage_sink->new_window_id */
 
@@ -782,25 +937,11 @@ gst_glimage_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
 static GstCaps *
 gst_glimage_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
 {
-  GstGLImageSink *gl_sink = GST_GLIMAGE_SINK (bsink);
   GstCaps *tmp = NULL;
   GstCaps *result = NULL;
 
   tmp = gst_caps_from_string ("video/x-raw(memory:GLMemory),format=RGBA");
 
-  result =
-      gst_gl_color_convert_transform_caps (gl_sink->context, GST_PAD_SRC, tmp,
-      NULL);
-  gst_caps_unref (tmp);
-  tmp = result;
-  GST_DEBUG_OBJECT (bsink, "convert returned caps %" GST_PTR_FORMAT, tmp);
-
-  result =
-      gst_gl_upload_transform_caps (gl_sink->context, GST_PAD_SRC, tmp, NULL);
-  gst_caps_unref (tmp);
-  tmp = result;
-  GST_DEBUG_OBJECT (bsink, "transfer returned caps %" GST_PTR_FORMAT, tmp);
-
   if (filter) {
     result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
     gst_caps_unref (tmp);
@@ -824,8 +965,6 @@ gst_glimage_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
   gint display_par_n, display_par_d;
   guint display_ratio_num, display_ratio_den;
   GstVideoInfo vinfo;
-  GstCapsFeatures *gl_features;
-  GstCaps *uploaded_caps;
 
   GST_DEBUG_OBJECT (bsink, "set caps with %" GST_PTR_FORMAT, caps);
 
@@ -888,38 +1027,6 @@ gst_glimage_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
   if (!_ensure_gl_setup (glimage_sink))
     return FALSE;
 
-  if (glimage_sink->upload)
-    gst_object_unref (glimage_sink->upload);
-  glimage_sink->upload = gst_gl_upload_new (glimage_sink->context);
-
-  gl_features =
-      gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
-
-  uploaded_caps = gst_caps_copy (caps);
-  gst_caps_set_features (uploaded_caps, 0,
-      gst_caps_features_copy (gl_features));
-  gst_gl_upload_set_caps (glimage_sink->upload, caps, uploaded_caps);
-
-  if (glimage_sink->gl_caps)
-    gst_caps_unref (glimage_sink->gl_caps);
-  glimage_sink->gl_caps = gst_caps_copy (caps);
-  gst_caps_set_simple (glimage_sink->gl_caps, "format", G_TYPE_STRING, "RGBA",
-      NULL);
-  gst_caps_set_features (glimage_sink->gl_caps, 0,
-      gst_caps_features_copy (gl_features));
-
-  if (glimage_sink->convert)
-    gst_object_unref (glimage_sink->convert);
-  glimage_sink->convert = gst_gl_color_convert_new (glimage_sink->context);
-  if (!gst_gl_color_convert_set_caps (glimage_sink->convert, uploaded_caps,
-          glimage_sink->gl_caps)) {
-    gst_caps_unref (uploaded_caps);
-    gst_caps_features_free (gl_features);
-    return FALSE;
-  }
-  gst_caps_unref (uploaded_caps);
-  gst_caps_features_free (gl_features);
-
   glimage_sink->caps_change = TRUE;
 
   return TRUE;
@@ -929,9 +1036,7 @@ static GstFlowReturn
 gst_glimage_sink_prepare (GstBaseSink * bsink, GstBuffer * buf)
 {
   GstGLImageSink *glimage_sink;
-  GstBuffer *uploaded_buffer, *next_buffer = NULL;
   GstVideoFrame gl_frame;
-  GstVideoInfo gl_info;
 
   glimage_sink = GST_GLIMAGE_SINK (bsink);
 
@@ -945,31 +1050,14 @@ gst_glimage_sink_prepare (GstBaseSink * bsink, GstBuffer * buf)
   if (!_ensure_gl_setup (glimage_sink))
     return GST_FLOW_NOT_NEGOTIATED;
 
-  if (gst_gl_upload_perform_with_buffer (glimage_sink->upload, buf,
-          &uploaded_buffer) != GST_GL_UPLOAD_DONE)
-    goto upload_failed;
-
-  if (!(next_buffer =
-          gst_gl_color_convert_perform (glimage_sink->convert,
-              uploaded_buffer))) {
-    gst_buffer_unref (uploaded_buffer);
-    goto upload_failed;
-  }
-
-  gst_video_info_from_caps (&gl_info, glimage_sink->gl_caps);
-
-  if (!gst_video_frame_map (&gl_frame, &gl_info, next_buffer,
+  if (!gst_video_frame_map (&gl_frame, &glimage_sink->info, buf,
           GST_MAP_READ | GST_MAP_GL)) {
-    gst_buffer_unref (uploaded_buffer);
-    gst_buffer_unref (next_buffer);
     goto upload_failed;
   }
-  gst_buffer_unref (uploaded_buffer);
 
   glimage_sink->next_tex = *(guint *) gl_frame.data[0];
 
-  gst_buffer_replace (&glimage_sink->next_buffer, next_buffer);
-  gst_buffer_unref (next_buffer);
+  gst_buffer_replace (&glimage_sink->next_buffer, buf);
 
   gst_video_frame_unmap (&gl_frame);
 
@@ -1027,7 +1115,6 @@ gst_glimage_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
   if (g_atomic_int_get (&glimage_sink->to_quit) != 0) {
     GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND,
         ("%s", gst_gl_context_get_error ()), (NULL));
-    gst_gl_upload_release_buffer (glimage_sink->upload);
     return GST_FLOW_ERROR;
   }
 
@@ -1036,14 +1123,12 @@ gst_glimage_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
 /* ERRORS */
 redisplay_failed:
   {
-    gst_gl_upload_release_buffer (glimage_sink->upload);
     GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND,
         ("%s", gst_gl_context_get_error ()), (NULL));
     return GST_FLOW_ERROR;
   }
 }
 
-
 static void
 gst_glimage_sink_video_overlay_init (GstVideoOverlayInterface * iface)
 {
@@ -1052,7 +1137,6 @@ gst_glimage_sink_video_overlay_init (GstVideoOverlayInterface * iface)
   iface->expose = gst_glimage_sink_expose;
 }
 
-
 static void
 gst_glimage_sink_set_window_handle (GstVideoOverlay * overlay, guintptr id)
 {
@@ -1161,8 +1245,6 @@ gst_glimage_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
     gst_query_add_allocation_pool (query, glimage_sink->pool, size, 2, 0);
   }
 
-  gst_gl_upload_propose_allocation (glimage_sink->upload, NULL, query);
-
   if (glimage_sink->context->gl_vtable->FenceSync)
     gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0);
 
index 01851a4d491a1d7a1faa0dce9cf37cd8e0942ce2..1eed7b39970b1dfdb23a169620d6891874c7c80d 100644 (file)
@@ -61,7 +61,6 @@ struct _GstGLImageSink
 
     //caps
     GstVideoInfo info;
-    GstCaps *gl_caps;
 
     GstGLDisplay *display;
     GstGLContext *context;
@@ -69,8 +68,6 @@ struct _GstGLImageSink
     gboolean handle_events;
     gboolean ignore_alpha;
 
-    GstGLUpload *upload;
-    GstGLColorConvert *convert;
     guint      next_tex;
     GstBuffer *next_buffer;
 
@@ -102,6 +99,7 @@ struct _GstGLImageSinkClass
 };
 
 GType gst_glimage_sink_get_type(void);
+GType gst_gl_image_sink_bin_get_type(void);
 
 G_END_DECLS
 
index 324dab6fbbb3faadfd8c23e1115ce914d7bfa09a..8f3596d18fe065538730b5f77aca3431a820cc74 100644 (file)
@@ -113,7 +113,7 @@ plugin_init (GstPlugin * plugin)
 #endif
 
   if (!gst_element_register (plugin, "glimagesink",
-          GST_RANK_SECONDARY, GST_TYPE_GLIMAGE_SINK)) {
+          GST_RANK_SECONDARY, gst_gl_image_sink_bin_get_type ())) {
     return FALSE;
   }