diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 8d380c3f1c..cecad05fc6 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -28,33 +28,14 @@ #endif #include "gstgtkglsink.h" +#include "gtkgstglwidget.h" GST_DEBUG_CATEGORY (gst_debug_gtk_gl_sink); #define GST_CAT_DEFAULT gst_debug_gtk_gl_sink -#define DEFAULT_FORCE_ASPECT_RATIO TRUE -#define DEFAULT_PAR_N 0 -#define DEFAULT_PAR_D 1 -#define DEFAULT_IGNORE_ALPHA TRUE - -static void gst_gtk_gl_sink_finalize (GObject * object); -static void gst_gtk_gl_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * param_spec); -static void gst_gtk_gl_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * param_spec); - +static gboolean gst_gtk_gl_sink_start (GstBaseSink * bsink); static gboolean gst_gtk_gl_sink_stop (GstBaseSink * bsink); - static gboolean gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query); - -static GstStateChangeReturn -gst_gtk_gl_sink_change_state (GstElement * element, GstStateChange transition); - -static void gst_gtk_gl_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, - GstClockTime * start, GstClockTime * end); -static gboolean gst_gtk_gl_sink_set_caps (GstBaseSink * bsink, GstCaps * caps); -static GstFlowReturn gst_gtk_gl_sink_show_frame (GstVideoSink * bsink, - GstBuffer * buf); static gboolean gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query); @@ -65,191 +46,41 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, "RGBA"))); -enum -{ - PROP_0, - PROP_WIDGET, - PROP_FORCE_ASPECT_RATIO, - PROP_PIXEL_ASPECT_RATIO, - PROP_IGNORE_ALPHA, -}; - -enum -{ - SIGNAL_0, - LAST_SIGNAL -}; - #define gst_gtk_gl_sink_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstGtkGLSink, gst_gtk_gl_sink, - GST_TYPE_VIDEO_SINK, GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_gl_sink, + GST_TYPE_GTK_BASE_SINK, GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_gl_sink, "gtkglsink", 0, "Gtk Video Sink")); static void gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) { - GObjectClass *gobject_class; GstElementClass *gstelement_class; GstBaseSinkClass *gstbasesink_class; - GstVideoSinkClass *gstvideosink_class; + GstGtkBaseSinkClass *gstgtkbasesink_class; - gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; gstbasesink_class = (GstBaseSinkClass *) klass; - gstvideosink_class = (GstVideoSinkClass *) klass; + gstgtkbasesink_class = (GstGtkBaseSinkClass *) klass; - gobject_class->set_property = gst_gtk_gl_sink_set_property; - gobject_class->get_property = gst_gtk_gl_sink_get_property; + gstbasesink_class->query = gst_gtk_gl_sink_query; + 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; + + gstgtkbasesink_class->create_widget = gtk_gst_gl_widget_new; + gstgtkbasesink_class->window_title = "Gtk+ GL renderer"; gst_element_class_set_metadata (gstelement_class, "Gtk Video Sink", "Sink/Video", "A video sink that renders to a GtkWidget", "Matthew Waters "); - g_object_class_install_property (gobject_class, PROP_WIDGET, - g_param_spec_object ("widget", "Gtk Widget", - "The GtkWidget to place in the widget heirachy", - GTK_TYPE_WIDGET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO, - g_param_spec_boolean ("force-aspect-ratio", - "Force aspect ratio", - "When enabled, scaling will respect original aspect ratio", - DEFAULT_FORCE_ASPECT_RATIO, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO, - gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio", - "The pixel aspect ratio of the device", DEFAULT_PAR_N, DEFAULT_PAR_D, - G_MAXINT, 1, 1, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_IGNORE_ALPHA, - g_param_spec_boolean ("ignore-alpha", "Ignore Alpha", - "When enabled, alpha will be ignored and converted to black", - DEFAULT_IGNORE_ALPHA, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&gst_gtk_gl_sink_template)); - - gobject_class->finalize = gst_gtk_gl_sink_finalize; - - gstelement_class->change_state = gst_gtk_gl_sink_change_state; - gstbasesink_class->query = gst_gtk_gl_sink_query; - gstbasesink_class->set_caps = gst_gtk_gl_sink_set_caps; - gstbasesink_class->get_times = gst_gtk_gl_sink_get_times; - gstbasesink_class->propose_allocation = gst_gtk_gl_sink_propose_allocation; - gstbasesink_class->stop = gst_gtk_gl_sink_stop; - - gstvideosink_class->show_frame = gst_gtk_gl_sink_show_frame; } static void gst_gtk_gl_sink_init (GstGtkGLSink * gtk_sink) { - gtk_sink->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; - gtk_sink->par_n = DEFAULT_PAR_N; - gtk_sink->par_d = DEFAULT_PAR_D; - gtk_sink->ignore_alpha = DEFAULT_IGNORE_ALPHA; -} - -static void -gst_gtk_gl_sink_finalize (GObject * object) -{ - GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (object);; - - g_clear_object (>k_sink->widget); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -widget_destroy_cb (GtkWidget * widget, GstGtkGLSink * gtk_sink) -{ - GST_OBJECT_LOCK (gtk_sink); - g_clear_object (>k_sink->widget); - GST_OBJECT_UNLOCK (gtk_sink); -} - -static GtkGstBaseWidget * -gst_gtk_gl_sink_get_widget (GstGtkGLSink * gtk_sink) -{ - if (gtk_sink->widget != NULL) - return gtk_sink->widget; - - /* Ensure GTK is initialized, this has no side effect if it was already - * initialized. Also, we do that lazily, so the application can be first */ - if (!gtk_init_check (NULL, NULL)) { - GST_ERROR_OBJECT (gtk_sink, "Could not ensure GTK initialization."); - return NULL; - } - - gtk_sink->widget = (GtkGstBaseWidget *) gtk_gst_gl_widget_new (); - gtk_sink->bind_force_aspect_ratio = - g_object_bind_property (gtk_sink, "force-aspect-ratio", gtk_sink->widget, - "force-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); - gtk_sink->bind_pixel_aspect_ratio = - g_object_bind_property (gtk_sink, "pixel-aspect-ratio", gtk_sink->widget, - "pixel-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); - gtk_sink->bind_ignore_alpha = - g_object_bind_property (gtk_sink, "ignore-alpha", gtk_sink->widget, - "ignore-alpha", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); - - /* Take the floating ref, otherwise the destruction of the container will - * make this widget disapear possibly before we are done. */ - gst_object_ref_sink (gtk_sink->widget); - g_signal_connect (gtk_sink->widget, "destroy", - G_CALLBACK (widget_destroy_cb), gtk_sink); - - return gtk_sink->widget; -} - -static void -gst_gtk_gl_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstGtkGLSink *gtk_sink; - - gtk_sink = GST_GTK_GL_SINK (object); - - switch (prop_id) { - case PROP_WIDGET: - g_value_set_object (value, gst_gtk_gl_sink_get_widget (gtk_sink)); - break; - case PROP_FORCE_ASPECT_RATIO: - g_value_set_boolean (value, gtk_sink->force_aspect_ratio); - break; - case PROP_PIXEL_ASPECT_RATIO: - gst_value_set_fraction (value, gtk_sink->par_n, gtk_sink->par_d); - break; - case PROP_IGNORE_ALPHA: - g_value_set_boolean (value, gtk_sink->ignore_alpha); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_gtk_gl_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (object); - - switch (prop_id) { - case PROP_FORCE_ASPECT_RATIO: - gtk_sink->force_aspect_ratio = g_value_get_boolean (value); - break; - case PROP_PIXEL_ASPECT_RATIO: - gtk_sink->par_n = gst_value_get_fraction_numerator (value); - gtk_sink->par_d = gst_value_get_fraction_denominator (value); - break; - case PROP_IGNORE_ALPHA: - gtk_sink->ignore_alpha = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } } static gboolean @@ -263,9 +94,8 @@ gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query) { const gchar *context_type; GstContext *context, *old_context; - gboolean ret; - ret = gst_gl_handle_context_query ((GstElement *) gtk_sink, query, + res = gst_gl_handle_context_query ((GstElement *) gtk_sink, query, >k_sink->display, >k_sink->gtk_context); if (gtk_sink->display) @@ -289,13 +119,11 @@ gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query) gst_query_set_context (query, context); gst_context_unref (context); - ret = gtk_sink->context != NULL; + res = gtk_sink->context != NULL; } GST_LOG_OBJECT (gtk_sink, "context query of type %s %i", context_type, - ret); - - if (ret) - return ret; + res); + break; } default: res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); @@ -306,180 +134,59 @@ gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query) } static gboolean -gst_gtk_gl_sink_stop (GstBaseSink * bsink) +gst_gtk_gl_sink_start (GstBaseSink * bsink) { + GstGtkBaseSink *base_sink = GST_GTK_BASE_SINK (bsink); + GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (bsink); + GtkGstGLWidget *gst_widget; + + if (!GST_BASE_SINK_CLASS (parent_class)->start (bsink)) + return FALSE; + + /* After this point, gtk_sink->widget will always be set */ + gst_widget = GTK_GST_GL_WIDGET (base_sink->widget); + + if (!gtk_gst_gl_widget_init_winsys (gst_widget)) + return FALSE; + + gtk_sink->display = gtk_gst_gl_widget_get_display (gst_widget); + gtk_sink->context = gtk_gst_gl_widget_get_context (gst_widget); + gtk_sink->gtk_context = gtk_gst_gl_widget_get_gtk_context (gst_widget); + + if (!gtk_sink->display || !gtk_sink->context || !gtk_sink->gtk_context) + return FALSE; + return TRUE; } -static GstStateChangeReturn -gst_gtk_gl_sink_change_state (GstElement * element, GstStateChange transition) -{ - GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (element); - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GtkWidget *toplevel; - - GST_DEBUG ("changing state: %s => %s", - gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)), - gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition))); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY:{ - GtkGstGLWidget *gst_widget; - - if (gst_gtk_gl_sink_get_widget (gtk_sink) == NULL) - return GST_STATE_CHANGE_FAILURE; - - /* After this point, gtk_sink->widget will always be set */ - gst_widget = GTK_GST_GL_WIDGET (gtk_sink->widget); - - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (gst_widget)); - if (!gtk_widget_is_toplevel (toplevel)) { - GtkWidget *window; - - /* User did not add widget its own UI, let's popup a new GtkWindow to - * make gst-launch-1.0 work. */ - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_default_size (GTK_WINDOW (window), 640, 480); - gtk_window_set_title (GTK_WINDOW (window), "Gtk+ OpenGL renderer"); - gtk_container_add (GTK_CONTAINER (window), toplevel); - gtk_widget_show_all (window); - } - - if (!gtk_gst_gl_widget_init_winsys (gst_widget)) - return GST_STATE_CHANGE_FAILURE; - - gtk_sink->display = gtk_gst_gl_widget_get_display (gst_widget); - gtk_sink->context = gtk_gst_gl_widget_get_context (gst_widget); - gtk_sink->gtk_context = gtk_gst_gl_widget_get_gtk_context (gst_widget); - - if (!gtk_sink->display || !gtk_sink->context || !gtk_sink->gtk_context) - return GST_STATE_CHANGE_FAILURE; - break; - } - case GST_STATE_CHANGE_READY_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_OBJECT_LOCK (gtk_sink); - if (gtk_sink->widget) - gtk_gst_base_widget_set_buffer (gtk_sink->widget, NULL); - GST_OBJECT_UNLOCK (gtk_sink); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - if (gtk_sink->display) { - gst_object_unref (gtk_sink->display); - gtk_sink->display = NULL; - } - - if (gtk_sink->context) { - gst_object_unref (gtk_sink->context); - gtk_sink->context = NULL; - } - - if (gtk_sink->gtk_context) { - gst_object_unref (gtk_sink->gtk_context); - gtk_sink->gtk_context = NULL; - } - break; - default: - break; - } - - return ret; -} - -static void -gst_gtk_gl_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, - GstClockTime * start, GstClockTime * end) -{ - GstGtkGLSink *gtk_sink; - - gtk_sink = GST_GTK_GL_SINK (bsink); - - if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { - *start = GST_BUFFER_TIMESTAMP (buf); - if (GST_BUFFER_DURATION_IS_VALID (buf)) - *end = *start + GST_BUFFER_DURATION (buf); - else { - if (GST_VIDEO_INFO_FPS_N (>k_sink->v_info) > 0) { - *end = *start + - gst_util_uint64_scale_int (GST_SECOND, - GST_VIDEO_INFO_FPS_D (>k_sink->v_info), - GST_VIDEO_INFO_FPS_N (>k_sink->v_info)); - } - } - } -} - -gboolean -gst_gtk_gl_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) +static gboolean +gst_gtk_gl_sink_stop (GstBaseSink * bsink) { GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (bsink); - GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps); - - if (!gst_video_info_from_caps (>k_sink->v_info, caps)) - return FALSE; - - GST_OBJECT_LOCK (gtk_sink); - - if (gtk_sink->widget == NULL) { - GST_OBJECT_UNLOCK (gtk_sink); - GST_ELEMENT_ERROR (gtk_sink, RESOURCE, NOT_FOUND, - ("%s", "Output widget was destroyed"), (NULL)); - return FALSE; + if (gtk_sink->display) { + gst_object_unref (gtk_sink->display); + gtk_sink->display = NULL; } - if (!gtk_gst_base_widget_set_caps (gtk_sink->widget, caps)) - return FALSE; + if (gtk_sink->context) { + gst_object_unref (gtk_sink->context); + gtk_sink->context = NULL; + } - GST_OBJECT_UNLOCK (gtk_sink); + if (gtk_sink->gtk_context) { + gst_object_unref (gtk_sink->gtk_context); + gtk_sink->gtk_context = NULL; + } return TRUE; } -static GstFlowReturn -gst_gtk_gl_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) -{ - GstGtkGLSink *gtk_sink; - - GST_TRACE ("rendering buffer:%p", buf); - - gtk_sink = GST_GTK_GL_SINK (vsink); - - GST_OBJECT_LOCK (vsink); - - if (gtk_sink->widget == NULL) { - GST_OBJECT_UNLOCK (vsink); - GST_ELEMENT_ERROR (gtk_sink, RESOURCE, NOT_FOUND, - ("%s", "Output widget was destroyed"), (NULL)); - return GST_FLOW_ERROR; - } - - gtk_gst_base_widget_set_buffer (gtk_sink->widget, buf); - - GST_OBJECT_UNLOCK (vsink); - - return GST_FLOW_OK; -} - static gboolean gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) { GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (bsink); - GstBufferPool *pool; + GstBufferPool *pool = NULL; GstStructure *config; GstCaps *caps; guint size; @@ -493,27 +200,7 @@ gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) if (caps == NULL) goto no_caps; - if ((pool = gtk_sink->pool)) - gst_object_ref (pool); - - if (pool != NULL) { - GstCaps *pcaps; - - /* we had a pool, check caps */ - GST_DEBUG_OBJECT (gtk_sink, "check existing pool caps"); - config = gst_buffer_pool_get_config (pool); - gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL); - - if (!gst_caps_is_equal (caps, pcaps)) { - GST_DEBUG_OBJECT (gtk_sink, "pool has different caps"); - /* different caps, we can't use this pool */ - gst_object_unref (pool); - pool = NULL; - } - gst_structure_free (config); - } - - if (pool == NULL && need_pool) { + if (need_pool) { GstVideoInfo info; if (!gst_video_info_from_caps (&info, caps)) @@ -529,9 +216,8 @@ gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) gst_buffer_pool_config_set_params (config, caps, size, 0, 0); if (!gst_buffer_pool_set_config (pool, config)) goto config_failed; - } - /* we need at least 2 buffer because we hold on to the last one */ - if (pool) { + + /* we need at least 2 buffer because we hold on to the last one */ gst_query_add_allocation_pool (query, pool, size, 2, 0); gst_object_unref (pool); } diff --git a/ext/gtk/gstgtkglsink.h b/ext/gtk/gstgtkglsink.h index fdc62727c8..dee1024786 100644 --- a/ext/gtk/gstgtkglsink.h +++ b/ext/gtk/gstgtkglsink.h @@ -27,14 +27,9 @@ #include #include -typedef struct _GstGtkGLSink GstGtkGLSink; -typedef struct _GstGtkGLSinkClass GstGtkGLSinkClass; +#include "gstgtkbasesink.h" -#include -G_BEGIN_DECLS - -GType gst_gtk_gl_sink_get_type (void); #define GST_TYPE_GTK_GL_SINK (gst_gtk_gl_sink_get_type()) #define GST_GTK_GL_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GTK_GL_SINK,GstGtkGLSink)) #define GST_GTK_GL_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GTK_GL_SINK,GstGtkGLSinkClass)) @@ -42,6 +37,13 @@ GType gst_gtk_gl_sink_get_type (void); #define GST_IS_GTK_GL_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GTK_GL_SINK)) #define GST_GTK_GL_SINK_CAST(obj) ((GstGtkGLSink*)(obj)) +G_BEGIN_DECLS + +typedef struct _GstGtkGLSink GstGtkGLSink; +typedef struct _GstGtkGLSinkClass GstGtkGLSinkClass; + +GType gst_gtk_gl_sink_get_type (void); + /** * GstGtkGLSink: * @@ -50,12 +52,7 @@ GType gst_gtk_gl_sink_get_type (void); struct _GstGtkGLSink { /* */ - GstVideoSink parent; - - GtkGstBaseWidget *widget; - - GstVideoInfo v_info; - GstBufferPool *pool; + GstGtkBaseSink parent; GstGLDisplay *display; GstGLContext *context; @@ -63,17 +60,6 @@ struct _GstGtkGLSink GstGLUpload *upload; GstBuffer *uploaded_buffer; - - /* properties */ - gboolean force_aspect_ratio; - GBinding *bind_force_aspect_ratio; - - gint par_n; - gint par_d; - GBinding *bind_pixel_aspect_ratio; - - gboolean ignore_alpha; - GBinding *bind_ignore_alpha; }; /** @@ -84,11 +70,9 @@ struct _GstGtkGLSink struct _GstGtkGLSinkClass { /* */ - GstVideoSinkClass object_class; + GstGtkBaseSinkClass object_class; }; -GstGtkGLSink * gst_gtk_gl_sink_new (void); - G_END_DECLS #endif /* __GST_GTK_GL_SINK_H__ */