From 8a0017e21d5f9a8507f0593c6b24f723aa415258 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Fri, 20 Feb 2015 16:47:01 +1100 Subject: [PATCH] glimagesink: implement as a bin 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 | 284 ++++++++++++++++++++++++++-------------- ext/gl/gstglimagesink.h | 4 +- ext/gl/gstopengl.c | 2 +- 3 files changed, 185 insertions(+), 105 deletions(-) diff --git a/ext/gl/gstglimagesink.c b/ext/gl/gstglimagesink.c index f1a27f9c24..8ea7d46192 100644 --- a/ext/gl/gstglimagesink.c +++ b/ext/gl/gstglimagesink.c @@ -3,6 +3,7 @@ * Copyright (C) 2003 Julien Moutte * Copyright (C) 2005,2006,2007 David A. Schleef * Copyright (C) 2008 Julien Isorce + * Copyright (C) 2015 Matthew Waters * * 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 #include "gstglimagesink.h" +#include "gstglsinkbin.h" #if GST_GL_HAVE_PLATFORM_EGL #include @@ -98,6 +100,112 @@ 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); diff --git a/ext/gl/gstglimagesink.h b/ext/gl/gstglimagesink.h index 01851a4d49..1eed7b3997 100644 --- a/ext/gl/gstglimagesink.h +++ b/ext/gl/gstglimagesink.h @@ -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 diff --git a/ext/gl/gstopengl.c b/ext/gl/gstopengl.c index 324dab6fbb..8f3596d18f 100644 --- a/ext/gl/gstopengl.c +++ b/ext/gl/gstopengl.c @@ -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; }