From 530be54c7b3087ab5bff8931ca7f6b3a706d5481 Mon Sep 17 00:00:00 2001 From: Filippo Argiolas Date: Thu, 14 Aug 2008 20:02:04 +0200 Subject: [PATCH 001/128] [171/906] import fxtest (little gtk app to easily test effects) from cvs branch, fixed rgbtocurve. --- tests/examples/gtk/fxtest/fxtest.c | 204 +++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 tests/examples/gtk/fxtest/fxtest.c diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c new file mode 100644 index 0000000000..5d663e5241 --- /dev/null +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -0,0 +1,204 @@ +#include +#include +#include +#include +#include +#include + + +GstElement *pipeline; + +static gboolean +expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) +{ + GstXOverlay *overlay = + GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (data), + GST_TYPE_X_OVERLAY)); + gst_x_overlay_set_xwindow_id (overlay, GDK_WINDOW_XWINDOW (widget->window)); + return FALSE; +} + +static void +destroy_cb (gpointer data) +{ + g_message ("destroy callback"); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + + gtk_main_quit (); +} + +gboolean +apply_fx (GtkWidget * widget, gpointer data) +{ + gchar *fx; + GEnumClass *p_class; + +/* heeeellppppp!! */ + p_class = + G_PARAM_SPEC_ENUM (g_object_class_find_property (G_OBJECT_GET_CLASS + (G_OBJECT (data)), "effect") + )->enum_class; + + fx = gtk_combo_box_get_active_text (GTK_COMBO_BOX (widget)); + g_print ("setting: %s - %s\n", fx, g_enum_get_value_by_nick (p_class, + fx)->value_name); + g_object_set (G_OBJECT (data), "effect", g_enum_get_value_by_nick (p_class, + fx)->value, NULL); + return FALSE; +} + +gboolean +play_cb (GtkWidget * widget, gpointer data) +{ + g_message ("playing"); + gst_element_set_state (GST_ELEMENT (data), GST_STATE_PLAYING); + return FALSE; +} + +gboolean +null_cb (GtkWidget * widget, gpointer data) +{ + g_message ("nulling"); + gst_element_set_state (GST_ELEMENT (data), GST_STATE_NULL); + return FALSE; +} + +gboolean +ready_cb (GtkWidget * widget, gpointer data) +{ + g_message ("readying"); + gst_element_set_state (GST_ELEMENT (data), GST_STATE_READY); + return FALSE; +} + +gboolean +pause_cb (GtkWidget * widget, gpointer data) +{ + g_message ("pausing"); + gst_element_set_state (GST_ELEMENT (data), GST_STATE_PAUSED); + return FALSE; +} + +gint +main (gint argc, gchar * argv[]) +{ + GstStateChangeReturn ret; + GstElement *src, *capsflt, *uload, *filter, *sink; + GstCaps *caps; + + GtkWidget *window; + GtkWidget *screen; + GtkWidget *vbox, *combo; + GtkWidget *hbox; + GtkWidget *play, *pause, *null, *ready; + + gtk_init (&argc, &argv); + gst_init (&argc, &argv); + + g_set_application_name ("gst-gl-effects test app"); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (window), 3); + + g_signal_connect (G_OBJECT (window), "delete-event", + G_CALLBACK (destroy_cb), NULL); + g_signal_connect (G_OBJECT (window), "destroy-event", + G_CALLBACK (destroy_cb), NULL); + + pipeline = gst_pipeline_new ("pipeline"); + + src = gst_element_factory_make ("v4l2src", "myv4l2src"); + capsflt = gst_element_factory_make ("capsfilter", "cflt"); + uload = gst_element_factory_make ("glupload", "glu"); + filter = gst_element_factory_make ("gleffects", "flt"); + sink = gst_element_factory_make ("glimagesink", "glsink"); + + gst_bin_add_many (GST_BIN (pipeline), src, capsflt, uload, filter, sink, NULL); + + if (!gst_element_link_many (src, capsflt, uload, filter, sink, NULL)) { + g_print ("Failed to link one or more elements!\n"); + return -1; + } + + screen = gtk_drawing_area_new (); + + gtk_widget_set_size_request (screen, 640, 480); // 500 x 376 + + vbox = gtk_vbox_new (FALSE, 2); + + gtk_box_pack_start (GTK_BOX (vbox), screen, TRUE, TRUE, 0); + + combo = gtk_combo_box_new_text (); + + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "identity"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "squeeze"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "stretch"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "bulge"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "twirl"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "tunnel"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "fisheye"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "square"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "mirror"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "heat"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "xpro"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "sepia"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "glow"); + + g_signal_connect (G_OBJECT (combo), "changed", G_CALLBACK (apply_fx), filter); + + gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 0); + + play = gtk_button_new_with_label ("PLAY"); + + g_signal_connect (G_OBJECT (play), "clicked", G_CALLBACK (play_cb), pipeline); + + pause = gtk_button_new_with_label ("PAUSE"); + + g_signal_connect (G_OBJECT (pause), "clicked", + G_CALLBACK (pause_cb), pipeline); + + null = gtk_button_new_with_label ("NULL"); + + g_signal_connect (G_OBJECT (null), "clicked", G_CALLBACK (null_cb), pipeline); + + ready = gtk_button_new_with_label ("READY"); + + g_signal_connect (G_OBJECT (ready), "clicked", + G_CALLBACK (ready_cb), pipeline); + + gtk_box_pack_start (GTK_BOX (hbox), null, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox), ready, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox), play, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox), pause, TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + gtk_container_add (GTK_CONTAINER (window), vbox); + + g_signal_connect (screen, "expose-event", G_CALLBACK (expose_cb), pipeline); + + caps = gst_caps_new_simple ("video/x-raw-yuv", + "width", G_TYPE_INT, 640, + "height", G_TYPE_INT, 480, "framerate", GST_TYPE_FRACTION, 30, 1, NULL); + g_object_set (G_OBJECT (capsflt), "caps", caps, NULL); + gst_caps_unref (caps); + + ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) { + g_print ("Failed to start up pipeline!\n"); + return -1; + } +// g_timeout_add (2000, (GSourceFunc) set_fx, filter); + + gtk_widget_show_all (GTK_WIDGET (window)); + + gtk_main (); + +// event_loop (pipeline); + + return 0; +} From ae673c3d4af1e57ddcab4553009d646a8a575f2d Mon Sep 17 00:00:00 2001 From: Filippo Argiolas Date: Thu, 14 Aug 2008 20:54:54 +0200 Subject: [PATCH 002/128] [172/906] add support for command line parsing to fxtest (try fxtest videotestsrc ! desired caps ! identity). report a new issue on BUGS. --- tests/examples/gtk/fxtest/fxtest.c | 53 ++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index 5d663e5241..55ef43cc92 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -85,8 +85,9 @@ gint main (gint argc, gchar * argv[]) { GstStateChangeReturn ret; - GstElement *src, *capsflt, *uload, *filter, *sink; - GstCaps *caps; + GstElement *uload, *filter, *sink; + GstElement *sourcebin; + GError *error = NULL; GtkWidget *window; GtkWidget *screen; @@ -94,10 +95,37 @@ main (gint argc, gchar * argv[]) GtkWidget *hbox; GtkWidget *play, *pause, *null, *ready; - gtk_init (&argc, &argv); - gst_init (&argc, &argv); + gchar **source_desc_array = NULL; + gchar *source_desc = NULL; + + GOptionContext *context; + gboolean retval; + GOptionEntry options[] = { + { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, NULL, NULL }, + { NULL } + }; g_set_application_name ("gst-gl-effects test app"); + + context = g_option_context_new ("src ! ... ! identity"); + g_option_context_add_main_entries (context, options, NULL); + retval = g_option_context_parse (context, &argc, &argv, &error); + g_assert (retval); + g_option_context_free (context); + + if (source_desc_array != NULL) { + source_desc = g_strjoinv (" ", source_desc_array); + g_strfreev (source_desc_array); + } + if (source_desc == NULL) { + g_print ("\nUsage: %s SOURCE_DESC\n\n", argv[0]); + g_print ("where SOURCE_DESC is a description of the source bin in gst-launch format\n"); + g_print ("like: videotestsrc ! video/x-raw-rgb, width=352, heigth=288 ! identity\n\n"); + return -1; + } + + gtk_init (&argc, &argv); + gst_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_container_set_border_width (GTK_CONTAINER (window), 3); @@ -109,15 +137,18 @@ main (gint argc, gchar * argv[]) pipeline = gst_pipeline_new ("pipeline"); - src = gst_element_factory_make ("v4l2src", "myv4l2src"); - capsflt = gst_element_factory_make ("capsfilter", "cflt"); + sourcebin = gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); + g_free (source_desc); + if (error) + g_error ("%s", error->message); + uload = gst_element_factory_make ("glupload", "glu"); filter = gst_element_factory_make ("gleffects", "flt"); sink = gst_element_factory_make ("glimagesink", "glsink"); - gst_bin_add_many (GST_BIN (pipeline), src, capsflt, uload, filter, sink, NULL); + gst_bin_add_many (GST_BIN (pipeline), sourcebin, uload, filter, sink, NULL); - if (!gst_element_link_many (src, capsflt, uload, filter, sink, NULL)) { + if (!gst_element_link_many (sourcebin, uload, filter, sink, NULL)) { g_print ("Failed to link one or more elements!\n"); return -1; } @@ -181,12 +212,6 @@ main (gint argc, gchar * argv[]) g_signal_connect (screen, "expose-event", G_CALLBACK (expose_cb), pipeline); - caps = gst_caps_new_simple ("video/x-raw-yuv", - "width", G_TYPE_INT, 640, - "height", G_TYPE_INT, 480, "framerate", GST_TYPE_FRACTION, 30, 1, NULL); - g_object_set (G_OBJECT (capsflt), "caps", caps, NULL); - gst_caps_unref (caps); - ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); if (ret == GST_STATE_CHANGE_FAILURE) { g_print ("Failed to start up pipeline!\n"); From 0bb26924a894aa9287bf2f0b11d613af35851586 Mon Sep 17 00:00:00 2001 From: Filippo Argiolas Date: Thu, 14 Aug 2008 21:29:02 +0200 Subject: [PATCH 003/128] [173/906] add lumaxpro (desaturate + cross process) effect. nothing too impressive but I like it. --- tests/examples/gtk/fxtest/fxtest.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index 55ef43cc92..cc1c46a667 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -164,16 +164,17 @@ main (gint argc, gchar * argv[]) combo = gtk_combo_box_new_text (); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "identity"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "mirror"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "squeeze"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "stretch"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "bulge"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "twirl"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "tunnel"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "fisheye"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "twirl"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "bulge"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "tunnel"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "square"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "mirror"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "heat"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "xpro"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "lumaxpro"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "sepia"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "glow"); From f327cd5a86b014b98671595d7510d31e93bdff13 Mon Sep 17 00:00:00 2001 From: Filippo Argiolas Date: Sat, 16 Aug 2008 09:13:39 +0200 Subject: [PATCH 004/128] [175/906] add sin effect (desaturate everything but red shades). still needs some tuning. --- tests/examples/gtk/fxtest/fxtest.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index cc1c46a667..f739540322 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -176,6 +176,7 @@ main (gint argc, gchar * argv[]) gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "xpro"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "lumaxpro"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "sepia"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "sin"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "glow"); g_signal_connect (G_OBJECT (combo), "changed", G_CALLBACK (apply_fx), filter); From 8941057006ae41da0f64cffba19732e24af363ed Mon Sep 17 00:00:00 2001 From: Filippo Argiolas Date: Sat, 16 Aug 2008 10:15:31 +0200 Subject: [PATCH 005/128] [178/906] improve fxtest command line option handling, default to videotestsrc if no source bin description is given --- tests/examples/gtk/fxtest/fxtest.c | 41 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index f739540322..9b7336120c 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -8,6 +8,7 @@ GstElement *pipeline; +/* TODO: use x overlay in the proper way (like suggested in docs, see gtkxoverlay example) */ static gboolean expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) { @@ -99,18 +100,22 @@ main (gint argc, gchar * argv[]) gchar *source_desc = NULL; GOptionContext *context; - gboolean retval; GOptionEntry options[] = { - { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, NULL, NULL }, + { "source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, + "Use a custom source bin description (gst-launch style)", NULL }, { NULL } }; - g_set_application_name ("gst-gl-effects test app"); - - context = g_option_context_new ("src ! ... ! identity"); + g_thread_init (NULL); + + context = g_option_context_new (NULL); g_option_context_add_main_entries (context, options, NULL); - retval = g_option_context_parse (context, &argc, &argv, &error); - g_assert (retval); + g_option_context_add_group (context, gst_init_get_option_group ()); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_print ("Inizialization error: %s\n", GST_STR_NULL (error->message)); + return -1; + } g_option_context_free (context); if (source_desc_array != NULL) { @@ -118,14 +123,18 @@ main (gint argc, gchar * argv[]) g_strfreev (source_desc_array); } if (source_desc == NULL) { - g_print ("\nUsage: %s SOURCE_DESC\n\n", argv[0]); - g_print ("where SOURCE_DESC is a description of the source bin in gst-launch format\n"); - g_print ("like: videotestsrc ! video/x-raw-rgb, width=352, heigth=288 ! identity\n\n"); + source_desc = g_strdup ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); + } + + sourcebin = gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); + g_free (source_desc); + if (error) { + g_print ("Error while parsing source bin description: %s\n", + GST_STR_NULL (error->message)); return -1; } - gtk_init (&argc, &argv); - gst_init (&argc, &argv); + g_set_application_name ("gst-gl-effects test app"); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_container_set_border_width (GTK_CONTAINER (window), 3); @@ -137,11 +146,6 @@ main (gint argc, gchar * argv[]) pipeline = gst_pipeline_new ("pipeline"); - sourcebin = gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); - g_free (source_desc); - if (error) - g_error ("%s", error->message); - uload = gst_element_factory_make ("glupload", "glu"); filter = gst_element_factory_make ("gleffects", "flt"); sink = gst_element_factory_make ("glimagesink", "glsink"); @@ -219,13 +223,10 @@ main (gint argc, gchar * argv[]) g_print ("Failed to start up pipeline!\n"); return -1; } -// g_timeout_add (2000, (GSourceFunc) set_fx, filter); gtk_widget_show_all (GTK_WIDGET (window)); gtk_main (); -// event_loop (pipeline); - return 0; } From 944afa296c9eeb1269e3164333786962e498ba2d Mon Sep 17 00:00:00 2001 From: Filippo Argiolas Date: Sat, 16 Aug 2008 17:36:10 +0200 Subject: [PATCH 006/128] [180/906] minor cleanup in fxtest --- tests/examples/gtk/fxtest/fxtest.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index 9b7336120c..aedb0a037f 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -6,8 +6,6 @@ #include -GstElement *pipeline; - /* TODO: use x overlay in the proper way (like suggested in docs, see gtkxoverlay example) */ static gboolean expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) @@ -20,7 +18,7 @@ expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) } static void -destroy_cb (gpointer data) +destroy_cb (GtkWidget *widget, GdkEvent *event, GstElement *pipeline) { g_message ("destroy callback"); @@ -86,6 +84,7 @@ gint main (gint argc, gchar * argv[]) { GstStateChangeReturn ret; + GstElement *pipeline; GstElement *uload, *filter, *sink; GstElement *sourcebin; GError *error = NULL; @@ -139,11 +138,6 @@ main (gint argc, gchar * argv[]) window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_container_set_border_width (GTK_CONTAINER (window), 3); - g_signal_connect (G_OBJECT (window), "delete-event", - G_CALLBACK (destroy_cb), NULL); - g_signal_connect (G_OBJECT (window), "destroy-event", - G_CALLBACK (destroy_cb), NULL); - pipeline = gst_pipeline_new ("pipeline"); uload = gst_element_factory_make ("glupload", "glu"); @@ -157,6 +151,11 @@ main (gint argc, gchar * argv[]) return -1; } + g_signal_connect (G_OBJECT (window), "delete-event", + G_CALLBACK (destroy_cb), pipeline); + g_signal_connect (G_OBJECT (window), "destroy-event", + G_CALLBACK (destroy_cb), pipeline); + screen = gtk_drawing_area_new (); gtk_widget_set_size_request (screen, 640, 480); // 500 x 376 From 3264db13fadb0b9aa38d3f2e2ac9db23eb0c2d3a Mon Sep 17 00:00:00 2001 From: Filippo Argiolas Date: Tue, 19 Aug 2008 08:50:14 +0200 Subject: [PATCH 007/128] [195/906] fix gstgldifferencematte and add an example app to test it dragging an image over the video (works with pixbufoverlay too, see pixbufdrop --help) --- tests/examples/gtk/fxtest/pixbufdrop.c | 278 +++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 tests/examples/gtk/fxtest/pixbufdrop.c diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c new file mode 100644 index 0000000000..df99dfa72a --- /dev/null +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -0,0 +1,278 @@ +#include +#include +#include +#include +#include +#include + +static gint delay = 0; +static gint saveddelay = 0; +static gint method = 1; + +struct _SourceData +{ + gpointer data; + gpointer nick; + gpointer value; +}; +typedef struct _SourceData SourceData; + +static GstBusSyncReply +create_window (GstBus *bus, GstMessage *message, GtkWidget *widget) +{ + // ignore anything but 'prepare-xwindow-id' element messages + if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) + return GST_BUS_PASS; + + if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) + return GST_BUS_PASS; + +#ifdef WIN32 + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), + reinterpret_castGDK_WINDOW_HWND(widget->window)); +#else + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), + GDK_WINDOW_XWINDOW(widget->window)); +#endif + + gst_message_unref (message); + + return GST_BUS_DROP; +} + +static gboolean +expose_cb(GtkWidget *widget, GdkEventExpose *event, GstElement *videosink) +{ + gst_x_overlay_expose (GST_X_OVERLAY (videosink)); + return FALSE; +} + +static void +destroy_cb (GtkWidget *widget, GdkEvent *event, GstElement *pipeline) +{ + g_message ("destroy callback"); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + + gtk_main_quit (); +} + +gboolean +play_cb (GtkWidget * widget, gpointer data) +{ + g_message ("playing"); + gst_element_set_state (GST_ELEMENT (data), GST_STATE_PLAYING); + return FALSE; +} + +gboolean +null_cb (GtkWidget * widget, gpointer data) +{ + g_message ("nulling"); + gst_element_set_state (GST_ELEMENT (data), GST_STATE_NULL); + return FALSE; +} + +gboolean +ready_cb (GtkWidget * widget, gpointer data) +{ + g_message ("readying"); + gst_element_set_state (GST_ELEMENT (data), GST_STATE_READY); + return FALSE; +} + +gboolean +pause_cb (GtkWidget * widget, gpointer data) +{ + g_message ("pausing"); + gst_element_set_state (GST_ELEMENT (data), GST_STATE_PAUSED); + return FALSE; +} + +static gboolean +set_location_delayed (gpointer data) +{ + SourceData *sdata = (SourceData *) data; + delay--; + g_print ("%d\n", delay); + if (delay > 0) { + return TRUE; + } + g_object_set (G_OBJECT (sdata->data), sdata->nick, sdata->value, NULL); + delay = saveddelay; + return FALSE; +} + +static void +on_drag_data_received (GtkWidget * widget, + GdkDragContext * context, int x, int y, + GtkSelectionData * seldata, guint inf, guint time, + gpointer data) +{ + GdkPixbufFormat *format; + SourceData *userdata = g_new0 (SourceData, 1); + gchar **uris = gtk_selection_data_get_uris (seldata); + gchar *filename = g_filename_from_uri (uris[0], NULL, NULL); + g_return_if_fail (filename != NULL); + format = gdk_pixbuf_get_file_info (filename, NULL, NULL); + g_return_if_fail (format); + g_print ("received %s image: %s\n", filename, + gdk_pixbuf_format_get_name (format)); + userdata->nick = "location"; + userdata->value = g_strdup (filename); + userdata->data = data; + saveddelay = delay; + if (delay > 0) { + g_print ("%d\n", delay); + g_timeout_add_seconds (1, set_location_delayed, userdata); + } + else + g_object_set (G_OBJECT (userdata->data), userdata->nick, userdata->value, NULL); + g_free (filename); +} + + +gint +main (gint argc, gchar * argv[]) +{ + GstStateChangeReturn ret; + GstElement *pipeline; + GstElement *uload, *filter, *sink; + GstElement *sourcebin; + GstBus *bus; + GError *error = NULL; + + GtkWidget *window; + GtkWidget *screen; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *play, *pause, *null, *ready; + + gchar **source_desc_array = NULL; + gchar *source_desc = NULL; + + GOptionContext *context; + GOptionEntry options[] = { + { "source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, + "Use a custom source bin description (gst-launch style)", NULL }, + { "method", 'm', 0, G_OPTION_ARG_INT, &method, "1 for gstdifferencematte, 2 for gstpixbufoverlay", "M" }, + { "delay", 'd', 0, G_OPTION_ARG_INT, &delay, "Wait N seconds before to send the image to gstreamer (useful with differencematte)", "N" }, + { NULL } + }; + + g_thread_init (NULL); + + context = g_option_context_new (NULL); + g_option_context_add_main_entries (context, options, NULL); + g_option_context_add_group (context, gst_init_get_option_group ()); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_print ("Inizialization error: %s\n", GST_STR_NULL (error->message)); + return -1; + } + g_option_context_free (context); + + if (source_desc_array != NULL) { + source_desc = g_strjoinv (" ", source_desc_array); + g_strfreev (source_desc_array); + } + if (source_desc == NULL) { + source_desc = g_strdup ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); + } + + sourcebin = gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); + g_free (source_desc); + if (error) { + g_print ("Error while parsing source bin description: %s\n", + GST_STR_NULL (error->message)); + return -1; + } + + g_set_application_name ("gst-gl-effects test app"); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (window), 3); + + pipeline = gst_pipeline_new ("pipeline"); + + uload = gst_element_factory_make ("glupload", "glu"); + if (method == 2) { + filter = gst_element_factory_make ("glpixbufoverlay", "flt"); + } else { + filter = gst_element_factory_make ("gldifferencematte", "flt"); + } + sink = gst_element_factory_make ("glimagesink", "glsink"); + + gst_bin_add_many (GST_BIN (pipeline), sourcebin, uload, filter, sink, NULL); + + if (!gst_element_link_many (sourcebin, uload, filter, sink, NULL)) { + g_print ("Failed to link one or more elements!\n"); + return -1; + } + + g_signal_connect (G_OBJECT (window), "delete-event", + G_CALLBACK (destroy_cb), pipeline); + g_signal_connect (G_OBJECT (window), "destroy-event", + G_CALLBACK (destroy_cb), pipeline); + + screen = gtk_drawing_area_new (); + + gtk_widget_set_size_request (screen, 640, 480); // 500 x 376 + + vbox = gtk_vbox_new (FALSE, 2); + + gtk_box_pack_start (GTK_BOX (vbox), screen, TRUE, TRUE, 0); + + hbox = gtk_hbox_new (FALSE, 0); + + play = gtk_button_new_with_label ("PLAY"); + + g_signal_connect (G_OBJECT (play), "clicked", G_CALLBACK (play_cb), pipeline); + + pause = gtk_button_new_with_label ("PAUSE"); + + g_signal_connect (G_OBJECT (pause), "clicked", + G_CALLBACK (pause_cb), pipeline); + + null = gtk_button_new_with_label ("NULL"); + + g_signal_connect (G_OBJECT (null), "clicked", G_CALLBACK (null_cb), pipeline); + + ready = gtk_button_new_with_label ("READY"); + + g_signal_connect (G_OBJECT (ready), "clicked", + G_CALLBACK (ready_cb), pipeline); + + gtk_box_pack_start (GTK_BOX (hbox), null, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox), ready, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox), play, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox), pause, TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + gtk_container_add (GTK_CONTAINER (window), vbox); + + bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); + gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, screen); + gst_object_unref (bus); + g_signal_connect(screen, "expose-event", G_CALLBACK(expose_cb), sink); + + gtk_drag_dest_set (screen, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY); + gtk_drag_dest_add_uri_targets (screen); + + g_signal_connect (screen, "drag-data-received", + G_CALLBACK (on_drag_data_received), filter); + + ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) { + g_print ("Failed to start up pipeline!\n"); + return -1; + } + + gtk_widget_show_all (GTK_WIDGET (window)); + + gtk_main (); + + return 0; +} From 04ccea87809b9db5ca06ed995c5e647fbd9f3f87 Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Tue, 19 Aug 2008 21:04:29 +0200 Subject: [PATCH 008/128] [198/906] add fxtest vs8 project --- tests/examples/gtk/fxtest/fxtest.c | 11 +++++++++++ tests/examples/gtk/fxtest/pixbufdrop.c | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index aedb0a037f..f3c2bfa985 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -2,7 +2,13 @@ #include #include #include + +#ifdef WIN32 +#include +#else #include +#endif + #include @@ -13,7 +19,12 @@ expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) GstXOverlay *overlay = GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (data), GST_TYPE_X_OVERLAY)); +#ifdef WIN32 + gst_x_overlay_set_xwindow_id (overlay, (gulong)GDK_WINDOW_HWND(widget->window)); +#else gst_x_overlay_set_xwindow_id (overlay, GDK_WINDOW_XWINDOW (widget->window)); +#endif + return FALSE; } diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index df99dfa72a..33f348518a 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -2,7 +2,13 @@ #include #include #include + +#ifdef WIN32 +#include +#else #include +#endif + #include static gint delay = 0; From dcbc69cb0bfc3c577b494eaf9f06d6adbf7442a7 Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Tue, 19 Aug 2008 22:15:17 +0200 Subject: [PATCH 009/128] [199/906] add pixbufdrop vs8 project --- tests/examples/gtk/fxtest/pixbufdrop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index 33f348518a..1aaf6bbfc6 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -35,7 +35,7 @@ create_window (GstBus *bus, GstMessage *message, GtkWidget *widget) #ifdef WIN32 gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), - reinterpret_castGDK_WINDOW_HWND(widget->window)); + (gulong)GDK_WINDOW_HWND(widget->window)); #else gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), GDK_WINDOW_XWINDOW(widget->window)); From 532ea881fbbc5842793e714e83538b062205658d Mon Sep 17 00:00:00 2001 From: Filippo Argiolas Date: Wed, 15 Oct 2008 16:18:22 +0200 Subject: [PATCH 010/128] [247/906] Import xray effect Add xray effect. Maps luma to a negative, slightly cyan tinted, curve, applies some light gaussian blur and multiplies it with its sobel edges. Not sure about the name, likely to change. Probably still needs some tuning. --- tests/examples/gtk/fxtest/fxtest.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index f3c2bfa985..36dd2c162a 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -190,6 +190,7 @@ main (gint argc, gchar * argv[]) gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "xpro"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "lumaxpro"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "sepia"); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "xray"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "sin"); gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "glow"); From 4525015dc69b5e4bc3ecce0c0f775261fda5f1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 3 Feb 2009 18:33:36 +0100 Subject: [PATCH 011/128] [295/906] Fix indention --- tests/examples/gtk/fxtest/fxtest.c | 33 +++++----- tests/examples/gtk/fxtest/pixbufdrop.c | 84 ++++++++++++++------------ 2 files changed, 65 insertions(+), 52 deletions(-) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index 36dd2c162a..a02272fa59 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -17,10 +17,11 @@ static gboolean expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) { GstXOverlay *overlay = - GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (data), - GST_TYPE_X_OVERLAY)); + GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (data), + GST_TYPE_X_OVERLAY)); #ifdef WIN32 - gst_x_overlay_set_xwindow_id (overlay, (gulong)GDK_WINDOW_HWND(widget->window)); + gst_x_overlay_set_xwindow_id (overlay, + (gulong) GDK_WINDOW_HWND (widget->window)); #else gst_x_overlay_set_xwindow_id (overlay, GDK_WINDOW_XWINDOW (widget->window)); #endif @@ -29,7 +30,7 @@ expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) } static void -destroy_cb (GtkWidget *widget, GdkEvent *event, GstElement *pipeline) +destroy_cb (GtkWidget * widget, GdkEvent * event, GstElement * pipeline) { g_message ("destroy callback"); @@ -111,9 +112,10 @@ main (gint argc, gchar * argv[]) GOptionContext *context; GOptionEntry options[] = { - { "source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, - "Use a custom source bin description (gst-launch style)", NULL }, - { NULL } + {"source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, + "Use a custom source bin description (gst-launch style)", NULL} + , + {NULL} }; g_thread_init (NULL); @@ -127,20 +129,23 @@ main (gint argc, gchar * argv[]) return -1; } g_option_context_free (context); - + if (source_desc_array != NULL) { source_desc = g_strjoinv (" ", source_desc_array); g_strfreev (source_desc_array); } if (source_desc == NULL) { - source_desc = g_strdup ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); + source_desc = + g_strdup + ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); } - sourcebin = gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); + sourcebin = + gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); g_free (source_desc); if (error) { - g_print ("Error while parsing source bin description: %s\n", - GST_STR_NULL (error->message)); + g_print ("Error while parsing source bin description: %s\n", + GST_STR_NULL (error->message)); return -1; } @@ -163,9 +168,9 @@ main (gint argc, gchar * argv[]) } g_signal_connect (G_OBJECT (window), "delete-event", - G_CALLBACK (destroy_cb), pipeline); + G_CALLBACK (destroy_cb), pipeline); g_signal_connect (G_OBJECT (window), "destroy-event", - G_CALLBACK (destroy_cb), pipeline); + G_CALLBACK (destroy_cb), pipeline); screen = gtk_drawing_area_new (); diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index 1aaf6bbfc6..928e447f10 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -23,38 +23,38 @@ struct _SourceData }; typedef struct _SourceData SourceData; -static GstBusSyncReply -create_window (GstBus *bus, GstMessage *message, GtkWidget *widget) +static GstBusSyncReply +create_window (GstBus * bus, GstMessage * message, GtkWidget * widget) { - // ignore anything but 'prepare-xwindow-id' element messages - if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) - return GST_BUS_PASS; + // ignore anything but 'prepare-xwindow-id' element messages + if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) + return GST_BUS_PASS; - if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) - return GST_BUS_PASS; + if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) + return GST_BUS_PASS; #ifdef WIN32 - gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), - (gulong)GDK_WINDOW_HWND(widget->window)); + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), + (gulong) GDK_WINDOW_HWND (widget->window)); #else - gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), - GDK_WINDOW_XWINDOW(widget->window)); + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), + GDK_WINDOW_XWINDOW (widget->window)); #endif - gst_message_unref (message); + gst_message_unref (message); - return GST_BUS_DROP; + return GST_BUS_DROP; } -static gboolean -expose_cb(GtkWidget *widget, GdkEventExpose *event, GstElement *videosink) +static gboolean +expose_cb (GtkWidget * widget, GdkEventExpose * event, GstElement * videosink) { - gst_x_overlay_expose (GST_X_OVERLAY (videosink)); - return FALSE; + gst_x_overlay_expose (GST_X_OVERLAY (videosink)); + return FALSE; } static void -destroy_cb (GtkWidget *widget, GdkEvent *event, GstElement *pipeline) +destroy_cb (GtkWidget * widget, GdkEvent * event, GstElement * pipeline) { g_message ("destroy callback"); @@ -112,9 +112,8 @@ set_location_delayed (gpointer data) static void on_drag_data_received (GtkWidget * widget, - GdkDragContext * context, int x, int y, - GtkSelectionData * seldata, guint inf, guint time, - gpointer data) + GdkDragContext * context, int x, int y, + GtkSelectionData * seldata, guint inf, guint time, gpointer data) { GdkPixbufFormat *format; SourceData *userdata = g_new0 (SourceData, 1); @@ -124,7 +123,7 @@ on_drag_data_received (GtkWidget * widget, format = gdk_pixbuf_get_file_info (filename, NULL, NULL); g_return_if_fail (format); g_print ("received %s image: %s\n", filename, - gdk_pixbuf_format_get_name (format)); + gdk_pixbuf_format_get_name (format)); userdata->nick = "location"; userdata->value = g_strdup (filename); userdata->data = data; @@ -132,9 +131,9 @@ on_drag_data_received (GtkWidget * widget, if (delay > 0) { g_print ("%d\n", delay); g_timeout_add_seconds (1, set_location_delayed, userdata); - } - else - g_object_set (G_OBJECT (userdata->data), userdata->nick, userdata->value, NULL); + } else + g_object_set (G_OBJECT (userdata->data), userdata->nick, userdata->value, + NULL); g_free (filename); } @@ -160,11 +159,17 @@ main (gint argc, gchar * argv[]) GOptionContext *context; GOptionEntry options[] = { - { "source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, - "Use a custom source bin description (gst-launch style)", NULL }, - { "method", 'm', 0, G_OPTION_ARG_INT, &method, "1 for gstdifferencematte, 2 for gstpixbufoverlay", "M" }, - { "delay", 'd', 0, G_OPTION_ARG_INT, &delay, "Wait N seconds before to send the image to gstreamer (useful with differencematte)", "N" }, - { NULL } + {"source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, + "Use a custom source bin description (gst-launch style)", NULL} + , + {"method", 'm', 0, G_OPTION_ARG_INT, &method, + "1 for gstdifferencematte, 2 for gstpixbufoverlay", "M"} + , + {"delay", 'd', 0, G_OPTION_ARG_INT, &delay, + "Wait N seconds before to send the image to gstreamer (useful with differencematte)", + "N"} + , + {NULL} }; g_thread_init (NULL); @@ -178,20 +183,23 @@ main (gint argc, gchar * argv[]) return -1; } g_option_context_free (context); - + if (source_desc_array != NULL) { source_desc = g_strjoinv (" ", source_desc_array); g_strfreev (source_desc_array); } if (source_desc == NULL) { - source_desc = g_strdup ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); + source_desc = + g_strdup + ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); } - sourcebin = gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); + sourcebin = + gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); g_free (source_desc); if (error) { - g_print ("Error while parsing source bin description: %s\n", - GST_STR_NULL (error->message)); + g_print ("Error while parsing source bin description: %s\n", + GST_STR_NULL (error->message)); return -1; } @@ -218,9 +226,9 @@ main (gint argc, gchar * argv[]) } g_signal_connect (G_OBJECT (window), "delete-event", - G_CALLBACK (destroy_cb), pipeline); + G_CALLBACK (destroy_cb), pipeline); g_signal_connect (G_OBJECT (window), "destroy-event", - G_CALLBACK (destroy_cb), pipeline); + G_CALLBACK (destroy_cb), pipeline); screen = gtk_drawing_area_new (); @@ -262,7 +270,7 @@ main (gint argc, gchar * argv[]) bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, screen); gst_object_unref (bus); - g_signal_connect(screen, "expose-event", G_CALLBACK(expose_cb), sink); + g_signal_connect (screen, "expose-event", G_CALLBACK (expose_cb), sink); gtk_drag_dest_set (screen, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY); gtk_drag_dest_add_uri_targets (screen); From ea43a174800cb1d325c67674faaf7578648b2a08 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Tue, 10 Feb 2009 21:57:31 -0800 Subject: [PATCH 012/128] [298/906] Revert "Fix indention" This reverts commit 96e4ab18c2cf9876f6c031b9aba6282d0bd45a93. You should have asked first. And you would have been told "no", because it causes people on development branches to do a huge amount of extra work. --- tests/examples/gtk/fxtest/fxtest.c | 33 +++++----- tests/examples/gtk/fxtest/pixbufdrop.c | 84 ++++++++++++-------------- 2 files changed, 52 insertions(+), 65 deletions(-) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index a02272fa59..36dd2c162a 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -17,11 +17,10 @@ static gboolean expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) { GstXOverlay *overlay = - GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (data), - GST_TYPE_X_OVERLAY)); + GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (data), + GST_TYPE_X_OVERLAY)); #ifdef WIN32 - gst_x_overlay_set_xwindow_id (overlay, - (gulong) GDK_WINDOW_HWND (widget->window)); + gst_x_overlay_set_xwindow_id (overlay, (gulong)GDK_WINDOW_HWND(widget->window)); #else gst_x_overlay_set_xwindow_id (overlay, GDK_WINDOW_XWINDOW (widget->window)); #endif @@ -30,7 +29,7 @@ expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) } static void -destroy_cb (GtkWidget * widget, GdkEvent * event, GstElement * pipeline) +destroy_cb (GtkWidget *widget, GdkEvent *event, GstElement *pipeline) { g_message ("destroy callback"); @@ -112,10 +111,9 @@ main (gint argc, gchar * argv[]) GOptionContext *context; GOptionEntry options[] = { - {"source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, - "Use a custom source bin description (gst-launch style)", NULL} - , - {NULL} + { "source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, + "Use a custom source bin description (gst-launch style)", NULL }, + { NULL } }; g_thread_init (NULL); @@ -129,23 +127,20 @@ main (gint argc, gchar * argv[]) return -1; } g_option_context_free (context); - + if (source_desc_array != NULL) { source_desc = g_strjoinv (" ", source_desc_array); g_strfreev (source_desc_array); } if (source_desc == NULL) { - source_desc = - g_strdup - ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); + source_desc = g_strdup ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); } - sourcebin = - gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); + sourcebin = gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); g_free (source_desc); if (error) { - g_print ("Error while parsing source bin description: %s\n", - GST_STR_NULL (error->message)); + g_print ("Error while parsing source bin description: %s\n", + GST_STR_NULL (error->message)); return -1; } @@ -168,9 +163,9 @@ main (gint argc, gchar * argv[]) } g_signal_connect (G_OBJECT (window), "delete-event", - G_CALLBACK (destroy_cb), pipeline); + G_CALLBACK (destroy_cb), pipeline); g_signal_connect (G_OBJECT (window), "destroy-event", - G_CALLBACK (destroy_cb), pipeline); + G_CALLBACK (destroy_cb), pipeline); screen = gtk_drawing_area_new (); diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index 928e447f10..1aaf6bbfc6 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -23,38 +23,38 @@ struct _SourceData }; typedef struct _SourceData SourceData; -static GstBusSyncReply -create_window (GstBus * bus, GstMessage * message, GtkWidget * widget) +static GstBusSyncReply +create_window (GstBus *bus, GstMessage *message, GtkWidget *widget) { - // ignore anything but 'prepare-xwindow-id' element messages - if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) - return GST_BUS_PASS; + // ignore anything but 'prepare-xwindow-id' element messages + if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) + return GST_BUS_PASS; - if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) - return GST_BUS_PASS; + if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) + return GST_BUS_PASS; #ifdef WIN32 - gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), - (gulong) GDK_WINDOW_HWND (widget->window)); + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), + (gulong)GDK_WINDOW_HWND(widget->window)); #else - gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), - GDK_WINDOW_XWINDOW (widget->window)); + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), + GDK_WINDOW_XWINDOW(widget->window)); #endif - gst_message_unref (message); + gst_message_unref (message); - return GST_BUS_DROP; + return GST_BUS_DROP; } -static gboolean -expose_cb (GtkWidget * widget, GdkEventExpose * event, GstElement * videosink) +static gboolean +expose_cb(GtkWidget *widget, GdkEventExpose *event, GstElement *videosink) { - gst_x_overlay_expose (GST_X_OVERLAY (videosink)); - return FALSE; + gst_x_overlay_expose (GST_X_OVERLAY (videosink)); + return FALSE; } static void -destroy_cb (GtkWidget * widget, GdkEvent * event, GstElement * pipeline) +destroy_cb (GtkWidget *widget, GdkEvent *event, GstElement *pipeline) { g_message ("destroy callback"); @@ -112,8 +112,9 @@ set_location_delayed (gpointer data) static void on_drag_data_received (GtkWidget * widget, - GdkDragContext * context, int x, int y, - GtkSelectionData * seldata, guint inf, guint time, gpointer data) + GdkDragContext * context, int x, int y, + GtkSelectionData * seldata, guint inf, guint time, + gpointer data) { GdkPixbufFormat *format; SourceData *userdata = g_new0 (SourceData, 1); @@ -123,7 +124,7 @@ on_drag_data_received (GtkWidget * widget, format = gdk_pixbuf_get_file_info (filename, NULL, NULL); g_return_if_fail (format); g_print ("received %s image: %s\n", filename, - gdk_pixbuf_format_get_name (format)); + gdk_pixbuf_format_get_name (format)); userdata->nick = "location"; userdata->value = g_strdup (filename); userdata->data = data; @@ -131,9 +132,9 @@ on_drag_data_received (GtkWidget * widget, if (delay > 0) { g_print ("%d\n", delay); g_timeout_add_seconds (1, set_location_delayed, userdata); - } else - g_object_set (G_OBJECT (userdata->data), userdata->nick, userdata->value, - NULL); + } + else + g_object_set (G_OBJECT (userdata->data), userdata->nick, userdata->value, NULL); g_free (filename); } @@ -159,17 +160,11 @@ main (gint argc, gchar * argv[]) GOptionContext *context; GOptionEntry options[] = { - {"source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, - "Use a custom source bin description (gst-launch style)", NULL} - , - {"method", 'm', 0, G_OPTION_ARG_INT, &method, - "1 for gstdifferencematte, 2 for gstpixbufoverlay", "M"} - , - {"delay", 'd', 0, G_OPTION_ARG_INT, &delay, - "Wait N seconds before to send the image to gstreamer (useful with differencematte)", - "N"} - , - {NULL} + { "source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, + "Use a custom source bin description (gst-launch style)", NULL }, + { "method", 'm', 0, G_OPTION_ARG_INT, &method, "1 for gstdifferencematte, 2 for gstpixbufoverlay", "M" }, + { "delay", 'd', 0, G_OPTION_ARG_INT, &delay, "Wait N seconds before to send the image to gstreamer (useful with differencematte)", "N" }, + { NULL } }; g_thread_init (NULL); @@ -183,23 +178,20 @@ main (gint argc, gchar * argv[]) return -1; } g_option_context_free (context); - + if (source_desc_array != NULL) { source_desc = g_strjoinv (" ", source_desc_array); g_strfreev (source_desc_array); } if (source_desc == NULL) { - source_desc = - g_strdup - ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); + source_desc = g_strdup ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); } - sourcebin = - gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); + sourcebin = gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); g_free (source_desc); if (error) { - g_print ("Error while parsing source bin description: %s\n", - GST_STR_NULL (error->message)); + g_print ("Error while parsing source bin description: %s\n", + GST_STR_NULL (error->message)); return -1; } @@ -226,9 +218,9 @@ main (gint argc, gchar * argv[]) } g_signal_connect (G_OBJECT (window), "delete-event", - G_CALLBACK (destroy_cb), pipeline); + G_CALLBACK (destroy_cb), pipeline); g_signal_connect (G_OBJECT (window), "destroy-event", - G_CALLBACK (destroy_cb), pipeline); + G_CALLBACK (destroy_cb), pipeline); screen = gtk_drawing_area_new (); @@ -270,7 +262,7 @@ main (gint argc, gchar * argv[]) bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, screen); gst_object_unref (bus); - g_signal_connect (screen, "expose-event", G_CALLBACK (expose_cb), sink); + g_signal_connect(screen, "expose-event", G_CALLBACK(expose_cb), sink); gtk_drag_dest_set (screen, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY); gtk_drag_dest_add_uri_targets (screen); From f115d31df6cb324f6c21cb9aba20c80dcd4b5da6 Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Fri, 23 Jan 2009 02:04:23 +0100 Subject: [PATCH 013/128] [301/906] depends on libpng instead of gdk_pixbuf --- tests/examples/gtk/fxtest/pixbufdrop.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index 1aaf6bbfc6..06df5d1c68 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -119,7 +119,10 @@ on_drag_data_received (GtkWidget * widget, GdkPixbufFormat *format; SourceData *userdata = g_new0 (SourceData, 1); gchar **uris = gtk_selection_data_get_uris (seldata); - gchar *filename = g_filename_from_uri (uris[0], NULL, NULL); + gchar *filename = NULL; + + g_return_if_fail (uris != NULL); + filename = g_filename_from_uri (uris[0], NULL, NULL); g_return_if_fail (filename != NULL); format = gdk_pixbuf_get_file_info (filename, NULL, NULL); g_return_if_fail (format); From 500ebc49b93ab3258d58c84065dd4f4c00f2b801 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Thu, 5 Feb 2009 13:13:51 -0800 Subject: [PATCH 014/128] [308/906] Rename glpixbufoverlay to gloverlay --- tests/examples/gtk/fxtest/pixbufdrop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index 06df5d1c68..bd4ba7f3e9 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -165,7 +165,7 @@ main (gint argc, gchar * argv[]) GOptionEntry options[] = { { "source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, "Use a custom source bin description (gst-launch style)", NULL }, - { "method", 'm', 0, G_OPTION_ARG_INT, &method, "1 for gstdifferencematte, 2 for gstpixbufoverlay", "M" }, + { "method", 'm', 0, G_OPTION_ARG_INT, &method, "1 for gstdifferencematte, 2 for gloverlay", "M" }, { "delay", 'd', 0, G_OPTION_ARG_INT, &delay, "Wait N seconds before to send the image to gstreamer (useful with differencematte)", "N" }, { NULL } }; @@ -207,7 +207,7 @@ main (gint argc, gchar * argv[]) uload = gst_element_factory_make ("glupload", "glu"); if (method == 2) { - filter = gst_element_factory_make ("glpixbufoverlay", "flt"); + filter = gst_element_factory_make ("gloverlay", "flt"); } else { filter = gst_element_factory_make ("gldifferencematte", "flt"); } From cbbb5f1eff623719f3720bbc0a2d85c27f75040e Mon Sep 17 00:00:00 2001 From: David Schleef Date: Tue, 10 Feb 2009 22:39:14 -0800 Subject: [PATCH 015/128] [310/906] Global reindent Indent parameters: INDENT_PARAMETERS="--braces-on-if-line \ --case-brace-indentation0 \ --case-indentation2 \ --braces-after-struct-decl-line \ --line-length80 \ --no-tabs \ --cuddle-else \ --dont-line-up-parentheses \ --honour-newlines \ --continuation-indentation4 \ --tab-size8 \ --indent-level2" --- tests/examples/gtk/fxtest/fxtest.c | 33 +++++----- tests/examples/gtk/fxtest/pixbufdrop.c | 84 ++++++++++++++------------ 2 files changed, 65 insertions(+), 52 deletions(-) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index 36dd2c162a..a02272fa59 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -17,10 +17,11 @@ static gboolean expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) { GstXOverlay *overlay = - GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (data), - GST_TYPE_X_OVERLAY)); + GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (data), + GST_TYPE_X_OVERLAY)); #ifdef WIN32 - gst_x_overlay_set_xwindow_id (overlay, (gulong)GDK_WINDOW_HWND(widget->window)); + gst_x_overlay_set_xwindow_id (overlay, + (gulong) GDK_WINDOW_HWND (widget->window)); #else gst_x_overlay_set_xwindow_id (overlay, GDK_WINDOW_XWINDOW (widget->window)); #endif @@ -29,7 +30,7 @@ expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) } static void -destroy_cb (GtkWidget *widget, GdkEvent *event, GstElement *pipeline) +destroy_cb (GtkWidget * widget, GdkEvent * event, GstElement * pipeline) { g_message ("destroy callback"); @@ -111,9 +112,10 @@ main (gint argc, gchar * argv[]) GOptionContext *context; GOptionEntry options[] = { - { "source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, - "Use a custom source bin description (gst-launch style)", NULL }, - { NULL } + {"source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, + "Use a custom source bin description (gst-launch style)", NULL} + , + {NULL} }; g_thread_init (NULL); @@ -127,20 +129,23 @@ main (gint argc, gchar * argv[]) return -1; } g_option_context_free (context); - + if (source_desc_array != NULL) { source_desc = g_strjoinv (" ", source_desc_array); g_strfreev (source_desc_array); } if (source_desc == NULL) { - source_desc = g_strdup ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); + source_desc = + g_strdup + ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); } - sourcebin = gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); + sourcebin = + gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); g_free (source_desc); if (error) { - g_print ("Error while parsing source bin description: %s\n", - GST_STR_NULL (error->message)); + g_print ("Error while parsing source bin description: %s\n", + GST_STR_NULL (error->message)); return -1; } @@ -163,9 +168,9 @@ main (gint argc, gchar * argv[]) } g_signal_connect (G_OBJECT (window), "delete-event", - G_CALLBACK (destroy_cb), pipeline); + G_CALLBACK (destroy_cb), pipeline); g_signal_connect (G_OBJECT (window), "destroy-event", - G_CALLBACK (destroy_cb), pipeline); + G_CALLBACK (destroy_cb), pipeline); screen = gtk_drawing_area_new (); diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index bd4ba7f3e9..4dba23c36e 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -23,38 +23,38 @@ struct _SourceData }; typedef struct _SourceData SourceData; -static GstBusSyncReply -create_window (GstBus *bus, GstMessage *message, GtkWidget *widget) +static GstBusSyncReply +create_window (GstBus * bus, GstMessage * message, GtkWidget * widget) { - // ignore anything but 'prepare-xwindow-id' element messages - if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) - return GST_BUS_PASS; + // ignore anything but 'prepare-xwindow-id' element messages + if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) + return GST_BUS_PASS; - if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) - return GST_BUS_PASS; + if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) + return GST_BUS_PASS; #ifdef WIN32 - gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), - (gulong)GDK_WINDOW_HWND(widget->window)); + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), + (gulong) GDK_WINDOW_HWND (widget->window)); #else - gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), - GDK_WINDOW_XWINDOW(widget->window)); + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), + GDK_WINDOW_XWINDOW (widget->window)); #endif - gst_message_unref (message); + gst_message_unref (message); - return GST_BUS_DROP; + return GST_BUS_DROP; } -static gboolean -expose_cb(GtkWidget *widget, GdkEventExpose *event, GstElement *videosink) +static gboolean +expose_cb (GtkWidget * widget, GdkEventExpose * event, GstElement * videosink) { - gst_x_overlay_expose (GST_X_OVERLAY (videosink)); - return FALSE; + gst_x_overlay_expose (GST_X_OVERLAY (videosink)); + return FALSE; } static void -destroy_cb (GtkWidget *widget, GdkEvent *event, GstElement *pipeline) +destroy_cb (GtkWidget * widget, GdkEvent * event, GstElement * pipeline) { g_message ("destroy callback"); @@ -112,9 +112,8 @@ set_location_delayed (gpointer data) static void on_drag_data_received (GtkWidget * widget, - GdkDragContext * context, int x, int y, - GtkSelectionData * seldata, guint inf, guint time, - gpointer data) + GdkDragContext * context, int x, int y, + GtkSelectionData * seldata, guint inf, guint time, gpointer data) { GdkPixbufFormat *format; SourceData *userdata = g_new0 (SourceData, 1); @@ -127,7 +126,7 @@ on_drag_data_received (GtkWidget * widget, format = gdk_pixbuf_get_file_info (filename, NULL, NULL); g_return_if_fail (format); g_print ("received %s image: %s\n", filename, - gdk_pixbuf_format_get_name (format)); + gdk_pixbuf_format_get_name (format)); userdata->nick = "location"; userdata->value = g_strdup (filename); userdata->data = data; @@ -135,9 +134,9 @@ on_drag_data_received (GtkWidget * widget, if (delay > 0) { g_print ("%d\n", delay); g_timeout_add_seconds (1, set_location_delayed, userdata); - } - else - g_object_set (G_OBJECT (userdata->data), userdata->nick, userdata->value, NULL); + } else + g_object_set (G_OBJECT (userdata->data), userdata->nick, userdata->value, + NULL); g_free (filename); } @@ -163,11 +162,17 @@ main (gint argc, gchar * argv[]) GOptionContext *context; GOptionEntry options[] = { - { "source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, - "Use a custom source bin description (gst-launch style)", NULL }, - { "method", 'm', 0, G_OPTION_ARG_INT, &method, "1 for gstdifferencematte, 2 for gloverlay", "M" }, - { "delay", 'd', 0, G_OPTION_ARG_INT, &delay, "Wait N seconds before to send the image to gstreamer (useful with differencematte)", "N" }, - { NULL } + {"source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, + "Use a custom source bin description (gst-launch style)", NULL} + , + {"method", 'm', 0, G_OPTION_ARG_INT, &method, + "1 for gstdifferencematte, 2 for gloverlay", "M"} + , + {"delay", 'd', 0, G_OPTION_ARG_INT, &delay, + "Wait N seconds before to send the image to gstreamer (useful with differencematte)", + "N"} + , + {NULL} }; g_thread_init (NULL); @@ -181,20 +186,23 @@ main (gint argc, gchar * argv[]) return -1; } g_option_context_free (context); - + if (source_desc_array != NULL) { source_desc = g_strjoinv (" ", source_desc_array); g_strfreev (source_desc_array); } if (source_desc == NULL) { - source_desc = g_strdup ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); + source_desc = + g_strdup + ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); } - sourcebin = gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); + sourcebin = + gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); g_free (source_desc); if (error) { - g_print ("Error while parsing source bin description: %s\n", - GST_STR_NULL (error->message)); + g_print ("Error while parsing source bin description: %s\n", + GST_STR_NULL (error->message)); return -1; } @@ -221,9 +229,9 @@ main (gint argc, gchar * argv[]) } g_signal_connect (G_OBJECT (window), "delete-event", - G_CALLBACK (destroy_cb), pipeline); + G_CALLBACK (destroy_cb), pipeline); g_signal_connect (G_OBJECT (window), "destroy-event", - G_CALLBACK (destroy_cb), pipeline); + G_CALLBACK (destroy_cb), pipeline); screen = gtk_drawing_area_new (); @@ -265,7 +273,7 @@ main (gint argc, gchar * argv[]) bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, screen); gst_object_unref (bus); - g_signal_connect(screen, "expose-event", G_CALLBACK(expose_cb), sink); + g_signal_connect (screen, "expose-event", G_CALLBACK (expose_cb), sink); gtk_drag_dest_set (screen, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY); gtk_drag_dest_add_uri_targets (screen); From b70b0106b504390337ee3017fab1586b1a9a5473 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Sun, 12 Apr 2009 20:03:30 -0700 Subject: [PATCH 016/128] [328/906] Convert gtk examples to use helper library Helper lib implements gst-gtk glue on all platforms --- tests/examples/gtk/fxtest/fxtest.c | 14 +++-------- tests/examples/gtk/fxtest/pixbufdrop.c | 14 ++--------- tests/examples/gtk/gstgtk.c | 32 ++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 23 deletions(-) create mode 100644 tests/examples/gtk/gstgtk.c diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index a02272fa59..7242c9ba4b 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -3,11 +3,7 @@ #include #include -#ifdef WIN32 -#include -#else -#include -#endif +#include "../gstgtk.h" #include @@ -19,12 +15,8 @@ expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) GstXOverlay *overlay = GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (data), GST_TYPE_X_OVERLAY)); -#ifdef WIN32 - gst_x_overlay_set_xwindow_id (overlay, - (gulong) GDK_WINDOW_HWND (widget->window)); -#else - gst_x_overlay_set_xwindow_id (overlay, GDK_WINDOW_XWINDOW (widget->window)); -#endif + + gst_x_overlay_set_gtk_window (overlay, widget); return FALSE; } diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index 4dba23c36e..9ebe166c45 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -3,11 +3,7 @@ #include #include -#ifdef WIN32 -#include -#else -#include -#endif +#include "../gstgtk.h" #include @@ -33,13 +29,7 @@ create_window (GstBus * bus, GstMessage * message, GtkWidget * widget) if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) return GST_BUS_PASS; -#ifdef WIN32 - gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), - (gulong) GDK_WINDOW_HWND (widget->window)); -#else - gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), - GDK_WINDOW_XWINDOW (widget->window)); -#endif + gst_x_overlay_set_gtk_window (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), widget); gst_message_unref (message); diff --git a/tests/examples/gtk/gstgtk.c b/tests/examples/gtk/gstgtk.c new file mode 100644 index 0000000000..3685c87719 --- /dev/null +++ b/tests/examples/gtk/gstgtk.c @@ -0,0 +1,32 @@ + +#include "gstgtk.h" + +#if defined(GDK_WINDOWING_WIN32) +#include +#elif defined(GDK_WINDOWING_X11) +#include +#elif defined(GDK_WINDOWING_QUARTZ) +#include +#else +#error unimplemented GTK backend +#endif + + +void +gst_x_overlay_set_gtk_window (GstXOverlay *xoverlay, GtkWidget *window) +{ + +#if defined(GDK_WINDOWING_WIN32) + gst_x_overlay_set_xwindow_id (xoverlay, (gulong)GDK_WINDOW_HWND(window->window)); +#elif defined(GDK_WINDOWING_QUARTZ) + gst_x_overlay_set_xwindow_id (xoverlay, + (gulong)gdk_quartz_window_get_nswindow (window->window)); +#elif defined(GDK_WINDOWING_X11) + gst_x_overlay_set_xwindow_id (xoverlay, GDK_WINDOW_XWINDOW(window->window)); +#else +#error unimplemented GTK backend +#endif + +} + + From b1102eafe5f8bfe118debf930310b740a6088fcc Mon Sep 17 00:00:00 2001 From: Filippo Argiolas Date: Tue, 14 Jul 2009 20:25:28 +0200 Subject: [PATCH 017/128] [360/906] examples: add missing copyright/license to my examples --- tests/examples/gtk/fxtest/fxtest.c | 20 ++++++++++++++++++++ tests/examples/gtk/fxtest/pixbufdrop.c | 23 ++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index 7242c9ba4b..8f08828cea 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -1,3 +1,23 @@ +/* + * GStreamer + * Copyright (C) 2008-2009 Filippo Argiolas + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + #include #include #include diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index 9ebe166c45..6fd1783482 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -1,3 +1,23 @@ +/* + * GStreamer + * Copyright (C) 2008-2009 Filippo Argiolas + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + #include #include #include @@ -29,7 +49,8 @@ create_window (GstBus * bus, GstMessage * message, GtkWidget * widget) if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) return GST_BUS_PASS; - gst_x_overlay_set_gtk_window (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), widget); + gst_x_overlay_set_gtk_window (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), + widget); gst_message_unref (message); From 754299a5fd2d8559547e7c0c23a7f51ef3f21422 Mon Sep 17 00:00:00 2001 From: Filippo Argiolas Date: Tue, 14 Jul 2009 20:36:13 +0200 Subject: [PATCH 018/128] [361/906] gstgtk: add missing license and copyright information --- tests/examples/gtk/gstgtk.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/examples/gtk/gstgtk.c b/tests/examples/gtk/gstgtk.c index 3685c87719..3a68e19635 100644 --- a/tests/examples/gtk/gstgtk.c +++ b/tests/examples/gtk/gstgtk.c @@ -1,3 +1,22 @@ +/* + * GStreamer + * Copyright (C) 2009 David A. Schleef + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ #include "gstgtk.h" From 757d0056628cf9adb04460d6c9d0242c25c077e6 Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Fri, 23 Oct 2009 01:07:29 +0200 Subject: [PATCH 019/128] [386/906] pixbufdrop: fix example on win32 --- tests/examples/gtk/fxtest/pixbufdrop.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index 6fd1783482..cd7f175880 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -126,8 +126,11 @@ on_drag_data_received (GtkWidget * widget, GdkDragContext * context, int x, int y, GtkSelectionData * seldata, guint inf, guint time, gpointer data) { - GdkPixbufFormat *format; SourceData *userdata = g_new0 (SourceData, 1); +#ifdef G_OS_WIN32 + gchar *filename = g_filename_from_uri (seldata->data, NULL, NULL); +#else + GdkPixbufFormat *format; gchar **uris = gtk_selection_data_get_uris (seldata); gchar *filename = NULL; @@ -138,6 +141,8 @@ on_drag_data_received (GtkWidget * widget, g_return_if_fail (format); g_print ("received %s image: %s\n", filename, gdk_pixbuf_format_get_name (format)); +#endif + userdata->nick = "location"; userdata->value = g_strdup (filename); userdata->data = data; From df4b871718c0edfbf5b27095fc869f717011dfc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= Date: Tue, 12 Jan 2010 18:32:39 +0300 Subject: [PATCH 020/128] [413/906] Fix Windows compiler warning in test/examples/gtk/fxtest/pixbufdrop.c --- tests/examples/gtk/fxtest/pixbufdrop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index cd7f175880..c2a87161c9 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -128,7 +128,7 @@ on_drag_data_received (GtkWidget * widget, { SourceData *userdata = g_new0 (SourceData, 1); #ifdef G_OS_WIN32 - gchar *filename = g_filename_from_uri (seldata->data, NULL, NULL); + gchar *filename = g_filename_from_uri ((const gchar *) seldata->data, NULL, NULL); #else GdkPixbufFormat *format; gchar **uris = gtk_selection_data_get_uris (seldata); From b130c3b75016c0ec2633e1b14b788cd16296b0aa Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Mon, 12 Jul 2010 18:38:59 +0200 Subject: [PATCH 021/128] [457/906] gtk examples: adapt code since the native-window changes from gtk Fixes bug #599885 --- tests/examples/gtk/fxtest/pixbufdrop.c | 35 ++++++++++++++++++++------ 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index c2a87161c9..d9a951228c 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -57,6 +57,26 @@ create_window (GstBus * bus, GstMessage * message, GtkWidget * widget) return GST_BUS_DROP; } +static void +message_cb (GstBus * bus, GstMessage * message, GstElement * pipeline) +{ + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + + gtk_main_quit (); +} + +static void +realize_cb (GtkWidget * widget, GstElement * pipeline) +{ +#if GTK_CHECK_VERSION(2,18,0) + if (!gdk_window_ensure_native (widget->window)) + g_error ("Failed to create native window!"); +#endif + + gst_element_set_state (pipeline, GST_STATE_PLAYING); +} + static gboolean expose_cb (GtkWidget * widget, GdkEventExpose * event, GstElement * videosink) { @@ -128,7 +148,8 @@ on_drag_data_received (GtkWidget * widget, { SourceData *userdata = g_new0 (SourceData, 1); #ifdef G_OS_WIN32 - gchar *filename = g_filename_from_uri ((const gchar *) seldata->data, NULL, NULL); + gchar *filename = + g_filename_from_uri ((const gchar *) seldata->data, NULL, NULL); #else GdkPixbufFormat *format; gchar **uris = gtk_selection_data_get_uris (seldata); @@ -160,7 +181,6 @@ on_drag_data_received (GtkWidget * widget, gint main (gint argc, gchar * argv[]) { - GstStateChangeReturn ret; GstElement *pipeline; GstElement *uload, *filter, *sink; GstElement *sourcebin; @@ -288,8 +308,13 @@ main (gint argc, gchar * argv[]) bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, screen); + gst_bus_add_signal_watch (bus); + g_signal_connect (bus, "message::error", G_CALLBACK (message_cb), pipeline); + g_signal_connect (bus, "message::warning", G_CALLBACK (message_cb), pipeline); + g_signal_connect (bus, "message::eos", G_CALLBACK (message_cb), pipeline); gst_object_unref (bus); g_signal_connect (screen, "expose-event", G_CALLBACK (expose_cb), sink); + g_signal_connect (screen, "realize", G_CALLBACK (realize_cb), pipeline); gtk_drag_dest_set (screen, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY); gtk_drag_dest_add_uri_targets (screen); @@ -297,12 +322,6 @@ main (gint argc, gchar * argv[]) g_signal_connect (screen, "drag-data-received", G_CALLBACK (on_drag_data_received), filter); - ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); - if (ret == GST_STATE_CHANGE_FAILURE) { - g_print ("Failed to start up pipeline!\n"); - return -1; - } - gtk_widget_show_all (GTK_WIDGET (window)); gtk_main (); From 4555feb0438f0a0ef6f96eaea4d80a556a01505e Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 16 Sep 2010 15:00:29 +0300 Subject: [PATCH 022/128] [461/906] xoverlay: require base from git and update to new API --- tests/examples/gtk/gstgtk.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/examples/gtk/gstgtk.c b/tests/examples/gtk/gstgtk.c index 3a68e19635..7ee2461b2f 100644 --- a/tests/examples/gtk/gstgtk.c +++ b/tests/examples/gtk/gstgtk.c @@ -32,20 +32,20 @@ void -gst_x_overlay_set_gtk_window (GstXOverlay *xoverlay, GtkWidget *window) +gst_x_overlay_set_gtk_window (GstXOverlay * xoverlay, GtkWidget * window) { #if defined(GDK_WINDOWING_WIN32) - gst_x_overlay_set_xwindow_id (xoverlay, (gulong)GDK_WINDOW_HWND(window->window)); + gst_x_overlay_set_window_handle (xoverlay, + (gulong) GDK_WINDOW_HWND (window->window)); #elif defined(GDK_WINDOWING_QUARTZ) - gst_x_overlay_set_xwindow_id (xoverlay, - (gulong)gdk_quartz_window_get_nswindow (window->window)); + gst_x_overlay_set_window_handle (xoverlay, + (gulong) gdk_quartz_window_get_nswindow (window->window)); #elif defined(GDK_WINDOWING_X11) - gst_x_overlay_set_xwindow_id (xoverlay, GDK_WINDOW_XWINDOW(window->window)); + gst_x_overlay_set_window_handle (xoverlay, + GDK_WINDOW_XWINDOW (window->window)); #else #error unimplemented GTK backend #endif } - - From d4a320f81fd3080883a8cc961b134627014c236e Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Thu, 7 Jun 2012 00:51:47 +1000 Subject: [PATCH 023/128] [511/906] tests: update for 1.0 --- tests/examples/gtk/fxtest/fxtest.c | 16 +++++++++------- tests/examples/gtk/fxtest/pixbufdrop.c | 16 +++++++++------- tests/examples/gtk/gstgtk.c | 9 +++++---- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index 8f08828cea..75811f7212 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -18,6 +18,8 @@ * Boston, MA 02111-1307, USA. */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #include #include #include @@ -25,18 +27,18 @@ #include "../gstgtk.h" -#include +#include -/* TODO: use x overlay in the proper way (like suggested in docs, see gtkxoverlay example) */ +/* TODO: use video overlay in the proper way (like suggested in docs, see gtkvideooverlay example) */ static gboolean expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) { - GstXOverlay *overlay = - GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (data), - GST_TYPE_X_OVERLAY)); + GstVideoOverlay *overlay = + GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (data), + GST_TYPE_VIDEO_OVERLAY)); - gst_x_overlay_set_gtk_window (overlay, widget); + gst_video_overlay_set_gtk_window (overlay, widget); return FALSE; } @@ -149,7 +151,7 @@ main (gint argc, gchar * argv[]) if (source_desc == NULL) { source_desc = g_strdup - ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); + ("videotestsrc ! video/x-raw, width=352, height=288 ! identity"); } sourcebin = diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index d9a951228c..d68fde1fb8 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -18,6 +18,8 @@ * Boston, MA 02111-1307, USA. */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #include #include #include @@ -25,7 +27,7 @@ #include "../gstgtk.h" -#include +#include static gint delay = 0; static gint saveddelay = 0; @@ -42,15 +44,15 @@ typedef struct _SourceData SourceData; static GstBusSyncReply create_window (GstBus * bus, GstMessage * message, GtkWidget * widget) { - // ignore anything but 'prepare-xwindow-id' element messages + // ignore anything but 'prepare-window-handle' element messages if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) return GST_BUS_PASS; - if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) + if (!gst_is_video_overlay_prepare_window_handle_message (message)) return GST_BUS_PASS; - gst_x_overlay_set_gtk_window (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), - widget); + gst_video_overlay_set_gtk_window (GST_VIDEO_OVERLAY (GST_MESSAGE_SRC + (message)), widget); gst_message_unref (message); @@ -80,7 +82,7 @@ realize_cb (GtkWidget * widget, GstElement * pipeline) static gboolean expose_cb (GtkWidget * widget, GdkEventExpose * event, GstElement * videosink) { - gst_x_overlay_expose (GST_X_OVERLAY (videosink)); + gst_video_overlay_expose (GST_VIDEO_OVERLAY (videosink)); return FALSE; } @@ -230,7 +232,7 @@ main (gint argc, gchar * argv[]) if (source_desc == NULL) { source_desc = g_strdup - ("videotestsrc ! video/x-raw-rgb, width=352, height=288 ! identity"); + ("videotestsrc ! video/x-raw, width=352, height=288 ! identity"); } sourcebin = diff --git a/tests/examples/gtk/gstgtk.c b/tests/examples/gtk/gstgtk.c index 7ee2461b2f..069d8e00b9 100644 --- a/tests/examples/gtk/gstgtk.c +++ b/tests/examples/gtk/gstgtk.c @@ -32,17 +32,18 @@ void -gst_x_overlay_set_gtk_window (GstXOverlay * xoverlay, GtkWidget * window) +gst_video_overlay_set_gtk_window (GstVideoOverlay * videooverlay, + GtkWidget * window) { #if defined(GDK_WINDOWING_WIN32) - gst_x_overlay_set_window_handle (xoverlay, + gst_video_overlay_set_window_handle (videooverlay, (gulong) GDK_WINDOW_HWND (window->window)); #elif defined(GDK_WINDOWING_QUARTZ) - gst_x_overlay_set_window_handle (xoverlay, + gst_video_overlay_set_window_handle (videooverlay, (gulong) gdk_quartz_window_get_nswindow (window->window)); #elif defined(GDK_WINDOWING_X11) - gst_x_overlay_set_window_handle (xoverlay, + gst_video_overlay_set_window_handle (videooverlay, GDK_WINDOW_XWINDOW (window->window)); #else #error unimplemented GTK backend From 3d180b1602ec4ecff22dda0bfb64aac2df75a183 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 14 Aug 2012 14:41:19 +1000 Subject: [PATCH 024/128] [560/906] examples: update for bus api changes and glimagesink changes --- tests/examples/gtk/fxtest/pixbufdrop.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index d68fde1fb8..c4664965cf 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -309,7 +309,8 @@ main (gint argc, gchar * argv[]) gtk_container_add (GTK_CONTAINER (window), vbox); bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, screen); + gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, screen, + NULL); gst_bus_add_signal_watch (bus); g_signal_connect (bus, "message::error", G_CALLBACK (message_cb), pipeline); g_signal_connect (bus, "message::warning", G_CALLBACK (message_cb), pipeline); From d6054f9738e50faa090136e2cbd8ed1d9b29940a Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Thu, 8 Nov 2012 22:53:56 +1100 Subject: [PATCH 025/128] [603/906] update FSF address --- tests/examples/gtk/fxtest/fxtest.c | 4 ++-- tests/examples/gtk/fxtest/pixbufdrop.c | 4 ++-- tests/examples/gtk/gstgtk.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index 75811f7212..40298d297c 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -14,8 +14,8 @@ * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #define GLIB_DISABLE_DEPRECATION_WARNINGS diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index c4664965cf..1607b962bc 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -14,8 +14,8 @@ * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #define GLIB_DISABLE_DEPRECATION_WARNINGS diff --git a/tests/examples/gtk/gstgtk.c b/tests/examples/gtk/gstgtk.c index 069d8e00b9..ec52f9ca3b 100644 --- a/tests/examples/gtk/gstgtk.c +++ b/tests/examples/gtk/gstgtk.c @@ -14,8 +14,8 @@ * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #include "gstgtk.h" From 1a2de27a527dddd7bc482b6fc6a8f1b86295a0a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 28 Jun 2013 11:00:46 +0200 Subject: [PATCH 026/128] [720/906] examples: Stop using deprecated GLib thread API --- tests/examples/gtk/fxtest/fxtest.c | 2 -- tests/examples/gtk/fxtest/pixbufdrop.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index 40298d297c..124beb140f 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -132,8 +132,6 @@ main (gint argc, gchar * argv[]) {NULL} }; - g_thread_init (NULL); - context = g_option_context_new (NULL); g_option_context_add_main_entries (context, options, NULL); g_option_context_add_group (context, gst_init_get_option_group ()); diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index 1607b962bc..5853068433 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -213,8 +213,6 @@ main (gint argc, gchar * argv[]) {NULL} }; - g_thread_init (NULL); - context = g_option_context_new (NULL); g_option_context_add_main_entries (context, options, NULL); g_option_context_add_group (context, gst_init_get_option_group ()); From 804c5b14e83950ab7d083c92e78633eeac9f30e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 10 Jul 2013 11:24:34 +0200 Subject: [PATCH 027/128] [729/906] gl: Include config.h everywhere --- tests/examples/gtk/fxtest/fxtest.c | 3 +++ tests/examples/gtk/fxtest/pixbufdrop.c | 3 +++ tests/examples/gtk/gstgtk.c | 3 +++ 3 files changed, 9 insertions(+) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index 124beb140f..c4a8e0b52d 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -17,6 +17,9 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #define GLIB_DISABLE_DEPRECATION_WARNINGS diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index 5853068433..d9f363bfdc 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -17,6 +17,9 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #define GLIB_DISABLE_DEPRECATION_WARNINGS diff --git a/tests/examples/gtk/gstgtk.c b/tests/examples/gtk/gstgtk.c index ec52f9ca3b..dc680a1b5e 100644 --- a/tests/examples/gtk/gstgtk.c +++ b/tests/examples/gtk/gstgtk.c @@ -17,6 +17,9 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include "gstgtk.h" From e850ed5498f6f720ad2b3bc1530edc3a316fc376 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 16 Jul 2013 18:27:07 +0200 Subject: [PATCH 028/128] [769/906] tests/examples: fix and port some of the examples. Realize widgets, remove glupload element. --- tests/examples/gtk/fxtest/fxtest.c | 7 +++---- tests/examples/gtk/fxtest/pixbufdrop.c | 23 +++++++---------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index c4a8e0b52d..8152cb8e3f 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -114,7 +114,7 @@ main (gint argc, gchar * argv[]) { GstStateChangeReturn ret; GstElement *pipeline; - GstElement *uload, *filter, *sink; + GstElement *filter, *sink; GstElement *sourcebin; GError *error = NULL; @@ -171,13 +171,12 @@ main (gint argc, gchar * argv[]) pipeline = gst_pipeline_new ("pipeline"); - uload = gst_element_factory_make ("glupload", "glu"); filter = gst_element_factory_make ("gleffects", "flt"); sink = gst_element_factory_make ("glimagesink", "glsink"); - gst_bin_add_many (GST_BIN (pipeline), sourcebin, uload, filter, sink, NULL); + gst_bin_add_many (GST_BIN (pipeline), sourcebin, filter, sink, NULL); - if (!gst_element_link_many (sourcebin, uload, filter, sink, NULL)) { + if (!gst_element_link_many (sourcebin, filter, sink, NULL)) { g_print ("Failed to link one or more elements!\n"); return -1; } diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index d9f363bfdc..5f10b01bf8 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -71,17 +71,6 @@ message_cb (GstBus * bus, GstMessage * message, GstElement * pipeline) gtk_main_quit (); } -static void -realize_cb (GtkWidget * widget, GstElement * pipeline) -{ -#if GTK_CHECK_VERSION(2,18,0) - if (!gdk_window_ensure_native (widget->window)) - g_error ("Failed to create native window!"); -#endif - - gst_element_set_state (pipeline, GST_STATE_PLAYING); -} - static gboolean expose_cb (GtkWidget * widget, GdkEventExpose * event, GstElement * videosink) { @@ -187,7 +176,7 @@ gint main (gint argc, gchar * argv[]) { GstElement *pipeline; - GstElement *uload, *filter, *sink; + GstElement *filter, *sink; GstElement *sourcebin; GstBus *bus; GError *error = NULL; @@ -252,7 +241,6 @@ main (gint argc, gchar * argv[]) pipeline = gst_pipeline_new ("pipeline"); - uload = gst_element_factory_make ("glupload", "glu"); if (method == 2) { filter = gst_element_factory_make ("gloverlay", "flt"); } else { @@ -260,9 +248,9 @@ main (gint argc, gchar * argv[]) } sink = gst_element_factory_make ("glimagesink", "glsink"); - gst_bin_add_many (GST_BIN (pipeline), sourcebin, uload, filter, sink, NULL); + gst_bin_add_many (GST_BIN (pipeline), sourcebin, filter, sink, NULL); - if (!gst_element_link_many (sourcebin, uload, filter, sink, NULL)) { + if (!gst_element_link_many (sourcebin, filter, sink, NULL)) { g_print ("Failed to link one or more elements!\n"); return -1; } @@ -309,6 +297,8 @@ main (gint argc, gchar * argv[]) gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_realize (screen); + bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, screen, NULL); @@ -318,7 +308,6 @@ main (gint argc, gchar * argv[]) g_signal_connect (bus, "message::eos", G_CALLBACK (message_cb), pipeline); gst_object_unref (bus); g_signal_connect (screen, "expose-event", G_CALLBACK (expose_cb), sink); - g_signal_connect (screen, "realize", G_CALLBACK (realize_cb), pipeline); gtk_drag_dest_set (screen, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY); gtk_drag_dest_add_uri_targets (screen); @@ -328,6 +317,8 @@ main (gint argc, gchar * argv[]) gtk_widget_show_all (GTK_WIDGET (window)); + gst_element_set_state (pipeline, GST_STATE_PLAYING); + gtk_main (); return 0; From f5cb0ccb16d7991186096d1ed5b993f86d2e0283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 17 Jul 2013 11:22:02 +0200 Subject: [PATCH 029/128] [771/906] gl: Some less long/ulong/gulong usage --- tests/examples/gtk/gstgtk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/examples/gtk/gstgtk.c b/tests/examples/gtk/gstgtk.c index dc680a1b5e..5dcdcdca47 100644 --- a/tests/examples/gtk/gstgtk.c +++ b/tests/examples/gtk/gstgtk.c @@ -41,10 +41,10 @@ gst_video_overlay_set_gtk_window (GstVideoOverlay * videooverlay, #if defined(GDK_WINDOWING_WIN32) gst_video_overlay_set_window_handle (videooverlay, - (gulong) GDK_WINDOW_HWND (window->window)); + (guintptr) GDK_WINDOW_HWND (window->window)); #elif defined(GDK_WINDOWING_QUARTZ) gst_video_overlay_set_window_handle (videooverlay, - (gulong) gdk_quartz_window_get_nswindow (window->window)); + (guintptr) gdk_quartz_window_get_nswindow (window->window)); #elif defined(GDK_WINDOWING_X11) gst_video_overlay_set_window_handle (videooverlay, GDK_WINDOW_XWINDOW (window->window)); From 499cd75e4b6c67a7062aa4dfbf239216b55925a4 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Sun, 29 Dec 2013 17:29:53 +1100 Subject: [PATCH 030/128] [864/906] examples: update to gtk3 --- tests/examples/gtk/fxtest/fxtest.c | 44 +++++++++++----------- tests/examples/gtk/fxtest/pixbufdrop.c | 8 ++-- tests/examples/gtk/gstgtk.c | 51 +++++++++++++++++--------- 3 files changed, 59 insertions(+), 44 deletions(-) diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c index 8152cb8e3f..7ff5d71d45 100644 --- a/tests/examples/gtk/fxtest/fxtest.c +++ b/tests/examples/gtk/fxtest/fxtest.c @@ -35,7 +35,7 @@ /* TODO: use video overlay in the proper way (like suggested in docs, see gtkvideooverlay example) */ static gboolean -expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer data) +expose_cb (GtkWidget * widget, gpointer data) { GstVideoOverlay *overlay = GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (data), @@ -69,7 +69,7 @@ apply_fx (GtkWidget * widget, gpointer data) (G_OBJECT (data)), "effect") )->enum_class; - fx = gtk_combo_box_get_active_text (GTK_COMBO_BOX (widget)); + fx = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (widget)); g_print ("setting: %s - %s\n", fx, g_enum_get_value_by_nick (p_class, fx)->value_name); g_object_set (G_OBJECT (data), "effect", g_enum_get_value_by_nick (p_class, @@ -190,34 +190,34 @@ main (gint argc, gchar * argv[]) gtk_widget_set_size_request (screen, 640, 480); // 500 x 376 - vbox = gtk_vbox_new (FALSE, 2); + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); gtk_box_pack_start (GTK_BOX (vbox), screen, TRUE, TRUE, 0); - combo = gtk_combo_box_new_text (); + combo = gtk_combo_box_text_new (); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "identity"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "mirror"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "squeeze"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "stretch"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "fisheye"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "twirl"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "bulge"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "tunnel"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "square"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "heat"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "xpro"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "lumaxpro"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "sepia"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "xray"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "sin"); - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "glow"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "identity"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "mirror"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "squeeze"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "stretch"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "fisheye"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "twirl"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "bulge"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "tunnel"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "square"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "heat"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "xpro"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "lumaxpro"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "sepia"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "xray"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "sin"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "glow"); g_signal_connect (G_OBJECT (combo), "changed", G_CALLBACK (apply_fx), filter); gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0); - hbox = gtk_hbox_new (FALSE, 0); + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); play = gtk_button_new_with_label ("PLAY"); @@ -246,7 +246,7 @@ main (gint argc, gchar * argv[]) gtk_container_add (GTK_CONTAINER (window), vbox); - g_signal_connect (screen, "expose-event", G_CALLBACK (expose_cb), pipeline); + g_signal_connect (screen, "realize", G_CALLBACK (expose_cb), pipeline); ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); if (ret == GST_STATE_CHANGE_FAILURE) { diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c index 5f10b01bf8..7422e8afc6 100644 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ b/tests/examples/gtk/fxtest/pixbufdrop.c @@ -72,7 +72,7 @@ message_cb (GstBus * bus, GstMessage * message, GstElement * pipeline) } static gboolean -expose_cb (GtkWidget * widget, GdkEventExpose * event, GstElement * videosink) +expose_cb (GtkWidget * widget, cairo_t * cr, GstElement * videosink) { gst_video_overlay_expose (GST_VIDEO_OVERLAY (videosink)); return FALSE; @@ -264,11 +264,11 @@ main (gint argc, gchar * argv[]) gtk_widget_set_size_request (screen, 640, 480); // 500 x 376 - vbox = gtk_vbox_new (FALSE, 2); + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); gtk_box_pack_start (GTK_BOX (vbox), screen, TRUE, TRUE, 0); - hbox = gtk_hbox_new (FALSE, 0); + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); play = gtk_button_new_with_label ("PLAY"); @@ -307,7 +307,7 @@ main (gint argc, gchar * argv[]) g_signal_connect (bus, "message::warning", G_CALLBACK (message_cb), pipeline); g_signal_connect (bus, "message::eos", G_CALLBACK (message_cb), pipeline); gst_object_unref (bus); - g_signal_connect (screen, "expose-event", G_CALLBACK (expose_cb), sink); + g_signal_connect (screen, "draw", G_CALLBACK (expose_cb), sink); gtk_drag_dest_set (screen, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY); gtk_drag_dest_add_uri_targets (screen); diff --git a/tests/examples/gtk/gstgtk.c b/tests/examples/gtk/gstgtk.c index 5dcdcdca47..eb6272522d 100644 --- a/tests/examples/gtk/gstgtk.c +++ b/tests/examples/gtk/gstgtk.c @@ -21,35 +21,50 @@ #include "config.h" #endif +#include #include "gstgtk.h" -#if defined(GDK_WINDOWING_WIN32) +#if defined(GST_GL_HAVE_WINDOW_WIN32) && defined(GDK_WINDOWING_WIN32) #include -#elif defined(GDK_WINDOWING_X11) +#endif +#if defined(GST_GL_HAVE_WINDOW_X11) && defined(GDK_WINDOWING_X11) #include -#elif defined(GDK_WINDOWING_QUARTZ) +#endif +#if defined(GST_GL_HAVE_WINDOW_COCOA) && defined(GDK_WINDOWING_QUARTZ) #include -#else -#error unimplemented GTK backend #endif void gst_video_overlay_set_gtk_window (GstVideoOverlay * videooverlay, - GtkWidget * window) + GtkWidget * widget) { + GdkWindow *window; + GdkDisplay *display; + const gchar *user_choice = g_getenv ("GST_GL_WINDOW"); -#if defined(GDK_WINDOWING_WIN32) - gst_video_overlay_set_window_handle (videooverlay, - (guintptr) GDK_WINDOW_HWND (window->window)); -#elif defined(GDK_WINDOWING_QUARTZ) - gst_video_overlay_set_window_handle (videooverlay, - (guintptr) gdk_quartz_window_get_nswindow (window->window)); -#elif defined(GDK_WINDOWING_X11) - gst_video_overlay_set_window_handle (videooverlay, - GDK_WINDOW_XWINDOW (window->window)); -#else -#error unimplemented GTK backend + window = gtk_widget_get_window (widget); + display = gdk_window_get_display (window); + +#if defined(GST_GL_HAVE_WINDOW_WIN32) && defined(GDK_WINDOWING_WIN32) + if (GDK_IS_WIN32_DISPLAY (display) && (!user_choice + || g_strcmp0 (user_choice, "win32") == 0)) { + gst_video_overlay_set_window_handle (videooverlay, + (guintptr) GDK_WINDOW_HWND (window)); + } else #endif - +#if defined(GST_GL_HAVE_WINDOW_COCOA) && defined(GDK_WINDOWING_QUARTZ) + if (GDK_IS_QUARTZ_DISPLAY (display) && (!user_choice + || g_strcmp0 (user_choice, "cocoa") == 0)) { + gst_video_overlay_set_window_handle (videooverlay, (guintptr) + gdk_quartz_window_get_nswindow (window)); + } else +#endif +#if defined(GST_GL_HAVE_WINDOW_X11) && defined(GDK_WINDOWING_X11) + if (GDK_IS_X11_DISPLAY (display) && (!user_choice + || g_strcmp0 (user_choice, "x11") == 0)) { + gst_video_overlay_set_window_handle (videooverlay, GDK_WINDOW_XID (window)); + } else +#endif + g_error ("Unsupported Gtk+ backend"); } From 12e669f3881e395bdffb83424b5f76b678353ce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= Date: Tue, 18 Mar 2014 00:08:50 +0000 Subject: [PATCH 031/128] gl: fix the use of always-defined macros After 2a0f0399ae226089c2ba07b1b904741b856f37af GST_GL_* macros are always defined to 0 or 1. Don't use #ifdef ... or #if defined() on them. https://bugzilla.gnome.org/show_bug.cgi?id=726591 --- tests/examples/gtk/gstgtk.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/examples/gtk/gstgtk.c b/tests/examples/gtk/gstgtk.c index eb6272522d..3d0d15ae22 100644 --- a/tests/examples/gtk/gstgtk.c +++ b/tests/examples/gtk/gstgtk.c @@ -24,13 +24,13 @@ #include #include "gstgtk.h" -#if defined(GST_GL_HAVE_WINDOW_WIN32) && defined(GDK_WINDOWING_WIN32) +#if GST_GL_HAVE_WINDOW_WIN32 && GDK_WINDOWING_WIN32 #include #endif -#if defined(GST_GL_HAVE_WINDOW_X11) && defined(GDK_WINDOWING_X11) +#if GST_GL_HAVE_WINDOW_X11 && GDK_WINDOWING_X11 #include #endif -#if defined(GST_GL_HAVE_WINDOW_COCOA) && defined(GDK_WINDOWING_QUARTZ) +#if GST_GL_HAVE_WINDOW_COCOA && GDK_WINDOWING_QUARTZ #include #endif @@ -46,21 +46,21 @@ gst_video_overlay_set_gtk_window (GstVideoOverlay * videooverlay, window = gtk_widget_get_window (widget); display = gdk_window_get_display (window); -#if defined(GST_GL_HAVE_WINDOW_WIN32) && defined(GDK_WINDOWING_WIN32) +#if GST_GL_HAVE_WINDOW_WIN32 && GDK_WINDOWING_WIN32 if (GDK_IS_WIN32_DISPLAY (display) && (!user_choice || g_strcmp0 (user_choice, "win32") == 0)) { gst_video_overlay_set_window_handle (videooverlay, (guintptr) GDK_WINDOW_HWND (window)); } else #endif -#if defined(GST_GL_HAVE_WINDOW_COCOA) && defined(GDK_WINDOWING_QUARTZ) +#if GST_GL_HAVE_WINDOW_COCOA && GDK_WINDOWING_QUARTZ if (GDK_IS_QUARTZ_DISPLAY (display) && (!user_choice || g_strcmp0 (user_choice, "cocoa") == 0)) { gst_video_overlay_set_window_handle (videooverlay, (guintptr) gdk_quartz_window_get_nswindow (window)); } else #endif -#if defined(GST_GL_HAVE_WINDOW_X11) && defined(GDK_WINDOWING_X11) +#if GST_GL_HAVE_WINDOW_X11 && GDK_WINDOWING_X11 if (GDK_IS_X11_DISPLAY (display) && (!user_choice || g_strcmp0 (user_choice, "x11") == 0)) { gst_video_overlay_set_window_handle (videooverlay, GDK_WINDOW_XID (window)); From fc45400f4ecc8a66d6393d806a0eb79776b04b5b Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 29 Apr 2014 16:38:55 +1000 Subject: [PATCH 032/128] gl/examples: move to -bad - fix all the compiler errors - give them their own gl directory --- tests/examples/gtk/fxtest/fxtest.c | 262 -------------------- tests/examples/gtk/fxtest/pixbufdrop.c | 325 ------------------------- tests/examples/gtk/gstgtk.c | 70 ------ 3 files changed, 657 deletions(-) delete mode 100644 tests/examples/gtk/fxtest/fxtest.c delete mode 100644 tests/examples/gtk/fxtest/pixbufdrop.c delete mode 100644 tests/examples/gtk/gstgtk.c diff --git a/tests/examples/gtk/fxtest/fxtest.c b/tests/examples/gtk/fxtest/fxtest.c deleted file mode 100644 index 7ff5d71d45..0000000000 --- a/tests/examples/gtk/fxtest/fxtest.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008-2009 Filippo Argiolas - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define GLIB_DISABLE_DEPRECATION_WARNINGS - -#include -#include -#include -#include - -#include "../gstgtk.h" - -#include - - -/* TODO: use video overlay in the proper way (like suggested in docs, see gtkvideooverlay example) */ -static gboolean -expose_cb (GtkWidget * widget, gpointer data) -{ - GstVideoOverlay *overlay = - GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (data), - GST_TYPE_VIDEO_OVERLAY)); - - gst_video_overlay_set_gtk_window (overlay, widget); - - return FALSE; -} - -static void -destroy_cb (GtkWidget * widget, GdkEvent * event, GstElement * pipeline) -{ - g_message ("destroy callback"); - - gst_element_set_state (pipeline, GST_STATE_NULL); - gst_object_unref (pipeline); - - gtk_main_quit (); -} - -gboolean -apply_fx (GtkWidget * widget, gpointer data) -{ - gchar *fx; - GEnumClass *p_class; - -/* heeeellppppp!! */ - p_class = - G_PARAM_SPEC_ENUM (g_object_class_find_property (G_OBJECT_GET_CLASS - (G_OBJECT (data)), "effect") - )->enum_class; - - fx = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (widget)); - g_print ("setting: %s - %s\n", fx, g_enum_get_value_by_nick (p_class, - fx)->value_name); - g_object_set (G_OBJECT (data), "effect", g_enum_get_value_by_nick (p_class, - fx)->value, NULL); - return FALSE; -} - -gboolean -play_cb (GtkWidget * widget, gpointer data) -{ - g_message ("playing"); - gst_element_set_state (GST_ELEMENT (data), GST_STATE_PLAYING); - return FALSE; -} - -gboolean -null_cb (GtkWidget * widget, gpointer data) -{ - g_message ("nulling"); - gst_element_set_state (GST_ELEMENT (data), GST_STATE_NULL); - return FALSE; -} - -gboolean -ready_cb (GtkWidget * widget, gpointer data) -{ - g_message ("readying"); - gst_element_set_state (GST_ELEMENT (data), GST_STATE_READY); - return FALSE; -} - -gboolean -pause_cb (GtkWidget * widget, gpointer data) -{ - g_message ("pausing"); - gst_element_set_state (GST_ELEMENT (data), GST_STATE_PAUSED); - return FALSE; -} - -gint -main (gint argc, gchar * argv[]) -{ - GstStateChangeReturn ret; - GstElement *pipeline; - GstElement *filter, *sink; - GstElement *sourcebin; - GError *error = NULL; - - GtkWidget *window; - GtkWidget *screen; - GtkWidget *vbox, *combo; - GtkWidget *hbox; - GtkWidget *play, *pause, *null, *ready; - - gchar **source_desc_array = NULL; - gchar *source_desc = NULL; - - GOptionContext *context; - GOptionEntry options[] = { - {"source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, - "Use a custom source bin description (gst-launch style)", NULL} - , - {NULL} - }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, options, NULL); - g_option_context_add_group (context, gst_init_get_option_group ()); - g_option_context_add_group (context, gtk_get_option_group (TRUE)); - if (!g_option_context_parse (context, &argc, &argv, &error)) { - g_print ("Inizialization error: %s\n", GST_STR_NULL (error->message)); - return -1; - } - g_option_context_free (context); - - if (source_desc_array != NULL) { - source_desc = g_strjoinv (" ", source_desc_array); - g_strfreev (source_desc_array); - } - if (source_desc == NULL) { - source_desc = - g_strdup - ("videotestsrc ! video/x-raw, width=352, height=288 ! identity"); - } - - sourcebin = - gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); - g_free (source_desc); - if (error) { - g_print ("Error while parsing source bin description: %s\n", - GST_STR_NULL (error->message)); - return -1; - } - - g_set_application_name ("gst-gl-effects test app"); - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width (GTK_CONTAINER (window), 3); - - pipeline = gst_pipeline_new ("pipeline"); - - filter = gst_element_factory_make ("gleffects", "flt"); - sink = gst_element_factory_make ("glimagesink", "glsink"); - - gst_bin_add_many (GST_BIN (pipeline), sourcebin, filter, sink, NULL); - - if (!gst_element_link_many (sourcebin, filter, sink, NULL)) { - g_print ("Failed to link one or more elements!\n"); - return -1; - } - - g_signal_connect (G_OBJECT (window), "delete-event", - G_CALLBACK (destroy_cb), pipeline); - g_signal_connect (G_OBJECT (window), "destroy-event", - G_CALLBACK (destroy_cb), pipeline); - - screen = gtk_drawing_area_new (); - - gtk_widget_set_size_request (screen, 640, 480); // 500 x 376 - - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); - - gtk_box_pack_start (GTK_BOX (vbox), screen, TRUE, TRUE, 0); - - combo = gtk_combo_box_text_new (); - - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "identity"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "mirror"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "squeeze"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "stretch"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "fisheye"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "twirl"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "bulge"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "tunnel"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "square"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "heat"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "xpro"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "lumaxpro"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "sepia"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "xray"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "sin"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "glow"); - - g_signal_connect (G_OBJECT (combo), "changed", G_CALLBACK (apply_fx), filter); - - gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0); - - hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - - play = gtk_button_new_with_label ("PLAY"); - - g_signal_connect (G_OBJECT (play), "clicked", G_CALLBACK (play_cb), pipeline); - - pause = gtk_button_new_with_label ("PAUSE"); - - g_signal_connect (G_OBJECT (pause), "clicked", - G_CALLBACK (pause_cb), pipeline); - - null = gtk_button_new_with_label ("NULL"); - - g_signal_connect (G_OBJECT (null), "clicked", G_CALLBACK (null_cb), pipeline); - - ready = gtk_button_new_with_label ("READY"); - - g_signal_connect (G_OBJECT (ready), "clicked", - G_CALLBACK (ready_cb), pipeline); - - gtk_box_pack_start (GTK_BOX (hbox), null, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (hbox), ready, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (hbox), play, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (hbox), pause, TRUE, TRUE, 0); - - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - - gtk_container_add (GTK_CONTAINER (window), vbox); - - g_signal_connect (screen, "realize", G_CALLBACK (expose_cb), pipeline); - - ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); - if (ret == GST_STATE_CHANGE_FAILURE) { - g_print ("Failed to start up pipeline!\n"); - return -1; - } - - gtk_widget_show_all (GTK_WIDGET (window)); - - gtk_main (); - - return 0; -} diff --git a/tests/examples/gtk/fxtest/pixbufdrop.c b/tests/examples/gtk/fxtest/pixbufdrop.c deleted file mode 100644 index 7422e8afc6..0000000000 --- a/tests/examples/gtk/fxtest/pixbufdrop.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008-2009 Filippo Argiolas - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define GLIB_DISABLE_DEPRECATION_WARNINGS - -#include -#include -#include -#include - -#include "../gstgtk.h" - -#include - -static gint delay = 0; -static gint saveddelay = 0; -static gint method = 1; - -struct _SourceData -{ - gpointer data; - gpointer nick; - gpointer value; -}; -typedef struct _SourceData SourceData; - -static GstBusSyncReply -create_window (GstBus * bus, GstMessage * message, GtkWidget * widget) -{ - // ignore anything but 'prepare-window-handle' element messages - if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) - return GST_BUS_PASS; - - if (!gst_is_video_overlay_prepare_window_handle_message (message)) - return GST_BUS_PASS; - - gst_video_overlay_set_gtk_window (GST_VIDEO_OVERLAY (GST_MESSAGE_SRC - (message)), widget); - - gst_message_unref (message); - - return GST_BUS_DROP; -} - -static void -message_cb (GstBus * bus, GstMessage * message, GstElement * pipeline) -{ - gst_element_set_state (pipeline, GST_STATE_NULL); - gst_object_unref (pipeline); - - gtk_main_quit (); -} - -static gboolean -expose_cb (GtkWidget * widget, cairo_t * cr, GstElement * videosink) -{ - gst_video_overlay_expose (GST_VIDEO_OVERLAY (videosink)); - return FALSE; -} - -static void -destroy_cb (GtkWidget * widget, GdkEvent * event, GstElement * pipeline) -{ - g_message ("destroy callback"); - - gst_element_set_state (pipeline, GST_STATE_NULL); - gst_object_unref (pipeline); - - gtk_main_quit (); -} - -gboolean -play_cb (GtkWidget * widget, gpointer data) -{ - g_message ("playing"); - gst_element_set_state (GST_ELEMENT (data), GST_STATE_PLAYING); - return FALSE; -} - -gboolean -null_cb (GtkWidget * widget, gpointer data) -{ - g_message ("nulling"); - gst_element_set_state (GST_ELEMENT (data), GST_STATE_NULL); - return FALSE; -} - -gboolean -ready_cb (GtkWidget * widget, gpointer data) -{ - g_message ("readying"); - gst_element_set_state (GST_ELEMENT (data), GST_STATE_READY); - return FALSE; -} - -gboolean -pause_cb (GtkWidget * widget, gpointer data) -{ - g_message ("pausing"); - gst_element_set_state (GST_ELEMENT (data), GST_STATE_PAUSED); - return FALSE; -} - -static gboolean -set_location_delayed (gpointer data) -{ - SourceData *sdata = (SourceData *) data; - delay--; - g_print ("%d\n", delay); - if (delay > 0) { - return TRUE; - } - g_object_set (G_OBJECT (sdata->data), sdata->nick, sdata->value, NULL); - delay = saveddelay; - return FALSE; -} - -static void -on_drag_data_received (GtkWidget * widget, - GdkDragContext * context, int x, int y, - GtkSelectionData * seldata, guint inf, guint time, gpointer data) -{ - SourceData *userdata = g_new0 (SourceData, 1); -#ifdef G_OS_WIN32 - gchar *filename = - g_filename_from_uri ((const gchar *) seldata->data, NULL, NULL); -#else - GdkPixbufFormat *format; - gchar **uris = gtk_selection_data_get_uris (seldata); - gchar *filename = NULL; - - g_return_if_fail (uris != NULL); - filename = g_filename_from_uri (uris[0], NULL, NULL); - g_return_if_fail (filename != NULL); - format = gdk_pixbuf_get_file_info (filename, NULL, NULL); - g_return_if_fail (format); - g_print ("received %s image: %s\n", filename, - gdk_pixbuf_format_get_name (format)); -#endif - - userdata->nick = "location"; - userdata->value = g_strdup (filename); - userdata->data = data; - saveddelay = delay; - if (delay > 0) { - g_print ("%d\n", delay); - g_timeout_add_seconds (1, set_location_delayed, userdata); - } else - g_object_set (G_OBJECT (userdata->data), userdata->nick, userdata->value, - NULL); - g_free (filename); -} - - -gint -main (gint argc, gchar * argv[]) -{ - GstElement *pipeline; - GstElement *filter, *sink; - GstElement *sourcebin; - GstBus *bus; - GError *error = NULL; - - GtkWidget *window; - GtkWidget *screen; - GtkWidget *vbox; - GtkWidget *hbox; - GtkWidget *play, *pause, *null, *ready; - - gchar **source_desc_array = NULL; - gchar *source_desc = NULL; - - GOptionContext *context; - GOptionEntry options[] = { - {"source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array, - "Use a custom source bin description (gst-launch style)", NULL} - , - {"method", 'm', 0, G_OPTION_ARG_INT, &method, - "1 for gstdifferencematte, 2 for gloverlay", "M"} - , - {"delay", 'd', 0, G_OPTION_ARG_INT, &delay, - "Wait N seconds before to send the image to gstreamer (useful with differencematte)", - "N"} - , - {NULL} - }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, options, NULL); - g_option_context_add_group (context, gst_init_get_option_group ()); - g_option_context_add_group (context, gtk_get_option_group (TRUE)); - if (!g_option_context_parse (context, &argc, &argv, &error)) { - g_print ("Inizialization error: %s\n", GST_STR_NULL (error->message)); - return -1; - } - g_option_context_free (context); - - if (source_desc_array != NULL) { - source_desc = g_strjoinv (" ", source_desc_array); - g_strfreev (source_desc_array); - } - if (source_desc == NULL) { - source_desc = - g_strdup - ("videotestsrc ! video/x-raw, width=352, height=288 ! identity"); - } - - sourcebin = - gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error); - g_free (source_desc); - if (error) { - g_print ("Error while parsing source bin description: %s\n", - GST_STR_NULL (error->message)); - return -1; - } - - g_set_application_name ("gst-gl-effects test app"); - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width (GTK_CONTAINER (window), 3); - - pipeline = gst_pipeline_new ("pipeline"); - - if (method == 2) { - filter = gst_element_factory_make ("gloverlay", "flt"); - } else { - filter = gst_element_factory_make ("gldifferencematte", "flt"); - } - sink = gst_element_factory_make ("glimagesink", "glsink"); - - gst_bin_add_many (GST_BIN (pipeline), sourcebin, filter, sink, NULL); - - if (!gst_element_link_many (sourcebin, filter, sink, NULL)) { - g_print ("Failed to link one or more elements!\n"); - return -1; - } - - g_signal_connect (G_OBJECT (window), "delete-event", - G_CALLBACK (destroy_cb), pipeline); - g_signal_connect (G_OBJECT (window), "destroy-event", - G_CALLBACK (destroy_cb), pipeline); - - screen = gtk_drawing_area_new (); - - gtk_widget_set_size_request (screen, 640, 480); // 500 x 376 - - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); - - gtk_box_pack_start (GTK_BOX (vbox), screen, TRUE, TRUE, 0); - - hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - - play = gtk_button_new_with_label ("PLAY"); - - g_signal_connect (G_OBJECT (play), "clicked", G_CALLBACK (play_cb), pipeline); - - pause = gtk_button_new_with_label ("PAUSE"); - - g_signal_connect (G_OBJECT (pause), "clicked", - G_CALLBACK (pause_cb), pipeline); - - null = gtk_button_new_with_label ("NULL"); - - g_signal_connect (G_OBJECT (null), "clicked", G_CALLBACK (null_cb), pipeline); - - ready = gtk_button_new_with_label ("READY"); - - g_signal_connect (G_OBJECT (ready), "clicked", - G_CALLBACK (ready_cb), pipeline); - - gtk_box_pack_start (GTK_BOX (hbox), null, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (hbox), ready, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (hbox), play, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (hbox), pause, TRUE, TRUE, 0); - - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - - gtk_container_add (GTK_CONTAINER (window), vbox); - - gtk_widget_realize (screen); - - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, screen, - NULL); - gst_bus_add_signal_watch (bus); - g_signal_connect (bus, "message::error", G_CALLBACK (message_cb), pipeline); - g_signal_connect (bus, "message::warning", G_CALLBACK (message_cb), pipeline); - g_signal_connect (bus, "message::eos", G_CALLBACK (message_cb), pipeline); - gst_object_unref (bus); - g_signal_connect (screen, "draw", G_CALLBACK (expose_cb), sink); - - gtk_drag_dest_set (screen, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY); - gtk_drag_dest_add_uri_targets (screen); - - g_signal_connect (screen, "drag-data-received", - G_CALLBACK (on_drag_data_received), filter); - - gtk_widget_show_all (GTK_WIDGET (window)); - - gst_element_set_state (pipeline, GST_STATE_PLAYING); - - gtk_main (); - - return 0; -} diff --git a/tests/examples/gtk/gstgtk.c b/tests/examples/gtk/gstgtk.c deleted file mode 100644 index 3d0d15ae22..0000000000 --- a/tests/examples/gtk/gstgtk.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2009 David A. Schleef - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include "gstgtk.h" - -#if GST_GL_HAVE_WINDOW_WIN32 && GDK_WINDOWING_WIN32 -#include -#endif -#if GST_GL_HAVE_WINDOW_X11 && GDK_WINDOWING_X11 -#include -#endif -#if GST_GL_HAVE_WINDOW_COCOA && GDK_WINDOWING_QUARTZ -#include -#endif - - -void -gst_video_overlay_set_gtk_window (GstVideoOverlay * videooverlay, - GtkWidget * widget) -{ - GdkWindow *window; - GdkDisplay *display; - const gchar *user_choice = g_getenv ("GST_GL_WINDOW"); - - window = gtk_widget_get_window (widget); - display = gdk_window_get_display (window); - -#if GST_GL_HAVE_WINDOW_WIN32 && GDK_WINDOWING_WIN32 - if (GDK_IS_WIN32_DISPLAY (display) && (!user_choice - || g_strcmp0 (user_choice, "win32") == 0)) { - gst_video_overlay_set_window_handle (videooverlay, - (guintptr) GDK_WINDOW_HWND (window)); - } else -#endif -#if GST_GL_HAVE_WINDOW_COCOA && GDK_WINDOWING_QUARTZ - if (GDK_IS_QUARTZ_DISPLAY (display) && (!user_choice - || g_strcmp0 (user_choice, "cocoa") == 0)) { - gst_video_overlay_set_window_handle (videooverlay, (guintptr) - gdk_quartz_window_get_nswindow (window)); - } else -#endif -#if GST_GL_HAVE_WINDOW_X11 && GDK_WINDOWING_X11 - if (GDK_IS_X11_DISPLAY (display) && (!user_choice - || g_strcmp0 (user_choice, "x11") == 0)) { - gst_video_overlay_set_window_handle (videooverlay, GDK_WINDOW_XID (window)); - } else -#endif - g_error ("Unsupported Gtk+ backend"); -} From a959c410d97d5c56326c10e9028182113906d733 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Thu, 18 Dec 2014 17:00:30 +1100 Subject: [PATCH 033/128] Implement gtk sinks two sinks are provided. gtksink which is a cairo/software based renderer and gtkglsink which utilises the GL support in gtk and gstreamer. --- ext/gtk/Makefile.am | 43 +++ ext/gtk/gstgtkglsink.c | 435 +++++++++++++++++++++++ ext/gtk/gstgtkglsink.h | 86 +++++ ext/gtk/gstgtksink.c | 274 +++++++++++++++ ext/gtk/gstgtksink.h | 77 ++++ ext/gtk/gstplugin.c | 52 +++ ext/gtk/gtkgstglwidget.c | 617 +++++++++++++++++++++++++++++++++ ext/gtk/gtkgstglwidget.h | 77 ++++ ext/gtk/gtkgstwidget.c | 240 +++++++++++++ ext/gtk/gtkgstwidget.h | 72 ++++ tests/examples/gtk/Makefile.am | 22 ++ tests/examples/gtk/gtkglsink.c | 201 +++++++++++ tests/examples/gtk/gtksink.c | 184 ++++++++++ 13 files changed, 2380 insertions(+) create mode 100644 ext/gtk/Makefile.am create mode 100644 ext/gtk/gstgtkglsink.c create mode 100644 ext/gtk/gstgtkglsink.h create mode 100644 ext/gtk/gstgtksink.c create mode 100644 ext/gtk/gstgtksink.h create mode 100644 ext/gtk/gstplugin.c create mode 100644 ext/gtk/gtkgstglwidget.c create mode 100644 ext/gtk/gtkgstglwidget.h create mode 100644 ext/gtk/gtkgstwidget.c create mode 100644 ext/gtk/gtkgstwidget.h create mode 100644 tests/examples/gtk/Makefile.am create mode 100644 tests/examples/gtk/gtkglsink.c create mode 100644 tests/examples/gtk/gtksink.c diff --git a/ext/gtk/Makefile.am b/ext/gtk/Makefile.am new file mode 100644 index 0000000000..45d0be0d28 --- /dev/null +++ b/ext/gtk/Makefile.am @@ -0,0 +1,43 @@ +# preamble +NULL = +BUILT_SOURCES = +CLEANFILES = +EXTRA_DIST = +DISTCLEANFILES = +lib_LTLIBRARIES = + +# source +sources = \ + gtkgstwidget.c \ + gtkgstwidget.h \ + gstgtksink.c \ + gstgtksink.h \ + gstplugin.c \ + $(NULL) + +libgstgtksink_la_CFLAGS = \ + -I$(top_srcdir)/gst-libs \ + -I$(top_builddir)/gst-libs \ + $(GTK3_CFLAGS) \ + $(GST_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) +libgstgtksink_la_LIBADD = \ + $(GTK3_LIBS) \ + $(GST_BASE_LIBS) \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstvideo-$(GST_API_VERSION) + +libgstgtksink_la_SOURCES = $(sources) +libgstgtksink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstgtksink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) + +if USE_GTK3_GL +if USE_GL +libgstgtksink_la_SOURCES += gstgtkglsink.c gstgtkglsink.h gtkgstglwidget.c gtkgstglwidget.h +libgstgtksink_la_LIBADD += \ + $(top_builddir)/gst-libs/gst/gl/libgstgl-$(GST_API_VERSION).la +endif +endif + +plugin_LTLIBRARIES = libgstgtksink.la diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c new file mode 100644 index 0000000000..1572f9707c --- /dev/null +++ b/ext/gtk/gstgtkglsink.c @@ -0,0 +1,435 @@ +/* + * GStreamer + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:gstgtkglsink + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstgtkglsink.h" + +GST_DEBUG_CATEGORY (gst_debug_gtk_gl_sink); +#define GST_CAT_DEFAULT gst_debug_gtk_gl_sink + +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_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); + +static GstStaticPadTemplate gst_gtk_gl_sink_template = +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"))); + +enum +{ + ARG_0, + PROP_WIDGET +}; + +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, + "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; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesink_class = (GstBaseSinkClass *) klass; + gstvideosink_class = (GstVideoSinkClass *) klass; + + gobject_class->set_property = gst_gtk_gl_sink_set_property; + gobject_class->get_property = gst_gtk_gl_sink_get_property; + + gst_element_class_set_metadata (gstelement_class, "Gtk Video Sink", + "Sink/Video", "A video sink the 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)); + + 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->widget = (GtkGstGLWidget *) gtk_gst_gl_widget_new (); +} + +static void +gst_gtk_gl_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +_reset (GstGtkGLSink * gtk_sink) +{ + 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; + } +} + +static void +gst_gtk_gl_sink_finalize (GObject * object) +{ + GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (object);; + + _reset (gtk_sink); + + g_object_unref (gtk_sink->widget); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +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, gtk_sink->widget); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query) +{ + GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (bsink); + gboolean res = FALSE; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CONTEXT: + { + const gchar *context_type; + GstContext *context, *old_context; + gboolean ret; + + ret = gst_gl_handle_context_query ((GstElement *) gtk_sink, query, + >k_sink->display, >k_sink->gtk_context); + + if (gtk_sink->display) + gst_gl_display_filter_gl_api (gtk_sink->display, GST_GL_API_OPENGL3); + + 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, gtk_sink->context, + NULL); + gst_query_set_context (query, context); + gst_context_unref (context); + + ret = gtk_sink->context != NULL; + } + GST_LOG_OBJECT (gtk_sink, "context query of type %s %i", context_type, + ret); + + if (ret) + return ret; + } + default: + res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); + break; + } + + return res; +} + +static gboolean +gst_gtk_gl_sink_stop (GstBaseSink * bsink) +{ + 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; + + 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: + if (!gtk_gst_gl_widget_init_winsys (gtk_sink->widget)) + return GST_STATE_CHANGE_FAILURE; + + gtk_sink->display = gtk_gst_gl_widget_get_display (gtk_sink->widget); + gtk_sink->context = gtk_gst_gl_widget_get_context (gtk_sink->widget); + gtk_sink->gtk_context = + gtk_gst_gl_widget_get_gtk_context (gtk_sink->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: + gtk_gst_gl_widget_set_buffer (gtk_sink->widget, NULL); + break; + case GST_STATE_CHANGE_READY_TO_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) +{ + GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (bsink); + + GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps); + + _reset (gtk_sink); + + if (!gst_video_info_from_caps (>k_sink->v_info, caps)) + return FALSE; + + if (!gtk_gst_gl_widget_set_caps (gtk_sink->widget, caps)) + return FALSE; + + 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); + + gtk_gst_gl_widget_set_buffer (gtk_sink->widget, buf); + + 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; + GstStructure *config; + GstCaps *caps; + guint size; + gboolean need_pool; + + if (!gtk_sink->display || !gtk_sink->context) + return FALSE; + + gst_query_parse_allocation (query, &caps, &need_pool); + + 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) { + GstVideoInfo info; + + if (!gst_video_info_from_caps (&info, caps)) + goto invalid_caps; + + GST_DEBUG_OBJECT (gtk_sink, "create new pool"); + pool = gst_gl_buffer_pool_new (gtk_sink->context); + + /* the normal size of a frame */ + size = info.size; + + config = gst_buffer_pool_get_config (pool); + 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) { + gst_query_add_allocation_pool (query, pool, size, 2, 0); + gst_object_unref (pool); + } + + /* we also support various metadata */ + gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0); + + if (gtk_sink->context->gl_vtable->FenceSync) + gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0); + + return TRUE; + + /* ERRORS */ +no_caps: + { + GST_DEBUG_OBJECT (bsink, "no caps specified"); + return FALSE; + } +invalid_caps: + { + GST_DEBUG_OBJECT (bsink, "invalid caps specified"); + return FALSE; + } +config_failed: + { + GST_DEBUG_OBJECT (bsink, "failed setting config"); + return FALSE; + } +} diff --git a/ext/gtk/gstgtkglsink.h b/ext/gtk/gstgtkglsink.h new file mode 100644 index 0000000000..1457260584 --- /dev/null +++ b/ext/gtk/gstgtkglsink.h @@ -0,0 +1,86 @@ +/* + * GStreamer + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_GTK_GL_SINK_H__ +#define __GST_GTK_GL_SINK_H__ + +#include +#include +#include +#include +#include + +typedef struct _GstGtkGLSink GstGtkGLSink; +typedef struct _GstGtkGLSinkClass GstGtkGLSinkClass; +typedef struct _GstGtkGLSinkPrivate GstGtkGLSinkPrivate; + +#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)) +#define GST_IS_GTK_GL_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GTK_GL_SINK)) +#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)) + +/** + * GstGtkGLSink: + * + * Opaque #GstGtkGLSink object + */ +struct _GstGtkGLSink +{ + /* */ + GstVideoSink parent; + + GtkGstGLWidget *widget; + + GstVideoInfo v_info; + GstBufferPool *pool; + + GstGLDisplay *display; + GstGLContext *context; + GstGLContext *gtk_context; + + GstGLUpload *upload; + GstBuffer *uploaded_buffer; + + GstGtkGLSinkPrivate *priv; +}; + +/** + * GstGtkGLSinkClass: + * + * The #GstGtkGLSinkClass struct only contains private data + */ +struct _GstGtkGLSinkClass +{ + /* */ + GstVideoSinkClass object_class; +}; + +GstGtkGLSink * gst_gtk_gl_sink_new (void); + +G_END_DECLS + +#endif /* __GST_GTK_GL_SINK_H__ */ diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c new file mode 100644 index 0000000000..e60d1bb6f1 --- /dev/null +++ b/ext/gtk/gstgtksink.c @@ -0,0 +1,274 @@ +/* + * GStreamer + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:gtkgstsink + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstgtksink.h" + +GST_DEBUG_CATEGORY (gst_debug_gtk_sink); +#define GST_CAT_DEFAULT gst_debug_gtk_sink + +static void gst_gtk_sink_finalize (GObject * object); +static void gst_gtk_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * param_spec); +static void gst_gtk_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * param_spec); + +static gboolean gst_gtk_sink_stop (GstBaseSink * bsink); + +static gboolean gst_gtk_sink_query (GstBaseSink * bsink, GstQuery * query); + +static GstStateChangeReturn +gst_gtk_sink_change_state (GstElement * element, GstStateChange transition); + +static void gst_gtk_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, + GstClockTime * start, GstClockTime * end); +static gboolean gst_gtk_sink_set_caps (GstBaseSink * bsink, GstCaps * caps); +static GstFlowReturn gst_gtk_sink_show_frame (GstVideoSink * bsink, + GstBuffer * buf); + +static GstStaticPadTemplate gst_gtk_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("BGRA")) + ); + +enum +{ + ARG_0, + PROP_WIDGET +}; + +enum +{ + SIGNAL_0, + LAST_SIGNAL +}; + +#define gst_gtk_sink_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstGtkSink, gst_gtk_sink, + GST_TYPE_VIDEO_SINK, GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_sink, "gtksink", + 0, "Gtk Video Sink")); + +static void +gst_gtk_sink_class_init (GstGtkSinkClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSinkClass *gstbasesink_class; + GstVideoSinkClass *gstvideosink_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesink_class = (GstBaseSinkClass *) klass; + gstvideosink_class = (GstVideoSinkClass *) klass; + + gobject_class->set_property = gst_gtk_sink_set_property; + gobject_class->get_property = gst_gtk_sink_get_property; + + gst_element_class_set_metadata (gstelement_class, "Gtk Video Sink", + "Sink/Video", "A video sink the 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)); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_gtk_sink_template)); + + gobject_class->finalize = gst_gtk_sink_finalize; + + gstelement_class->change_state = gst_gtk_sink_change_state; + gstbasesink_class->query = gst_gtk_sink_query; + gstbasesink_class->set_caps = gst_gtk_sink_set_caps; + gstbasesink_class->get_times = gst_gtk_sink_get_times; + gstbasesink_class->stop = gst_gtk_sink_stop; + + gstvideosink_class->show_frame = gst_gtk_sink_show_frame; +} + +static void +gst_gtk_sink_init (GstGtkSink * gtk_sink) +{ + gtk_sink->widget = (GtkGstWidget *) gtk_gst_widget_new (); +} + +static void +gst_gtk_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_gtk_sink_finalize (GObject * object) +{ + GstGtkSink *gtk_sink = GST_GTK_SINK (object);; + + g_object_unref (gtk_sink->widget); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_gtk_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstGtkSink *gtk_sink; + + gtk_sink = GST_GTK_SINK (object); + + switch (prop_id) { + case PROP_WIDGET: + g_value_set_object (value, gtk_sink->widget); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_gtk_sink_query (GstBaseSink * bsink, GstQuery * query) +{ + gboolean res = FALSE; + + switch (GST_QUERY_TYPE (query)) { + default: + res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); + break; + } + + return res; +} + +static gboolean +gst_gtk_sink_stop (GstBaseSink * bsink) +{ + return TRUE; +} + +static GstStateChangeReturn +gst_gtk_sink_change_state (GstElement * element, GstStateChange transition) +{ + GstGtkSink *gtk_sink = GST_GTK_SINK (element); + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + 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: + 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: + gtk_gst_widget_set_buffer (gtk_sink->widget, NULL); + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + return ret; +} + +static void +gst_gtk_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, + GstClockTime * start, GstClockTime * end) +{ + GstGtkSink *gtk_sink; + + gtk_sink = GST_GTK_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_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) +{ + GstGtkSink *gtk_sink = GST_GTK_SINK (bsink); + + GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps); + + if (!gst_video_info_from_caps (>k_sink->v_info, caps)) + return FALSE; + + if (!gtk_gst_widget_set_caps (gtk_sink->widget, caps)) + return FALSE; + + return TRUE; +} + +static GstFlowReturn +gst_gtk_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) +{ + GstGtkSink *gtk_sink; + + GST_TRACE ("rendering buffer:%p", buf); + + gtk_sink = GST_GTK_SINK (vsink); + + if (gtk_sink->widget) + gtk_gst_widget_set_buffer (gtk_sink->widget, buf); + + return GST_FLOW_OK; +} diff --git a/ext/gtk/gstgtksink.h b/ext/gtk/gstgtksink.h new file mode 100644 index 0000000000..e8cdf48a53 --- /dev/null +++ b/ext/gtk/gstgtksink.h @@ -0,0 +1,77 @@ +/* + * GStreamer + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_GTK_SINK_H__ +#define __GST_GTK_SINK_H__ + +#include +#include +#include +#include + +typedef struct _GstGtkSink GstGtkSink; +typedef struct _GstGtkSinkClass GstGtkSinkClass; +typedef struct _GstGtkSinkPrivate GstGtkSinkPrivate; + +#include + +G_BEGIN_DECLS + +GType gst_gtk_sink_get_type (void); +#define GST_TYPE_GTK_SINK (gst_gtk_sink_get_type()) +#define GST_GTK_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GTK_SINK,GstGtkSink)) +#define GST_GTK_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GTK_SINK,GstGtkSinkClass)) +#define GST_IS_GTK_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GTK_SINK)) +#define GST_IS_GTK_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GTK_SINK)) +#define GST_GTK_SINK_CAST(obj) ((GstGtkSink*)(obj)) + +/** + * GstGtkSink: + * + * Opaque #GstGtkSink object + */ +struct _GstGtkSink +{ + /* */ + GstVideoSink parent; + + GstVideoInfo v_info; + + GtkGstWidget *widget; + + GstGtkSinkPrivate *priv; +}; + +/** + * GstGtkSinkClass: + * + * The #GstGtkSinkClass struct only contains private data + */ +struct _GstGtkSinkClass +{ + /* */ + GstVideoSinkClass object_class; +}; + +GstGtkSink * gst_gtk_sink_new (void); + +G_END_DECLS + +#endif /* __GST_GTK_SINK_H__ */ diff --git a/ext/gtk/gstplugin.c b/ext/gtk/gstplugin.c new file mode 100644 index 0000000000..4c5d26b54e --- /dev/null +++ b/ext/gtk/gstplugin.c @@ -0,0 +1,52 @@ +/* + * GStreamer + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstgtksink.h" +#if defined(HAVE_GTK3_GL) +#include "gstgtkglsink.h" +#endif + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "gtksink", + GST_RANK_NONE, GST_TYPE_GTK_SINK)) { + return FALSE; + } +#if defined(HAVE_GTK3_GL) + if (!gst_element_register (plugin, "gtkglsink", + GST_RANK_NONE, GST_TYPE_GTK_GL_SINK)) { + return FALSE; + } +#endif + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + gstgtk, + "Gtk+ sink", + plugin_init, PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, + GST_PACKAGE_ORIGIN) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c new file mode 100644 index 0000000000..b5eb85d8c8 --- /dev/null +++ b/ext/gtk/gtkgstglwidget.c @@ -0,0 +1,617 @@ +/* + * GStreamer + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "gtkgstglwidget.h" +#include + +#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11) +#include +#include +#include +#endif + +/** + * SECTION:gtkgstglwidget + * @short_description: a #GtkGLArea that renders GStreamer video #GstBuffers + * @see_also: #GtkGLArea, #GstBuffer + * + * #GtkGstGLWidget is an #GtkWidget that renders GStreamer video buffers. + */ + +#define GST_CAT_DEFAULT gtk_gst_gl_widget_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +G_DEFINE_TYPE_WITH_CODE (GtkGstGLWidget, gtk_gst_gl_widget, GTK_TYPE_GL_AREA, + GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gtkgstglwidget", 0, + "Gtk Gst GL Widget");); + +#define GTK_GST_GL_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + GTK_TYPE_GST_GL_WIDGET, GtkGstGLWidgetPrivate)) + +struct _GtkGstGLWidgetPrivate +{ + GMutex lock; + + gboolean negotiated; + GstBuffer *buffer; + GstCaps *gl_caps; + GstCaps *caps; + GstVideoInfo v_info; + gboolean new_buffer; + + gboolean initted; + GstGLDisplay *display; + GdkGLContext *gdk_context; + GstGLContext *other_context; + GstGLContext *context; + GstGLUpload *upload; + GstGLShader *shader; + GLuint vao; + GLuint vertex_buffer; + GLint attr_position; + GLint attr_texture; + GLuint current_tex; +}; + +static void +gtk_gst_gl_widget_get_preferred_width (GtkWidget * widget, gint * min, + gint * natural) +{ + GtkGstGLWidget *gst_widget = (GtkGstGLWidget *) widget; + gint video_width = GST_VIDEO_INFO_WIDTH (&gst_widget->priv->v_info); + + if (!gst_widget->priv->negotiated) + video_width = 10; + + if (min) + *min = 1; + if (natural) + *natural = video_width; +} + +static void +gtk_gst_gl_widget_get_preferred_height (GtkWidget * widget, gint * min, + gint * natural) +{ + GtkGstGLWidget *gst_widget = (GtkGstGLWidget *) widget; + gint video_height = GST_VIDEO_INFO_HEIGHT (&gst_widget->priv->v_info); + + if (!gst_widget->priv->negotiated) + video_height = 10; + + if (min) + *min = 1; + if (natural) + *natural = video_height; +} + +static const GLfloat vertices[] = { + 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, + -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 1.0f +}; + +static void +gtk_gst_gl_widget_bind_buffer (GtkGstGLWidget * gst_widget) +{ + const GstGLFuncs *gl = gst_widget->priv->context->gl_vtable; + + gl->BindBuffer (GL_ARRAY_BUFFER, gst_widget->priv->vertex_buffer); + + /* Load the vertex position */ + gl->VertexAttribPointer (gst_widget->priv->attr_position, 3, GL_FLOAT, + GL_FALSE, 5 * sizeof (GLfloat), (void *) 0); + + /* Load the texture coordinate */ + gl->VertexAttribPointer (gst_widget->priv->attr_texture, 2, GL_FLOAT, + GL_FALSE, 5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat))); + + gl->EnableVertexAttribArray (gst_widget->priv->attr_position); + gl->EnableVertexAttribArray (gst_widget->priv->attr_texture); +} + +static void +gtk_gst_gl_widget_unbind_buffer (GtkGstGLWidget * gst_widget) +{ + const GstGLFuncs *gl = gst_widget->priv->context->gl_vtable; + + gl->BindBuffer (GL_ARRAY_BUFFER, 0); + + gl->DisableVertexAttribArray (gst_widget->priv->attr_position); + gl->DisableVertexAttribArray (gst_widget->priv->attr_texture); +} + +static void +gtk_gst_gl_widget_init_redisplay (GtkGstGLWidget * gst_widget) +{ + const GstGLFuncs *gl = gst_widget->priv->context->gl_vtable; + + gst_widget->priv->shader = gst_gl_shader_new (gst_widget->priv->context); + + gst_gl_shader_compile_with_default_vf_and_check + (gst_widget->priv->shader, &gst_widget->priv->attr_position, + &gst_widget->priv->attr_texture); + + if (gl->GenVertexArrays) { + gl->GenVertexArrays (1, &gst_widget->priv->vao); + gl->BindVertexArray (gst_widget->priv->vao); + } + + gl->GenBuffers (1, &gst_widget->priv->vertex_buffer); + gl->BindBuffer (GL_ARRAY_BUFFER, gst_widget->priv->vertex_buffer); + gl->BufferData (GL_ARRAY_BUFFER, 4 * 5 * sizeof (GLfloat), vertices, + GL_STATIC_DRAW); + + if (gl->GenVertexArrays) { + gtk_gst_gl_widget_bind_buffer (gst_widget); + gl->BindVertexArray (0); + } + + gl->BindBuffer (GL_ARRAY_BUFFER, 0); + + gst_widget->priv->initted = TRUE; +} + +static void +_redraw_texture (GtkGstGLWidget * gst_widget, guint tex) +{ + const GstGLFuncs *gl = gst_widget->priv->context->gl_vtable; + GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; + + gst_gl_shader_use (gst_widget->priv->shader); + + if (gl->BindVertexArray) + gl->BindVertexArray (gst_widget->priv->vao); + else + gtk_gst_gl_widget_bind_buffer (gst_widget); + + gl->ActiveTexture (GL_TEXTURE0); + gl->BindTexture (GL_TEXTURE_2D, tex); + gst_gl_shader_set_uniform_1i (gst_widget->priv->shader, "tex", 0); + + gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); + + if (gl->BindVertexArray) + gl->BindVertexArray (0); + else + gtk_gst_gl_widget_unbind_buffer (gst_widget); + + gl->BindTexture (GL_TEXTURE_2D, 0); +} + +static gboolean +gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) +{ + GtkGstGLWidget *gst_widget = (GtkGstGLWidget *) widget; + + g_mutex_lock (&gst_widget->priv->lock); + + if (!gst_widget->priv->initted) + gtk_gst_gl_widget_init_redisplay (gst_widget); + + if (gst_widget->priv->initted && gst_widget->priv->negotiated + && gst_widget->priv->buffer) { + GST_DEBUG ("rendering buffer %p with gdk context %p", + gst_widget->priv->buffer, context); + + gst_gl_context_activate (gst_widget->priv->other_context, TRUE); + + if (gst_widget->priv->new_buffer || gst_widget->priv->current_tex == 0) { + GstVideoFrame gl_frame; + GstGLSyncMeta *sync_meta; + + if (!gst_video_frame_map (&gl_frame, &gst_widget->priv->v_info, + gst_widget->priv->buffer, GST_MAP_READ | GST_MAP_GL)) { + goto error; + } + + sync_meta = gst_buffer_get_gl_sync_meta (gst_widget->priv->buffer); + if (sync_meta) { + gst_gl_sync_meta_set_sync_point (sync_meta, gst_widget->priv->context); + gst_gl_sync_meta_wait (sync_meta, gst_widget->priv->other_context); + } + + gst_widget->priv->current_tex = *(guint *) gl_frame.data[0]; + + gst_video_frame_unmap (&gl_frame); + } + + _redraw_texture (gst_widget, gst_widget->priv->current_tex); + gst_widget->priv->new_buffer = FALSE; + } else { + error: + /* FIXME: nothing to display */ + glClearColor (0.0, 0.0, 0.0, 0.0); + glClear (GL_COLOR_BUFFER_BIT); + } + + gst_gl_context_activate (gst_widget->priv->other_context, FALSE); + + g_mutex_unlock (&gst_widget->priv->lock); + return FALSE; +} + +typedef void (*ThreadFunc) (gpointer data); + +struct invoke_context +{ + ThreadFunc func; + gpointer data; + GMutex lock; + GCond cond; + gboolean fired; +}; + +static gboolean +_invoke_func (struct invoke_context *info) +{ + g_mutex_lock (&info->lock); + info->func (info->data); + info->fired = TRUE; + g_cond_signal (&info->cond); + g_mutex_unlock (&info->lock); + + return G_SOURCE_REMOVE; +} + +static void +_invoke_on_main (ThreadFunc func, gpointer data) +{ + GMainContext *main_context = g_main_context_default (); + struct invoke_context info; + + g_mutex_init (&info.lock); + g_cond_init (&info.cond); + info.fired = FALSE; + info.func = func; + info.data = data; + + g_main_context_invoke (main_context, (GSourceFunc) _invoke_func, &info); + + g_mutex_lock (&info.lock); + while (!info.fired) + g_cond_wait (&info.cond, &info.lock); + g_mutex_unlock (&info.lock); + + g_mutex_clear (&info.lock); + g_cond_clear (&info.cond); +} + +static void +_reset_gl (GtkGstGLWidget * gst_widget) +{ + const GstGLFuncs *gl = gst_widget->priv->other_context->gl_vtable; + + if (!gst_widget->priv->gdk_context) + gst_widget->priv->gdk_context = + gtk_gl_area_get_context (GTK_GL_AREA (gst_widget)); + if (gst_widget->priv->gdk_context == NULL) + return; + + gdk_gl_context_make_current (gst_widget->priv->gdk_context); + gst_gl_context_activate (gst_widget->priv->other_context, TRUE); + + if (gst_widget->priv->vao) { + gl->DeleteVertexArrays (1, &gst_widget->priv->vao); + gst_widget->priv->vao = 0; + } + + if (gst_widget->priv->vertex_buffer) { + gl->DeleteBuffers (1, &gst_widget->priv->vertex_buffer); + gst_widget->priv->vertex_buffer = 0; + } + + if (gst_widget->priv->upload) { + gst_object_unref (gst_widget->priv->upload); + gst_widget->priv->upload = NULL; + } + + if (gst_widget->priv->shader) { + gst_object_unref (gst_widget->priv->shader); + gst_widget->priv->shader = NULL; + } + + gst_gl_context_activate (gst_widget->priv->other_context, FALSE); + + gst_object_unref (gst_widget->priv->other_context); + gst_widget->priv->other_context = NULL; + + gdk_gl_context_clear_current (); + + g_object_unref (gst_widget->priv->gdk_context); + gst_widget->priv->gdk_context = NULL; +} + +static void +_reset (GtkGstGLWidget * gst_widget) +{ + gst_buffer_replace (&gst_widget->priv->buffer, NULL); + + gst_caps_replace (&gst_widget->priv->caps, NULL); + gst_caps_replace (&gst_widget->priv->gl_caps, NULL); + + gst_widget->priv->negotiated = FALSE; + gst_widget->priv->initted = FALSE; + gst_widget->priv->vao = 0; + gst_widget->priv->vertex_buffer = 0; + gst_widget->priv->attr_position = 0; + gst_widget->priv->attr_texture = 0; + gst_widget->priv->current_tex = 0; + gst_widget->priv->new_buffer = TRUE; +} + +static void +gtk_gst_gl_widget_finalize (GObject * object) +{ + GtkGstGLWidget *widget = GTK_GST_GL_WIDGET_CAST (object); + + g_mutex_clear (&widget->priv->lock); + + _reset (widget); + + if (widget->priv->other_context) { + _invoke_on_main ((ThreadFunc) _reset_gl, widget); + } + + if (widget->priv->context) { + gst_object_unref (widget->priv->context); + widget->priv->context = NULL; + } + + if (widget->priv->display) { + gst_object_unref (widget->priv->display); + widget->priv->display = NULL; + } + + G_OBJECT_CLASS (gtk_gst_gl_widget_parent_class)->finalize (object); +} + +static void +gtk_gst_gl_widget_class_init (GtkGstGLWidgetClass * klass) +{ + GtkWidgetClass *widget_klass = (GtkWidgetClass *) klass; + GtkGLAreaClass *gl_widget_klass = (GtkGLAreaClass *) klass; + + g_type_class_add_private (klass, sizeof (GtkGstGLWidgetPrivate)); + + gl_widget_klass->render = gtk_gst_gl_widget_render; + widget_klass->get_preferred_width = gtk_gst_gl_widget_get_preferred_width; + widget_klass->get_preferred_height = gtk_gst_gl_widget_get_preferred_height; + + G_OBJECT_CLASS (klass)->finalize = gtk_gst_gl_widget_finalize; +} + +static void +gtk_gst_gl_widget_init (GtkGstGLWidget * widget) +{ + GdkDisplay *display; + + widget->priv = GTK_GST_GL_WIDGET_GET_PRIVATE (widget); + + g_mutex_init (&widget->priv->lock); + + display = gdk_display_get_default (); + +#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11) + if (GDK_IS_X11_DISPLAY (display)) + widget->priv->display = (GstGLDisplay *) + gst_gl_display_x11_new_with_display (gdk_x11_display_get_xdisplay + (display)); +#endif + + if (!widget->priv->display) + widget->priv->display = gst_gl_display_new (); + + gtk_gl_area_set_has_alpha ((GtkGLArea *) widget, TRUE); +} + +GtkWidget * +gtk_gst_gl_widget_new (void) +{ + return (GtkWidget *) g_object_new (GTK_TYPE_GST_GL_WIDGET, NULL); +} + +static gboolean +_queue_draw (GtkGstGLWidget * widget) +{ + gtk_widget_queue_draw (GTK_WIDGET (widget)); + + return G_SOURCE_REMOVE; +} + +void +gtk_gst_gl_widget_set_buffer (GtkGstGLWidget * widget, GstBuffer * buffer) +{ + GMainContext *main_context = g_main_context_default (); + + g_return_if_fail (GTK_IS_GST_GL_WIDGET (widget)); + g_return_if_fail (widget->priv->negotiated); + + g_mutex_lock (&widget->priv->lock); + + gst_buffer_replace (&widget->priv->buffer, buffer); + widget->priv->new_buffer = TRUE; + + g_mutex_unlock (&widget->priv->lock); + + g_main_context_invoke (main_context, (GSourceFunc) _queue_draw, widget); +} + +static void +_get_gl_context (GtkGstGLWidget * gst_widget) +{ + GstGLPlatform platform; + GstGLAPI gl_api; + guintptr gl_handle; + + gtk_widget_realize (GTK_WIDGET (gst_widget)); + + if (gst_widget->priv->gdk_context) + g_object_unref (gst_widget->priv->gdk_context); + gst_widget->priv->gdk_context = + gtk_gl_area_get_context (GTK_GL_AREA (gst_widget)); + if (gst_widget->priv->gdk_context == NULL) { + g_assert_not_reached (); + return; + } + + g_object_ref (gst_widget->priv->gdk_context); + + gdk_gl_context_make_current (gst_widget->priv->gdk_context); + +#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11) + if (GST_IS_GL_DISPLAY_X11 (gst_widget->priv->display)) { + platform = GST_GL_PLATFORM_GLX; + gl_api = gst_gl_context_get_current_gl_api (NULL, NULL); + gl_handle = gst_gl_context_get_current_gl_context (platform); + if (gl_handle) + gst_widget->priv->other_context = + gst_gl_context_new_wrapped (gst_widget->priv->display, gl_handle, + platform, gl_api); + } +#endif + + if (gst_widget->priv->other_context) { + GError *error = NULL; + + gst_gl_context_activate (gst_widget->priv->other_context, TRUE); + if (!gst_gl_context_fill_info (gst_widget->priv->other_context, &error)) { + GST_ERROR ("failed to retreive gdk context info: %s", error->message); + g_object_unref (gst_widget->priv->other_context); + gst_widget->priv->other_context = NULL; + } else { + gst_gl_context_activate (gst_widget->priv->other_context, FALSE); + } + } +} + +static gboolean +_queue_resize (GtkGstGLWidget * widget) +{ + gtk_widget_queue_resize (GTK_WIDGET (widget)); + + return G_SOURCE_REMOVE; +} + +gboolean +gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * widget) +{ + g_return_val_if_fail (GTK_IS_GST_GL_WIDGET (widget), FALSE); + + g_mutex_lock (&widget->priv->lock); + + if (widget->priv->display && widget->priv->gdk_context + && widget->priv->other_context) { + g_mutex_unlock (&widget->priv->lock); + return TRUE; + } + + if (!widget->priv->other_context) { + _invoke_on_main ((ThreadFunc) _get_gl_context, widget); + } + + if (!GST_GL_IS_CONTEXT (widget->priv->other_context)) { + g_mutex_unlock (&widget->priv->lock); + return FALSE; + } + + widget->priv->context = gst_gl_context_new (widget->priv->display); + + if (!widget->priv->context) { + g_mutex_unlock (&widget->priv->lock); + return FALSE; + } + + gst_gl_context_create (widget->priv->context, widget->priv->other_context, + NULL); + + g_mutex_unlock (&widget->priv->lock); + return TRUE; +} + +gboolean +gtk_gst_gl_widget_set_caps (GtkGstGLWidget * widget, GstCaps * caps) +{ + GMainContext *main_context = g_main_context_default (); + GstVideoInfo v_info; + + g_return_val_if_fail (GTK_IS_GST_GL_WIDGET (widget), FALSE); + g_return_val_if_fail (GST_IS_CAPS (caps), FALSE); + g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE); + + if (widget->priv->caps && gst_caps_is_equal_fixed (widget->priv->caps, caps)) + return TRUE; + + if (!gst_video_info_from_caps (&v_info, caps)) + return FALSE; + + g_mutex_lock (&widget->priv->lock); + + _reset (widget); + + gst_caps_replace (&widget->priv->caps, caps); + + widget->priv->gl_caps = gst_video_info_to_caps (&v_info); + gst_caps_set_features (widget->priv->gl_caps, 0, + gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY)); + + widget->priv->v_info = v_info; + widget->priv->negotiated = TRUE; + + g_mutex_unlock (&widget->priv->lock); + + g_main_context_invoke (main_context, (GSourceFunc) _queue_resize, widget); + + return TRUE; +} + +GstGLContext * +gtk_gst_gl_widget_get_gtk_context (GtkGstGLWidget * gst_widget) +{ + if (!gst_widget->priv->other_context) + return NULL; + + return gst_object_ref (gst_widget->priv->other_context); +} + +GstGLContext * +gtk_gst_gl_widget_get_context (GtkGstGLWidget * gst_widget) +{ + if (!gst_widget->priv->context) + return NULL; + + return gst_object_ref (gst_widget->priv->context); +} + +GstGLDisplay * +gtk_gst_gl_widget_get_display (GtkGstGLWidget * gst_widget) +{ + if (!gst_widget->priv->display) + return NULL; + + return gst_object_ref (gst_widget->priv->display); +} diff --git a/ext/gtk/gtkgstglwidget.h b/ext/gtk/gtkgstglwidget.h new file mode 100644 index 0000000000..923b5f3dc3 --- /dev/null +++ b/ext/gtk/gtkgstglwidget.h @@ -0,0 +1,77 @@ +/* + * GStreamer + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GTK_GST_GL_WIDGET_H__ +#define __GTK_GST_GL_WIDGET_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +GType gtk_gst_gl_widget_get_type (void); +#define GTK_TYPE_GST_GL_WIDGET (gtk_gst_gl_widget_get_type()) +#define GTK_GST_GL_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GTK_TYPE_GST_GL_WIDGET,GtkGstGLWidget)) +#define GTK_GST_GL_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GTK_TYPE_GST_GL_WIDGET,GtkGstGLWidgetClass)) +#define GTK_IS_GST_GL_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GTK_TYPE_GST_GL_WIDGET)) +#define GTK_IS_GST_GL_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GTK_TYPE_GST_GL_WIDGET)) +#define GTK_GST_GL_WIDGET_CAST(obj) ((GtkGstGLWidget*)(obj)) + +typedef struct _GtkGstGLWidget GtkGstGLWidget; +typedef struct _GtkGstGLWidgetClass GtkGstGLWidgetClass; +typedef struct _GtkGstGLWidgetPrivate GtkGstGLWidgetPrivate; + +/** + * GtkGstGLWidget: + * + * Opaque #GtkGstGLWidget object + */ +struct _GtkGstGLWidget +{ + /* */ + GtkGLArea parent; + + GtkGstGLWidgetPrivate *priv; +}; + +/** + * GtkGstGLWidgetClass: + * + * The #GtkGstGLWidgetClass struct only contains private data + */ +struct _GtkGstGLWidgetClass +{ + /* */ + GtkGLAreaClass object_class; +}; + +GtkWidget * gtk_gst_gl_widget_new (void); + +gboolean gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * widget); +gboolean gtk_gst_gl_widget_set_caps (GtkGstGLWidget * widget, GstCaps *caps); +void gtk_gst_gl_widget_set_buffer (GtkGstGLWidget * widget, GstBuffer *buffer); +GstGLDisplay * gtk_gst_gl_widget_get_display (GtkGstGLWidget * widget); +GstGLContext * gtk_gst_gl_widget_get_context (GtkGstGLWidget * widget); +GstGLContext * gtk_gst_gl_widget_get_gtk_context (GtkGstGLWidget * widget); + +G_END_DECLS + +#endif /* __GTK_GST_GL_WIDGET_H__ */ diff --git a/ext/gtk/gtkgstwidget.c b/ext/gtk/gtkgstwidget.c new file mode 100644 index 0000000000..c103df7275 --- /dev/null +++ b/ext/gtk/gtkgstwidget.c @@ -0,0 +1,240 @@ +/* + * GStreamer + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "gtkgstwidget.h" +#include + +/** + * SECTION:gtkgstwidget + * @short_description: a #GtkWidget that renders GStreamer video #GstBuffers + * @see_also: #GtkDrawingArea, #GstBuffer + * + * #GtkGstWidget is an #GtkWidget that renders GStreamer video buffers. + */ + +G_DEFINE_TYPE (GtkGstWidget, gtk_gst_widget, GTK_TYPE_DRAWING_AREA); + +#define GTK_GST_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + GTK_TYPE_GST_WIDGET, GtkGstWidgetPrivate)) + +struct _GtkGstWidgetPrivate +{ + GMutex lock; + + gboolean negotiated; + GstBuffer *buffer; + GstCaps *caps; + GstVideoInfo v_info; +}; + +static void +gtk_gst_widget_get_preferred_width (GtkWidget * widget, gint * min, + gint * natural) +{ + GtkGstWidget *gst_widget = (GtkGstWidget *) widget; + gint video_width = GST_VIDEO_INFO_WIDTH (&gst_widget->priv->v_info); + + if (!gst_widget->priv->negotiated) + video_width = 10; + + if (min) + *min = 1; + if (natural) + *natural = video_width; +} + +static void +gtk_gst_widget_get_preferred_height (GtkWidget * widget, gint * min, + gint * natural) +{ + GtkGstWidget *gst_widget = (GtkGstWidget *) widget; + gint video_height = GST_VIDEO_INFO_HEIGHT (&gst_widget->priv->v_info); + + if (!gst_widget->priv->negotiated) + video_height = 10; + + if (min) + *min = 1; + if (natural) + *natural = video_height; +} + +static gboolean +gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) +{ + GtkGstWidget *gst_widget = (GtkGstWidget *) widget; + guint widget_width, widget_height; + cairo_surface_t *surface; + GstVideoFrame frame; + + widget_width = gtk_widget_get_allocated_width (widget); + widget_height = gtk_widget_get_allocated_height (widget); + + g_mutex_lock (&gst_widget->priv->lock); + + /* failed to map the video frame */ + if (gst_widget->priv->negotiated && gst_widget->priv->buffer + && gst_video_frame_map (&frame, &gst_widget->priv->v_info, + gst_widget->priv->buffer, GST_MAP_READ)) { + gdouble scale_x = + (gdouble) widget_width / GST_VIDEO_INFO_WIDTH (&frame.info); + gdouble scale_y = + (gdouble) widget_height / GST_VIDEO_INFO_HEIGHT (&frame.info); + + gst_widget->priv->v_info = frame.info; + + surface = cairo_image_surface_create_for_data (frame.data[0], + CAIRO_FORMAT_ARGB32, frame.info.width, frame.info.height, + frame.info.stride[0]); + + cairo_scale (cr, scale_x, scale_y); + cairo_rectangle (cr, 0, 0, widget_width, widget_height); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + + cairo_surface_destroy (surface); + + gst_video_frame_unmap (&frame); + } else { + GdkRGBA color; + + gtk_style_context_get_color (gtk_widget_get_style_context (widget), 0, + &color); + gdk_cairo_set_source_rgba (cr, &color); + cairo_rectangle (cr, 0, 0, widget_width, widget_height); + cairo_fill (cr); + } + + g_mutex_unlock (&gst_widget->priv->lock); + return FALSE; +} + +static void +gtk_gst_widget_finalize (GObject * object) +{ + GtkGstWidget *widget = GTK_GST_WIDGET_CAST (object); + + gst_buffer_replace (&widget->priv->buffer, NULL); + g_mutex_clear (&widget->priv->lock); + + G_OBJECT_CLASS (gtk_gst_widget_parent_class)->finalize (object); +} + +static void +gtk_gst_widget_class_init (GtkGstWidgetClass * klass) +{ + GtkWidgetClass *widget_klass = (GtkWidgetClass *) klass; + + g_type_class_add_private (klass, sizeof (GtkGstWidgetPrivate)); + + widget_klass->draw = gtk_gst_widget_draw; + widget_klass->get_preferred_width = gtk_gst_widget_get_preferred_width; + widget_klass->get_preferred_height = gtk_gst_widget_get_preferred_height; + + G_OBJECT_CLASS (klass)->finalize = gtk_gst_widget_finalize; +} + +static void +gtk_gst_widget_init (GtkGstWidget * widget) +{ + widget->priv = GTK_GST_WIDGET_GET_PRIVATE (widget); + + g_mutex_init (&widget->priv->lock); +} + +GtkWidget * +gtk_gst_widget_new (void) +{ + return (GtkWidget *) g_object_new (GTK_TYPE_GST_WIDGET, NULL); +} + +static gboolean +_queue_draw (GtkGstWidget * widget) +{ + gtk_widget_queue_draw (GTK_WIDGET (widget)); + + return G_SOURCE_REMOVE; +} + +void +gtk_gst_widget_set_buffer (GtkGstWidget * widget, GstBuffer * buffer) +{ + GMainContext *main_context = g_main_context_default (); + + g_return_if_fail (GTK_IS_GST_WIDGET (widget)); + g_return_if_fail (widget->priv->negotiated); + + g_mutex_lock (&widget->priv->lock); + + gst_buffer_replace (&widget->priv->buffer, buffer); + + g_mutex_unlock (&widget->priv->lock); + + g_main_context_invoke (main_context, (GSourceFunc) _queue_draw, widget); +} + +static gboolean +_queue_resize (GtkGstWidget * widget) +{ + gtk_widget_queue_resize (GTK_WIDGET (widget)); + + return G_SOURCE_REMOVE; +} + +gboolean +gtk_gst_widget_set_caps (GtkGstWidget * widget, GstCaps * caps) +{ + GMainContext *main_context = g_main_context_default (); + GstVideoInfo v_info; + + g_return_val_if_fail (GTK_IS_GST_WIDGET (widget), FALSE); + g_return_val_if_fail (GST_IS_CAPS (caps), FALSE); + g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE); + + if (widget->priv->caps && gst_caps_is_equal_fixed (widget->priv->caps, caps)) + return TRUE; + + if (!gst_video_info_from_caps (&v_info, caps)) + return FALSE; + + /* FIXME: support other formats */ + g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&v_info) == + GST_VIDEO_FORMAT_BGRA, FALSE); + + g_mutex_lock (&widget->priv->lock); + + gst_caps_replace (&widget->priv->caps, caps); + widget->priv->v_info = v_info; + widget->priv->negotiated = TRUE; + + g_mutex_unlock (&widget->priv->lock); + + gtk_widget_queue_resize (GTK_WIDGET (widget)); + + g_main_context_invoke (main_context, (GSourceFunc) _queue_resize, widget); + + return TRUE; +} diff --git a/ext/gtk/gtkgstwidget.h b/ext/gtk/gtkgstwidget.h new file mode 100644 index 0000000000..29adafffa2 --- /dev/null +++ b/ext/gtk/gtkgstwidget.h @@ -0,0 +1,72 @@ +/* + * GStreamer + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GTK_GST_WIDGET_H__ +#define __GTK_GST_WIDGET_H__ + +#include +#include + +G_BEGIN_DECLS + +GType gtk_gst_widget_get_type (void); +#define GTK_TYPE_GST_WIDGET (gtk_gst_widget_get_type()) +#define GTK_GST_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GTK_TYPE_GST_WIDGET,GtkGstWidget)) +#define GTK_GST_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GTK_TYPE_GST_WIDGET,GtkGstWidgetClass)) +#define GTK_IS_GST_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GTK_TYPE_GST_WIDGET)) +#define GST_IS_GST_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GTK_TYPE_GST_WIDGET)) +#define GTK_GST_WIDGET_CAST(obj) ((GtkGstWidget*)(obj)) + +typedef struct _GtkGstWidget GtkGstWidget; +typedef struct _GtkGstWidgetClass GtkGstWidgetClass; +typedef struct _GtkGstWidgetPrivate GtkGstWidgetPrivate; + +/** + * GtkGstWidget: + * + * Opaque #GtkGstWidget object + */ +struct _GtkGstWidget +{ + /* */ + GtkDrawingArea parent; + + GtkGstWidgetPrivate *priv; +}; + +/** + * GtkGstWidgetClass: + * + * The #GtkGstWidgetClass struct only contains private data + */ +struct _GtkGstWidgetClass +{ + /* */ + GtkDrawingAreaClass object_class; +}; + +GtkWidget * gtk_gst_widget_new (void); + +gboolean gtk_gst_widget_set_caps (GtkGstWidget * widget, GstCaps *caps); +void gtk_gst_widget_set_buffer (GtkGstWidget * widget, GstBuffer *buffer); + +G_END_DECLS + +#endif /* __GTK_GST_WIDGET_H__ */ diff --git a/tests/examples/gtk/Makefile.am b/tests/examples/gtk/Makefile.am new file mode 100644 index 0000000000..77afab5008 --- /dev/null +++ b/tests/examples/gtk/Makefile.am @@ -0,0 +1,22 @@ + +noinst_PROGRAMS = gtksink + +gtksink_SOURCES = gtksink.c +gtksink_CFLAGS = $(GTK3_CFLAGS) \ + $(GST_CFLAGS) +gtksink_LDADD = $(GTK3_LIBS) \ + $(GST_LIBS) + +if USE_GTK3_GL +if USE_GL +noinst_PROGRAMS += gtkglsink + +gtkglsink_SOURCES = gtkglsink.c +gtkglsink_CFLAGS = $(GTK3_CFLAGS) \ + $(GST_CFLAGS) \ + $(GL_CFLAGS) +gtkglsink_LDADD = $(GTK3_LIBS) \ + $(GST_LIBS) \ + $(GL_LIBS) +endif +endif diff --git a/tests/examples/gtk/gtkglsink.c b/tests/examples/gtk/gtkglsink.c new file mode 100644 index 0000000000..72c867f23b --- /dev/null +++ b/tests/examples/gtk/gtkglsink.c @@ -0,0 +1,201 @@ +/* + * GStreamer + * Copyright (C) 2014 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include + +#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11) +#include +#endif + +static void +button_state_null_cb (GtkWidget * widget, GstElement * pipeline) +{ + gst_element_set_state (pipeline, GST_STATE_NULL); + g_print ("GST_STATE_NULL\n"); +} + +static void +button_state_ready_cb (GtkWidget * widget, GstElement * pipeline) +{ + gst_element_set_state (pipeline, GST_STATE_READY); + g_print ("GST_STATE_READY\n"); +} + +static void +button_state_paused_cb (GtkWidget * widget, GstElement * pipeline) +{ + gst_element_set_state (pipeline, GST_STATE_PAUSED); + g_print ("GST_STATE_PAUSED\n"); +} + +static void +button_state_playing_cb (GtkWidget * widget, GstElement * pipeline) +{ + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_print ("GST_STATE_PLAYING\n"); +} + +static void +end_stream_cb (GstBus * bus, GstMessage * message, GstElement * pipeline) +{ + g_print ("End of stream\n"); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + + gtk_main_quit (); +} + +static void +destroy_cb (GtkWidget * widget, GdkEvent * event, GstElement * pipeline) +{ + g_print ("Close\n"); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + + gtk_main_quit (); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *window, *window_control; + GtkWidget *button_state_null, *button_state_ready; + GtkWidget *button_state_paused, *button_state_playing; + GtkWidget *grid, *area; + GstElement *pipeline; + GstElement *videosrc, *upload, *effect, *videosink; + GstStateChangeReturn ret; + GstCaps *caps; + GstBus *bus; + +#if GST_GL_HAVE_WINDOW_X11 && defined(GDK_WINDOWING_X11) + XInitThreads (); +#endif + + gst_init (&argc, &argv); + gtk_init (&argc, &argv); + + pipeline = gst_pipeline_new ("pipeline"); + + //window that contains an area where the video is drawn + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (window), 640, 480); + gtk_window_move (GTK_WINDOW (window), 300, 10); + gtk_window_set_title (GTK_WINDOW (window), "gtkgstwidget"); + + //window to control the states + window_control = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_resizable (GTK_WINDOW (window_control), FALSE); + gtk_window_move (GTK_WINDOW (window_control), 10, 10); + grid = gtk_grid_new (); + gtk_container_add (GTK_CONTAINER (window_control), grid); + + //control state null + button_state_null = gtk_button_new_with_label ("GST_STATE_NULL"); + g_signal_connect (G_OBJECT (button_state_null), "clicked", + G_CALLBACK (button_state_null_cb), pipeline); + gtk_grid_attach (GTK_GRID (grid), button_state_null, 0, 1, 1, 1); + gtk_widget_show (button_state_null); + + //control state ready + button_state_ready = gtk_button_new_with_label ("GST_STATE_READY"); + g_signal_connect (G_OBJECT (button_state_ready), "clicked", + G_CALLBACK (button_state_ready_cb), pipeline); + gtk_grid_attach (GTK_GRID (grid), button_state_ready, 0, 2, 1, 1); + gtk_widget_show (button_state_ready); + + //control state paused + button_state_paused = gtk_button_new_with_label ("GST_STATE_PAUSED"); + g_signal_connect (G_OBJECT (button_state_paused), "clicked", + G_CALLBACK (button_state_paused_cb), pipeline); + gtk_grid_attach (GTK_GRID (grid), button_state_paused, 0, 3, 1, 1); + gtk_widget_show (button_state_paused); + + //control state playing + button_state_playing = gtk_button_new_with_label ("GST_STATE_PLAYING"); + g_signal_connect (G_OBJECT (button_state_playing), "clicked", + G_CALLBACK (button_state_playing_cb), pipeline); + gtk_grid_attach (GTK_GRID (grid), button_state_playing, 0, 4, 1, 1); + gtk_widget_show (button_state_playing); + + gtk_widget_show (grid); + gtk_widget_show (window_control); + + g_signal_connect (G_OBJECT (window), "delete-event", G_CALLBACK (destroy_cb), + pipeline); + + //configure the pipeline + videosrc = gst_element_factory_make ("videotestsrc", "videotestsrc"); + upload = gst_element_factory_make ("glupload", "glupload"); + effect = gst_element_factory_make ("glfiltercube", "glfiltercube"); + videosink = gst_element_factory_make ("gtkglsink", "gtksink"); + + g_object_get (videosink, "widget", &area, NULL); + gtk_container_add (GTK_CONTAINER (window), area); + + gtk_widget_realize (area); + + caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, 640, + "height", G_TYPE_INT, 480, "format", G_TYPE_STRING, "RGBA", + "framerate", GST_TYPE_FRACTION, 30, 1, NULL); + + gst_bin_add_many (GST_BIN (pipeline), videosrc, upload, effect, videosink, + NULL); + + if (!gst_element_link_filtered (videosrc, upload, caps)) { + gst_caps_unref (caps); + g_warning ("Failed to link videosrc to glfiltercube!\n"); + return -1; + } + gst_caps_unref (caps); + + if (!gst_element_link_many (upload, effect, videosink, NULL)) { + g_warning ("Failed to link videosrc to glfiltercube!\n"); + return -1; + } + //set window id on this event + bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); + g_signal_connect (bus, "message::error", G_CALLBACK (end_stream_cb), + pipeline); + g_signal_connect (bus, "message::warning", G_CALLBACK (end_stream_cb), + pipeline); + g_signal_connect (bus, "message::eos", G_CALLBACK (end_stream_cb), pipeline); + gst_object_unref (bus); + + //start + ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) { + g_print ("Failed to start up pipeline!\n"); + return -1; + } + + gtk_widget_show_all (window); + + gtk_main (); + + gst_deinit (); + + return 0; +} diff --git a/tests/examples/gtk/gtksink.c b/tests/examples/gtk/gtksink.c new file mode 100644 index 0000000000..0fea057922 --- /dev/null +++ b/tests/examples/gtk/gtksink.c @@ -0,0 +1,184 @@ +/* + * GStreamer + * Copyright (C) 2014 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +static void +button_state_null_cb (GtkWidget * widget, GstElement * pipeline) +{ + gst_element_set_state (pipeline, GST_STATE_NULL); + g_print ("GST_STATE_NULL\n"); +} + +static void +button_state_ready_cb (GtkWidget * widget, GstElement * pipeline) +{ + gst_element_set_state (pipeline, GST_STATE_READY); + g_print ("GST_STATE_READY\n"); +} + +static void +button_state_paused_cb (GtkWidget * widget, GstElement * pipeline) +{ + gst_element_set_state (pipeline, GST_STATE_PAUSED); + g_print ("GST_STATE_PAUSED\n"); +} + +static void +button_state_playing_cb (GtkWidget * widget, GstElement * pipeline) +{ + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_print ("GST_STATE_PLAYING\n"); +} + +static void +end_stream_cb (GstBus * bus, GstMessage * message, GstElement * pipeline) +{ + g_print ("End of stream\n"); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + + gtk_main_quit (); +} + +static void +destroy_cb (GtkWidget * widget, GdkEvent * event, GstElement * pipeline) +{ + g_print ("Close\n"); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + + gtk_main_quit (); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *window, *window_control; + GtkWidget *button_state_null, *button_state_ready; + GtkWidget *button_state_paused, *button_state_playing; + GtkWidget *grid, *area; + GstElement *pipeline; + GstElement *videosrc, *videosink; + GstStateChangeReturn ret; + GstCaps *caps; + GstBus *bus; + + gst_init (&argc, &argv); + gtk_init (&argc, &argv); + + pipeline = gst_pipeline_new ("pipeline"); + + //window that contains an area where the video is drawn + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (window), 640, 480); + gtk_window_move (GTK_WINDOW (window), 300, 10); + gtk_window_set_title (GTK_WINDOW (window), "gtkgstwidget"); + + //window to control the states + window_control = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_resizable (GTK_WINDOW (window_control), FALSE); + gtk_window_move (GTK_WINDOW (window_control), 10, 10); + grid = gtk_grid_new (); + gtk_container_add (GTK_CONTAINER (window_control), grid); + + //control state null + button_state_null = gtk_button_new_with_label ("GST_STATE_NULL"); + g_signal_connect (G_OBJECT (button_state_null), "clicked", + G_CALLBACK (button_state_null_cb), pipeline); + gtk_grid_attach (GTK_GRID (grid), button_state_null, 0, 1, 1, 1); + gtk_widget_show (button_state_null); + + //control state ready + button_state_ready = gtk_button_new_with_label ("GST_STATE_READY"); + g_signal_connect (G_OBJECT (button_state_ready), "clicked", + G_CALLBACK (button_state_ready_cb), pipeline); + gtk_grid_attach (GTK_GRID (grid), button_state_ready, 0, 2, 1, 1); + gtk_widget_show (button_state_ready); + + //control state paused + button_state_paused = gtk_button_new_with_label ("GST_STATE_PAUSED"); + g_signal_connect (G_OBJECT (button_state_paused), "clicked", + G_CALLBACK (button_state_paused_cb), pipeline); + gtk_grid_attach (GTK_GRID (grid), button_state_paused, 0, 3, 1, 1); + gtk_widget_show (button_state_paused); + + //control state playing + button_state_playing = gtk_button_new_with_label ("GST_STATE_PLAYING"); + g_signal_connect (G_OBJECT (button_state_playing), "clicked", + G_CALLBACK (button_state_playing_cb), pipeline); + gtk_grid_attach (GTK_GRID (grid), button_state_playing, 0, 4, 1, 1); + gtk_widget_show (button_state_playing); + + gtk_widget_show (grid); + gtk_widget_show (window_control); + + g_signal_connect (G_OBJECT (window), "delete-event", G_CALLBACK (destroy_cb), + pipeline); + + //configure the pipeline + videosrc = gst_element_factory_make ("videotestsrc", "videotestsrc"); + videosink = gst_element_factory_make ("gtksink", "gtksink"); + + g_object_get (videosink, "widget", &area, NULL); + gtk_container_add (GTK_CONTAINER (window), area); + + gtk_widget_realize (area); + + caps = gst_caps_new_simple ("video/x-raw", + "width", G_TYPE_INT, 640, + "height", G_TYPE_INT, 480, "format", G_TYPE_STRING, "BGRA", NULL); + + gst_bin_add_many (GST_BIN (pipeline), videosrc, videosink, NULL); + + if (!gst_element_link_filtered (videosrc, videosink, caps)) { + gst_caps_unref (caps); + g_warning ("Failed to link videosrc to glfiltercube!\n"); + return -1; + } + gst_caps_unref (caps); + + //set window id on this event + bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); + g_signal_connect (bus, "message::error", G_CALLBACK (end_stream_cb), + pipeline); + g_signal_connect (bus, "message::warning", G_CALLBACK (end_stream_cb), + pipeline); + g_signal_connect (bus, "message::eos", G_CALLBACK (end_stream_cb), pipeline); + gst_object_unref (bus); + + //start + ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) { + g_print ("Failed to start up pipeline!\n"); + return -1; + } + + gtk_widget_show_all (window); + + gtk_main (); + + gst_deinit (); + + return 0; +} From fe5bf0cee16fc1133bc75e369bc26f106b943e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 11 Jun 2015 14:58:27 +0200 Subject: [PATCH 034/128] gtk: Add missing CFLAGS to example --- tests/examples/gtk/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/examples/gtk/Makefile.am b/tests/examples/gtk/Makefile.am index 77afab5008..945331d5f6 100644 --- a/tests/examples/gtk/Makefile.am +++ b/tests/examples/gtk/Makefile.am @@ -13,6 +13,8 @@ noinst_PROGRAMS += gtkglsink gtkglsink_SOURCES = gtkglsink.c gtkglsink_CFLAGS = $(GTK3_CFLAGS) \ + $(GST_PLUGINS_BAD_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_CFLAGS) \ $(GL_CFLAGS) gtkglsink_LDADD = $(GTK3_LIBS) \ From 4cef5787c8af5c5c9466d752b89184edcab8c1dd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 11 Jun 2015 15:02:44 +0200 Subject: [PATCH 035/128] gtk: Do not try to initialize display if we have not have a GLContext yet --- ext/gtk/gtkgstglwidget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index b5eb85d8c8..11c5b6f15a 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -210,7 +210,7 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) g_mutex_lock (&gst_widget->priv->lock); - if (!gst_widget->priv->initted) + if (!gst_widget->priv->initted && gst_widget->priv->context) gtk_gst_gl_widget_init_redisplay (gst_widget); if (gst_widget->priv->initted && gst_widget->priv->negotiated From 5c6050f8495204eee48b8a6b7e5bee3b9e420ab6 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 11 Jun 2015 12:10:23 -0400 Subject: [PATCH 036/128] gstgtk: Allow doing gst-inspect-1.0 on these elements This patch allow going gst-inspect-1.0 on these elements removing ugly crash that was previously occurring. The method consist of making the widget creation as lazy as possible. This way we don't endup doing gtk_init() before the application. We also ref_sink() the widget, so we don't crash if the parent widget is discarded, and cleanly error out with GL if the widget has no parent window, because calling gtk_widget_realized() can only be done if the widget has been parented to a window). --- ext/gtk/gstgtkglsink.c | 36 ++++++++++++++++++++++++++++++++++-- ext/gtk/gstgtksink.c | 27 +++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 1572f9707c..9ad195018b 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -120,7 +120,6 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) static void gst_gtk_gl_sink_init (GstGtkGLSink * gtk_sink) { - gtk_sink->widget = (GtkGstGLWidget *) gtk_gst_gl_widget_new (); } static void @@ -165,6 +164,28 @@ gst_gtk_gl_sink_finalize (GObject * object) G_OBJECT_CLASS (parent_class)->finalize (object); } +static GtkGstGLWidget * +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 lazylli, 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 = (GtkGstGLWidget *) gtk_gst_gl_widget_new (); + + /* 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); + + return gtk_sink->widget; +} + static void gst_gtk_gl_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) @@ -175,7 +196,7 @@ gst_gtk_gl_sink_get_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_WIDGET: - g_value_set_object (value, gtk_sink->widget); + g_value_set_object (value, gst_gtk_gl_sink_get_widget (gtk_sink)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -254,6 +275,17 @@ gst_gtk_gl_sink_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: + 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 */ + + if (!gtk_widget_get_parent (GTK_WIDGET (gtk_sink->widget))) { + GST_ERROR_OBJECT (gtk_sink, + "gtkglsink widget need to be parented to work."); + return GST_STATE_CHANGE_FAILURE; + } + if (!gtk_gst_gl_widget_init_winsys (gtk_sink->widget)) return GST_STATE_CHANGE_FAILURE; diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index e60d1bb6f1..b921ff02fe 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -117,7 +117,6 @@ gst_gtk_sink_class_init (GstGtkSinkClass * klass) static void gst_gtk_sink_init (GstGtkSink * gtk_sink) { - gtk_sink->widget = (GtkGstWidget *) gtk_gst_widget_new (); } static void @@ -141,6 +140,28 @@ gst_gtk_sink_finalize (GObject * object) G_OBJECT_CLASS (parent_class)->finalize (object); } +static GtkGstWidget * +gst_gtk_sink_get_widget (GstGtkSink * 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 lazylli, 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 = (GtkGstWidget *) gtk_gst_widget_new (); + + /* Take the floating ref, other wise the destruction of the container will + * make this widget disapear possibly before we are done. */ + gst_object_ref_sink (gtk_sink->widget); + + return gtk_sink->widget; +} + static void gst_gtk_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) @@ -151,7 +172,7 @@ gst_gtk_sink_get_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_WIDGET: - g_value_set_object (value, gtk_sink->widget); + g_value_set_object (value, gst_gtk_sink_get_widget (gtk_sink)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -191,6 +212,8 @@ gst_gtk_sink_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: + if (gst_gtk_sink_get_widget (gtk_sink) == NULL) + return GST_STATE_CHANGE_FAILURE; break; case GST_STATE_CHANGE_READY_TO_PAUSED: break; From bdbff3bc8e0ed0a348e61c90dfb971fa4868a1ab Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 11 Jun 2015 12:38:53 -0400 Subject: [PATCH 037/128] gstgtk: Don't leak the widget g_object_get() returns a ref, gtk_container_add() only ref_sink(). That mean we still need to unref afterward. This leak was hiding a reference bug previously present. --- tests/examples/gtk/gtkglsink.c | 1 + tests/examples/gtk/gtksink.c | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/examples/gtk/gtkglsink.c b/tests/examples/gtk/gtkglsink.c index 72c867f23b..62e512522b 100644 --- a/tests/examples/gtk/gtkglsink.c +++ b/tests/examples/gtk/gtkglsink.c @@ -156,6 +156,7 @@ main (int argc, char *argv[]) gtk_container_add (GTK_CONTAINER (window), area); gtk_widget_realize (area); + g_object_unref (area); caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, 640, "height", G_TYPE_INT, 480, "format", G_TYPE_STRING, "RGBA", diff --git a/tests/examples/gtk/gtksink.c b/tests/examples/gtk/gtksink.c index 0fea057922..d86fd090e5 100644 --- a/tests/examples/gtk/gtksink.c +++ b/tests/examples/gtk/gtksink.c @@ -142,6 +142,7 @@ main (int argc, char *argv[]) g_object_get (videosink, "widget", &area, NULL); gtk_container_add (GTK_CONTAINER (window), area); + g_object_unref (area); gtk_widget_realize (area); From b68f4784675e0695011eed03ee6be6dc2ba594df Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 11 Jun 2015 12:41:10 -0400 Subject: [PATCH 038/128] gstgtk: No need to realize the widget The widget already does that. --- tests/examples/gtk/gtkglsink.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/examples/gtk/gtkglsink.c b/tests/examples/gtk/gtkglsink.c index 62e512522b..4b71985b0f 100644 --- a/tests/examples/gtk/gtkglsink.c +++ b/tests/examples/gtk/gtkglsink.c @@ -154,8 +154,6 @@ main (int argc, char *argv[]) g_object_get (videosink, "widget", &area, NULL); gtk_container_add (GTK_CONTAINER (window), area); - - gtk_widget_realize (area); g_object_unref (area); caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, 640, From 7707894ee5a0d13123bea8fba770aa25e0daceef Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Fri, 12 Jun 2015 12:29:37 +1000 Subject: [PATCH 039/128] gtkglsink: reset the context/display in READY_TO_NULL Fixes context propagation in pipelines with upstream GL elements. --- ext/gtk/gstgtkglsink.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 9ad195018b..f278873b89 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -133,32 +133,11 @@ gst_gtk_gl_sink_set_property (GObject * object, guint prop_id, } } -static void -_reset (GstGtkGLSink * gtk_sink) -{ - 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; - } -} - static void gst_gtk_gl_sink_finalize (GObject * object) { GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (object);; - _reset (gtk_sink); - g_object_unref (gtk_sink->widget); G_OBJECT_CLASS (parent_class)->finalize (object); @@ -316,6 +295,20 @@ gst_gtk_gl_sink_change_state (GstElement * element, GstStateChange transition) gtk_gst_gl_widget_set_buffer (gtk_sink->widget, NULL); 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; @@ -354,8 +347,6 @@ gst_gtk_gl_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps); - _reset (gtk_sink); - if (!gst_video_info_from_caps (>k_sink->v_info, caps)) return FALSE; From b9ebc71cc8d40e3047af85223ab9c7cb98888ebc Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Fri, 12 Jun 2015 12:40:50 +1000 Subject: [PATCH 040/128] gtk: fix a couple of typos --- ext/gtk/gstgtkglsink.c | 6 +++--- ext/gtk/gstgtksink.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index f278873b89..c89c940eb4 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -94,7 +94,7 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) gobject_class->get_property = gst_gtk_gl_sink_get_property; gst_element_class_set_metadata (gstelement_class, "Gtk Video Sink", - "Sink/Video", "A video sink the renders to a GtkWidget", + "Sink/Video", "A video sink that renders to a GtkWidget", "Matthew Waters "); g_object_class_install_property (gobject_class, PROP_WIDGET, @@ -150,7 +150,7 @@ gst_gtk_gl_sink_get_widget (GstGtkGLSink * gtk_sink) return gtk_sink->widget; /* Ensure GTK is initialized, this has no side effect if it was already - * initialized. Also, we do that lazylli, so the application can be first */ + * 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; @@ -261,7 +261,7 @@ gst_gtk_gl_sink_change_state (GstElement * element, GstStateChange transition) if (!gtk_widget_get_parent (GTK_WIDGET (gtk_sink->widget))) { GST_ERROR_OBJECT (gtk_sink, - "gtkglsink widget need to be parented to work."); + "gtkglsink widget needs to be parented to work."); return GST_STATE_CHANGE_FAILURE; } diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index b921ff02fe..94b704775c 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -92,7 +92,7 @@ gst_gtk_sink_class_init (GstGtkSinkClass * klass) gobject_class->get_property = gst_gtk_sink_get_property; gst_element_class_set_metadata (gstelement_class, "Gtk Video Sink", - "Sink/Video", "A video sink the renders to a GtkWidget", + "Sink/Video", "A video sink that renders to a GtkWidget", "Matthew Waters "); g_object_class_install_property (gobject_class, PROP_WIDGET, @@ -147,7 +147,7 @@ gst_gtk_sink_get_widget (GstGtkSink * gtk_sink) return gtk_sink->widget; /* Ensure GTK is initialized, this has no side effect if it was already - * initialized. Also, we do that lazylli, so the application can be first */ + * 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; From a512a91598bba8cb3cb950c82563b4bea33d5b7a Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Fri, 12 Jun 2015 15:17:30 +1000 Subject: [PATCH 041/128] gtk: implement video aspect-ratio handling For both the software and the GL sink's. Doesn't deal with the pixel-aspect-ratio field at all yet. --- ext/gtk/gstgtkglsink.c | 48 ++++++++++++++++------ ext/gtk/gstgtkglsink.h | 4 ++ ext/gtk/gstgtksink.c | 51 ++++++++++++++++-------- ext/gtk/gstgtksink.h | 4 ++ ext/gtk/gtkgstglwidget.c | 84 ++++++++++++++++++++++++++++++++++++++- ext/gtk/gtkgstwidget.c | 86 ++++++++++++++++++++++++++++++++++++++-- 6 files changed, 243 insertions(+), 34 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index c89c940eb4..372846f0e7 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -32,6 +32,8 @@ GST_DEBUG_CATEGORY (gst_debug_gtk_gl_sink); #define GST_CAT_DEFAULT gst_debug_gtk_gl_sink +#define DEFAULT_FORCE_ASPECT_RATIO 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); @@ -62,8 +64,9 @@ GST_STATIC_PAD_TEMPLATE ("sink", enum { - ARG_0, - PROP_WIDGET + PROP_0, + PROP_WIDGET, + PROP_FORCE_ASPECT_RATIO, }; enum @@ -102,6 +105,13 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) "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)); + gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&gst_gtk_gl_sink_template)); @@ -120,17 +130,7 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) static void gst_gtk_gl_sink_init (GstGtkGLSink * gtk_sink) { -} - -static void -gst_gtk_gl_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + gtk_sink->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; } static void @@ -157,6 +157,9 @@ gst_gtk_gl_sink_get_widget (GstGtkGLSink * gtk_sink) } gtk_sink->widget = (GtkGstGLWidget *) gtk_gst_gl_widget_new (); + gtk_sink->bind_aspect_ratio = + g_object_bind_property (gtk_sink, "force-aspect-ratio", gtk_sink->widget, + "force-aspect-ratio", G_BINDING_BIDIRECTIONAL); /* Take the floating ref, otherwise the destruction of the container will * make this widget disapear possibly before we are done. */ @@ -177,6 +180,25 @@ gst_gtk_gl_sink_get_property (GObject * object, guint 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; + 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; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/ext/gtk/gstgtkglsink.h b/ext/gtk/gstgtkglsink.h index 1457260584..4c13059f5f 100644 --- a/ext/gtk/gstgtkglsink.h +++ b/ext/gtk/gstgtkglsink.h @@ -65,6 +65,10 @@ struct _GstGtkGLSink GstGLUpload *upload; GstBuffer *uploaded_buffer; + /* properties */ + gboolean force_aspect_ratio; + GBinding *bind_aspect_ratio; + GstGtkGLSinkPrivate *priv; }; diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index 94b704775c..1b349561c4 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -58,10 +58,13 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("BGRA")) ); +#define DEFAULT_FORCE_ASPECT_RATIO TRUE + enum { - ARG_0, - PROP_WIDGET + PROP_0, + PROP_WIDGET, + PROP_FORCE_ASPECT_RATIO, }; enum @@ -100,6 +103,13 @@ gst_gtk_sink_class_init (GstGtkSinkClass * klass) "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)); + gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&gst_gtk_sink_template)); @@ -119,17 +129,6 @@ gst_gtk_sink_init (GstGtkSink * gtk_sink) { } -static void -gst_gtk_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - static void gst_gtk_sink_finalize (GObject * object) { @@ -154,6 +153,9 @@ gst_gtk_sink_get_widget (GstGtkSink * gtk_sink) } gtk_sink->widget = (GtkGstWidget *) gtk_gst_widget_new (); + gtk_sink->bind_aspect_ratio = + g_object_bind_property (gtk_sink, "force-aspect-ratio", gtk_sink->widget, + "force-aspect-ratio", G_BINDING_BIDIRECTIONAL); /* Take the floating ref, other wise the destruction of the container will * make this widget disapear possibly before we are done. */ @@ -166,14 +168,31 @@ static void gst_gtk_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstGtkSink *gtk_sink; - - gtk_sink = GST_GTK_SINK (object); + GstGtkSink *gtk_sink = GST_GTK_SINK (object); switch (prop_id) { case PROP_WIDGET: g_value_set_object (value, gst_gtk_sink_get_widget (gtk_sink)); break; + case PROP_FORCE_ASPECT_RATIO: + g_value_set_boolean (value, gtk_sink->force_aspect_ratio); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_gtk_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstGtkSink *gtk_sink = GST_GTK_SINK (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + gtk_sink->force_aspect_ratio = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/ext/gtk/gstgtksink.h b/ext/gtk/gstgtksink.h index e8cdf48a53..444c4b1980 100644 --- a/ext/gtk/gstgtksink.h +++ b/ext/gtk/gstgtksink.h @@ -56,6 +56,10 @@ struct _GstGtkSink GtkGstWidget *widget; + /* properties */ + gboolean force_aspect_ratio; + GBinding *bind_aspect_ratio; + GstGtkSinkPrivate *priv; }; diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 11c5b6f15a..100fa1d072 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -51,10 +51,21 @@ G_DEFINE_TYPE_WITH_CODE (GtkGstGLWidget, gtk_gst_gl_widget, GTK_TYPE_GL_AREA, #define GTK_GST_GL_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ GTK_TYPE_GST_GL_WIDGET, GtkGstGLWidgetPrivate)) +#define DEFAULT_FORCE_ASPECT_RATIO TRUE + +enum +{ + PROP_0, + PROP_FORCE_ASPECT_RATIO, +}; + struct _GtkGstGLWidgetPrivate { GMutex lock; + /* properties */ + gboolean force_aspect_ratio; + gboolean negotiated; GstBuffer *buffer; GstCaps *gl_caps; @@ -182,6 +193,30 @@ _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) const GstGLFuncs *gl = gst_widget->priv->context->gl_vtable; GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; + if (gst_widget->priv->force_aspect_ratio) { + GstVideoRectangle src, dst, result; + gint gtk_viewport[4]; + + gl->ClearColor (0.0, 0.0, 0.0, 0.0); + gl->Clear (GL_COLOR_BUFFER_BIT); + + gl->GetIntegerv (GL_VIEWPORT, gtk_viewport); + + src.x = 0; + src.y = 0; + src.w = GST_VIDEO_INFO_WIDTH (&gst_widget->priv->v_info); + src.h = GST_VIDEO_INFO_HEIGHT (&gst_widget->priv->v_info); + + dst.x = gtk_viewport[0]; + dst.y = gtk_viewport[1]; + dst.w = gtk_viewport[2]; + dst.h = gtk_viewport[3]; + + gst_video_sink_center_rect (src, dst, &result, TRUE); + + gl->Viewport (result.x, result.y, result.w, result.h); + } + gst_gl_shader_use (gst_widget->priv->shader); if (gl->BindVertexArray) @@ -390,19 +425,62 @@ gtk_gst_gl_widget_finalize (GObject * object) G_OBJECT_CLASS (gtk_gst_gl_widget_parent_class)->finalize (object); } +static void +gtk_gst_gl_widget_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GtkGstGLWidget *gtk_widget = GTK_GST_GL_WIDGET (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + gtk_widget->priv->force_aspect_ratio = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_gst_gl_widget_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GtkGstGLWidget *gtk_widget = GTK_GST_GL_WIDGET (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + g_value_set_boolean (value, gtk_widget->priv->force_aspect_ratio); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void gtk_gst_gl_widget_class_init (GtkGstGLWidgetClass * klass) { + GObjectClass *gobject_klass = (GObjectClass *) klass; GtkWidgetClass *widget_klass = (GtkWidgetClass *) klass; GtkGLAreaClass *gl_widget_klass = (GtkGLAreaClass *) klass; g_type_class_add_private (klass, sizeof (GtkGstGLWidgetPrivate)); + gobject_klass->set_property = gtk_gst_gl_widget_set_property; + gobject_klass->get_property = gtk_gst_gl_widget_get_property; + gobject_klass->finalize = gtk_gst_gl_widget_finalize; + + g_object_class_install_property (gobject_klass, 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)); + gl_widget_klass->render = gtk_gst_gl_widget_render; + widget_klass->get_preferred_width = gtk_gst_gl_widget_get_preferred_width; widget_klass->get_preferred_height = gtk_gst_gl_widget_get_preferred_height; - - G_OBJECT_CLASS (klass)->finalize = gtk_gst_gl_widget_finalize; } static void @@ -412,6 +490,8 @@ gtk_gst_gl_widget_init (GtkGstGLWidget * widget) widget->priv = GTK_GST_GL_WIDGET_GET_PRIVATE (widget); + widget->priv->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; + g_mutex_init (&widget->priv->lock); display = gdk_display_get_default (); diff --git a/ext/gtk/gtkgstwidget.c b/ext/gtk/gtkgstwidget.c index c103df7275..aa40f39391 100644 --- a/ext/gtk/gtkgstwidget.c +++ b/ext/gtk/gtkgstwidget.c @@ -40,10 +40,21 @@ G_DEFINE_TYPE (GtkGstWidget, gtk_gst_widget, GTK_TYPE_DRAWING_AREA); #define GTK_GST_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ GTK_TYPE_GST_WIDGET, GtkGstWidgetPrivate)) +#define DEFAULT_FORCE_ASPECT_RATIO TRUE + +enum +{ + PROP_0, + PROP_FORCE_ASPECT_RATIO, +}; + struct _GtkGstWidgetPrivate { GMutex lock; + /* properties */ + gboolean force_aspect_ratio; + gboolean negotiated; GstBuffer *buffer; GstCaps *caps; @@ -103,6 +114,7 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) (gdouble) widget_width / GST_VIDEO_INFO_WIDTH (&frame.info); gdouble scale_y = (gdouble) widget_height / GST_VIDEO_INFO_HEIGHT (&frame.info); + GstVideoRectangle result; gst_widget->priv->v_info = frame.info; @@ -110,8 +122,32 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) CAIRO_FORMAT_ARGB32, frame.info.width, frame.info.height, frame.info.stride[0]); + if (gst_widget->priv->force_aspect_ratio) { + GstVideoRectangle src, dst; + + src.x = 0; + src.y = 0; + src.w = GST_VIDEO_INFO_WIDTH (&frame.info); + src.h = GST_VIDEO_INFO_HEIGHT (&frame.info); + + dst.x = 0; + dst.y = 0; + dst.w = widget_width; + dst.h = widget_height; + + gst_video_sink_center_rect (src, dst, &result, TRUE); + + scale_x = scale_y = MIN (scale_x, scale_y); + } else { + result.x = 0; + result.y = 0; + result.w = widget_width; + result.h = widget_height; + } + + cairo_translate (cr, result.x, result.y); cairo_scale (cr, scale_x, scale_y); - cairo_rectangle (cr, 0, 0, widget_width, widget_height); + cairo_rectangle (cr, 0, 0, result.w, result.h); cairo_set_source_surface (cr, surface, 0, 0); cairo_paint (cr); @@ -143,18 +179,60 @@ gtk_gst_widget_finalize (GObject * object) G_OBJECT_CLASS (gtk_gst_widget_parent_class)->finalize (object); } +static void +gtk_gst_widget_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GtkGstWidget *gtk_widget = GTK_GST_WIDGET (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + gtk_widget->priv->force_aspect_ratio = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_gst_widget_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GtkGstWidget *gtk_widget = GTK_GST_WIDGET (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + g_value_set_boolean (value, gtk_widget->priv->force_aspect_ratio); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void gtk_gst_widget_class_init (GtkGstWidgetClass * klass) { + GObjectClass *gobject_klass = (GObjectClass *) klass; GtkWidgetClass *widget_klass = (GtkWidgetClass *) klass; g_type_class_add_private (klass, sizeof (GtkGstWidgetPrivate)); + gobject_klass->set_property = gtk_gst_widget_set_property; + gobject_klass->get_property = gtk_gst_widget_get_property; + gobject_klass->finalize = gtk_gst_widget_finalize; + + g_object_class_install_property (gobject_klass, 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)); + widget_klass->draw = gtk_gst_widget_draw; widget_klass->get_preferred_width = gtk_gst_widget_get_preferred_width; widget_klass->get_preferred_height = gtk_gst_widget_get_preferred_height; - - G_OBJECT_CLASS (klass)->finalize = gtk_gst_widget_finalize; } static void @@ -162,6 +240,8 @@ gtk_gst_widget_init (GtkGstWidget * widget) { widget->priv = GTK_GST_WIDGET_GET_PRIVATE (widget); + widget->priv->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; + g_mutex_init (&widget->priv->lock); } From baad74b99598eb175eebb94143b0c7a3d95fdb03 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Jun 2015 15:39:56 +0200 Subject: [PATCH 042/128] gtk: Do not try to activate a NULL GLContext At that point in the code nothing guarantees it exists --- ext/gtk/gtkgstglwidget.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 100fa1d072..dfe2c2faf8 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -284,7 +284,8 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) glClear (GL_COLOR_BUFFER_BIT); } - gst_gl_context_activate (gst_widget->priv->other_context, FALSE); + if (gst_widget->priv->other_context) + gst_gl_context_activate (gst_widget->priv->other_context, FALSE); g_mutex_unlock (&gst_widget->priv->lock); return FALSE; From 869ea6093ca93d25e810c7c443d31a3198f50379 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 15 Jun 2015 14:33:08 +1000 Subject: [PATCH 043/128] gtk: implement basic wayland GL support --- ext/gtk/gtkgstglwidget.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index dfe2c2faf8..b0c707977b 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -33,6 +33,11 @@ #include #endif +#if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND) +#include +#include +#endif + /** * SECTION:gtkgstglwidget * @short_description: a #GtkGLArea that renders GStreamer video #GstBuffers @@ -503,6 +508,14 @@ gtk_gst_gl_widget_init (GtkGstGLWidget * widget) gst_gl_display_x11_new_with_display (gdk_x11_display_get_xdisplay (display)); #endif +#if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND) + if (GDK_IS_WAYLAND_DISPLAY (display)) { + struct wl_display *wayland_display = + gdk_wayland_display_get_wl_display (display); + widget->priv->display = (GstGLDisplay *) + gst_gl_display_wayland_new_with_display (wayland_display); + } +#endif if (!widget->priv->display) widget->priv->display = gst_gl_display_new (); @@ -575,6 +588,17 @@ _get_gl_context (GtkGstGLWidget * gst_widget) platform, gl_api); } #endif +#if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND) + if (GST_IS_GL_DISPLAY_WAYLAND (gst_widget->priv->display)) { + platform = GST_GL_PLATFORM_EGL; + gl_api = gst_gl_context_get_current_gl_api (NULL, NULL); + gl_handle = gst_gl_context_get_current_gl_context (platform); + if (gl_handle) + gst_widget->priv->other_context = + gst_gl_context_new_wrapped (gst_widget->priv->display, gl_handle, + platform, gl_api); + } +#endif if (gst_widget->priv->other_context) { GError *error = NULL; From 8648d59974a344941804f3e8fbae886c21b009d8 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 15 Jun 2015 14:35:35 +1000 Subject: [PATCH 044/128] gtk: silence unused variable warnings for unsupported winsys' --- ext/gtk/gtkgstglwidget.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index b0c707977b..ba68ba34af 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -51,7 +51,8 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); G_DEFINE_TYPE_WITH_CODE (GtkGstGLWidget, gtk_gst_gl_widget, GTK_TYPE_GL_AREA, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gtkgstglwidget", 0, - "Gtk Gst GL Widget");); + "Gtk Gst GL Widget"); + ); #define GTK_GST_GL_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ GTK_TYPE_GST_GL_WIDGET, GtkGstGLWidgetPrivate)) @@ -517,6 +518,8 @@ gtk_gst_gl_widget_init (GtkGstGLWidget * widget) } #endif + (void) display; + if (!widget->priv->display) widget->priv->display = gst_gl_display_new (); @@ -600,6 +603,10 @@ _get_gl_context (GtkGstGLWidget * gst_widget) } #endif + (void) platform; + (void) gl_api; + (void) gl_handle; + if (gst_widget->priv->other_context) { GError *error = NULL; From 48db03200dcf569821448aac61125831ddcbc1a9 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 15 Jun 2015 18:28:37 +1000 Subject: [PATCH 045/128] gtk: implement pixel and display aspect ratio handling --- ext/gtk/gstgtkglsink.c | 22 ++++++++- ext/gtk/gstgtkglsink.h | 6 ++- ext/gtk/gstgtksink.c | 21 ++++++++ ext/gtk/gstgtksink.h | 4 ++ ext/gtk/gtkgstglwidget.c | 96 ++++++++++++++++++++++++++++++++++-- ext/gtk/gtkgstwidget.c | 102 +++++++++++++++++++++++++++++++++++++-- 6 files changed, 239 insertions(+), 12 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 372846f0e7..660bf03592 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -33,6 +33,8 @@ 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 static void gst_gtk_gl_sink_finalize (GObject * object); static void gst_gtk_gl_sink_set_property (GObject * object, guint prop_id, @@ -67,6 +69,7 @@ enum PROP_0, PROP_WIDGET, PROP_FORCE_ASPECT_RATIO, + PROP_PIXEL_ASPECT_RATIO, }; enum @@ -112,6 +115,11 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) 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)); + gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&gst_gtk_gl_sink_template)); @@ -131,6 +139,8 @@ 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; } static void @@ -157,9 +167,12 @@ gst_gtk_gl_sink_get_widget (GstGtkGLSink * gtk_sink) } gtk_sink->widget = (GtkGstGLWidget *) gtk_gst_gl_widget_new (); - gtk_sink->bind_aspect_ratio = + gtk_sink->bind_force_aspect_ratio = g_object_bind_property (gtk_sink, "force-aspect-ratio", gtk_sink->widget, "force-aspect-ratio", G_BINDING_BIDIRECTIONAL); + gtk_sink->bind_pixel_aspect_ratio = + g_object_bind_property (gtk_sink, "pixel-aspect-ratio", gtk_sink->widget, + "pixel-aspect-ratio", G_BINDING_BIDIRECTIONAL); /* Take the floating ref, otherwise the destruction of the container will * make this widget disapear possibly before we are done. */ @@ -183,6 +196,9 @@ gst_gtk_gl_sink_get_property (GObject * object, guint prop_id, 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; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -199,6 +215,10 @@ gst_gtk_gl_sink_set_property (GObject * object, guint 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; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/ext/gtk/gstgtkglsink.h b/ext/gtk/gstgtkglsink.h index 4c13059f5f..eaf2f0c433 100644 --- a/ext/gtk/gstgtkglsink.h +++ b/ext/gtk/gstgtkglsink.h @@ -67,7 +67,11 @@ struct _GstGtkGLSink /* properties */ gboolean force_aspect_ratio; - GBinding *bind_aspect_ratio; + GBinding *bind_force_aspect_ratio; + + gint par_n; + gint par_d; + GBinding *bind_pixel_aspect_ratio; GstGtkGLSinkPrivate *priv; }; diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index 1b349561c4..67fe7de381 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -59,12 +59,15 @@ GST_STATIC_PAD_TEMPLATE ("sink", ); #define DEFAULT_FORCE_ASPECT_RATIO TRUE +#define DEFAULT_PAR_N 0 +#define DEFAULT_PAR_D 1 enum { PROP_0, PROP_WIDGET, PROP_FORCE_ASPECT_RATIO, + PROP_PIXEL_ASPECT_RATIO, }; enum @@ -110,6 +113,11 @@ gst_gtk_sink_class_init (GstGtkSinkClass * klass) 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)); + gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&gst_gtk_sink_template)); @@ -127,6 +135,9 @@ gst_gtk_sink_class_init (GstGtkSinkClass * klass) static void gst_gtk_sink_init (GstGtkSink * 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; } static void @@ -156,6 +167,9 @@ gst_gtk_sink_get_widget (GstGtkSink * gtk_sink) gtk_sink->bind_aspect_ratio = g_object_bind_property (gtk_sink, "force-aspect-ratio", gtk_sink->widget, "force-aspect-ratio", G_BINDING_BIDIRECTIONAL); + gtk_sink->bind_pixel_aspect_ratio = + g_object_bind_property (gtk_sink, "pixel-aspect-ratio", gtk_sink->widget, + "pixel-aspect-ratio", G_BINDING_BIDIRECTIONAL); /* Take the floating ref, other wise the destruction of the container will * make this widget disapear possibly before we are done. */ @@ -177,6 +191,9 @@ gst_gtk_sink_get_property (GObject * object, guint prop_id, 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; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -193,6 +210,10 @@ gst_gtk_sink_set_property (GObject * object, guint 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; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/ext/gtk/gstgtksink.h b/ext/gtk/gstgtksink.h index 444c4b1980..d3e0b7b1ef 100644 --- a/ext/gtk/gstgtksink.h +++ b/ext/gtk/gstgtksink.h @@ -60,6 +60,10 @@ struct _GstGtkSink gboolean force_aspect_ratio; GBinding *bind_aspect_ratio; + gint par_n; + gint par_d; + GBinding *bind_pixel_aspect_ratio; + GstGtkSinkPrivate *priv; }; diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index ba68ba34af..26fa0dcd4a 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -51,18 +51,20 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); G_DEFINE_TYPE_WITH_CODE (GtkGstGLWidget, gtk_gst_gl_widget, GTK_TYPE_GL_AREA, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gtkgstglwidget", 0, - "Gtk Gst GL Widget"); - ); + "Gtk Gst GL Widget");); #define GTK_GST_GL_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ GTK_TYPE_GST_GL_WIDGET, GtkGstGLWidgetPrivate)) #define DEFAULT_FORCE_ASPECT_RATIO TRUE +#define DEFAULT_PAR_N 0 +#define DEFAULT_PAR_D 1 enum { PROP_0, PROP_FORCE_ASPECT_RATIO, + PROP_PIXEL_ASPECT_RATIO, }; struct _GtkGstGLWidgetPrivate @@ -71,6 +73,10 @@ struct _GtkGstGLWidgetPrivate /* properties */ gboolean force_aspect_ratio; + gint par_n, par_d; + + gint display_width; + gint display_height; gboolean negotiated; GstBuffer *buffer; @@ -210,8 +216,8 @@ _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) src.x = 0; src.y = 0; - src.w = GST_VIDEO_INFO_WIDTH (&gst_widget->priv->v_info); - src.h = GST_VIDEO_INFO_HEIGHT (&gst_widget->priv->v_info); + src.w = gst_widget->priv->display_width; + src.h = gst_widget->priv->display_height; dst.x = gtk_viewport[0]; dst.y = gtk_viewport[1]; @@ -442,6 +448,10 @@ gtk_gst_gl_widget_set_property (GObject * object, guint prop_id, case PROP_FORCE_ASPECT_RATIO: gtk_widget->priv->force_aspect_ratio = g_value_get_boolean (value); break; + case PROP_PIXEL_ASPECT_RATIO: + gtk_widget->priv->par_n = gst_value_get_fraction_numerator (value); + gtk_widget->priv->par_d = gst_value_get_fraction_denominator (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -458,6 +468,10 @@ gtk_gst_gl_widget_get_property (GObject * object, guint prop_id, GValue * value, case PROP_FORCE_ASPECT_RATIO: g_value_set_boolean (value, gtk_widget->priv->force_aspect_ratio); break; + case PROP_PIXEL_ASPECT_RATIO: + gst_value_set_fraction (value, gtk_widget->priv->par_n, + gtk_widget->priv->par_d); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -484,6 +498,11 @@ gtk_gst_gl_widget_class_init (GtkGstGLWidgetClass * klass) DEFAULT_FORCE_ASPECT_RATIO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_klass, 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)); + gl_widget_klass->render = gtk_gst_gl_widget_render; widget_klass->get_preferred_width = gtk_gst_gl_widget_get_preferred_width; @@ -498,6 +517,8 @@ gtk_gst_gl_widget_init (GtkGstGLWidget * widget) widget->priv = GTK_GST_GL_WIDGET_GET_PRIVATE (widget); widget->priv->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; + widget->priv->par_n = DEFAULT_PAR_N; + widget->priv->par_d = DEFAULT_PAR_D; g_mutex_init (&widget->priv->lock); @@ -523,7 +544,7 @@ gtk_gst_gl_widget_init (GtkGstGLWidget * widget) if (!widget->priv->display) widget->priv->display = gst_gl_display_new (); - gtk_gl_area_set_has_alpha ((GtkGLArea *) widget, TRUE); + gtk_gl_area_set_has_alpha ((GtkGLArea *) widget, FALSE); } GtkWidget * @@ -665,6 +686,66 @@ gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * widget) return TRUE; } +static gboolean +_calculate_par (GtkGstGLWidget * widget, GstVideoInfo * info) +{ + gboolean ok; + gint width, height; + gint par_n, par_d; + gint display_par_n, display_par_d; + guint display_ratio_num, display_ratio_den; + + width = GST_VIDEO_INFO_WIDTH (info); + height = GST_VIDEO_INFO_HEIGHT (info); + + par_n = GST_VIDEO_INFO_PAR_N (info); + par_d = GST_VIDEO_INFO_PAR_D (info); + + if (!par_n) + par_n = 1; + + /* get display's PAR */ + if (widget->priv->par_n != 0 && widget->priv->par_d != 0) { + display_par_n = widget->priv->par_n; + display_par_d = widget->priv->par_d; + } else { + display_par_n = 1; + display_par_d = 1; + } + + ok = gst_video_calculate_display_ratio (&display_ratio_num, + &display_ratio_den, width, height, par_n, par_d, display_par_n, + display_par_d); + + if (!ok) + return FALSE; + + GST_LOG ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n, display_par_d); + + if (height % display_ratio_den == 0) { + GST_DEBUG ("keeping video height"); + widget->priv->display_width = (guint) + gst_util_uint64_scale_int (height, display_ratio_num, + display_ratio_den); + widget->priv->display_height = height; + } else if (width % display_ratio_num == 0) { + GST_DEBUG ("keeping video width"); + widget->priv->display_width = width; + widget->priv->display_height = (guint) + gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num); + } else { + GST_DEBUG ("approximating while keeping video height"); + widget->priv->display_width = (guint) + gst_util_uint64_scale_int (height, display_ratio_num, + display_ratio_den); + widget->priv->display_height = height; + } + GST_DEBUG ("scaling to %dx%d", widget->priv->display_width, + widget->priv->display_height); + + return TRUE; +} + gboolean gtk_gst_gl_widget_set_caps (GtkGstGLWidget * widget, GstCaps * caps) { @@ -691,6 +772,11 @@ gtk_gst_gl_widget_set_caps (GtkGstGLWidget * widget, GstCaps * caps) gst_caps_set_features (widget->priv->gl_caps, 0, gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY)); + if (!_calculate_par (widget, &v_info)) { + g_mutex_unlock (&widget->priv->lock); + return FALSE; + } + widget->priv->v_info = v_info; widget->priv->negotiated = TRUE; diff --git a/ext/gtk/gtkgstwidget.c b/ext/gtk/gtkgstwidget.c index aa40f39391..7607bd53b7 100644 --- a/ext/gtk/gtkgstwidget.c +++ b/ext/gtk/gtkgstwidget.c @@ -41,11 +41,14 @@ G_DEFINE_TYPE (GtkGstWidget, gtk_gst_widget, GTK_TYPE_DRAWING_AREA); GTK_TYPE_GST_WIDGET, GtkGstWidgetPrivate)) #define DEFAULT_FORCE_ASPECT_RATIO TRUE +#define DEFAULT_PAR_N 0 +#define DEFAULT_PAR_D 1 enum { PROP_0, PROP_FORCE_ASPECT_RATIO, + PROP_PIXEL_ASPECT_RATIO, }; struct _GtkGstWidgetPrivate @@ -54,6 +57,10 @@ struct _GtkGstWidgetPrivate /* properties */ gboolean force_aspect_ratio; + gint par_n, par_d; + + gint display_width; + gint display_height; gboolean negotiated; GstBuffer *buffer; @@ -110,10 +117,9 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) if (gst_widget->priv->negotiated && gst_widget->priv->buffer && gst_video_frame_map (&frame, &gst_widget->priv->v_info, gst_widget->priv->buffer, GST_MAP_READ)) { - gdouble scale_x = - (gdouble) widget_width / GST_VIDEO_INFO_WIDTH (&frame.info); + gdouble scale_x = (gdouble) widget_width / gst_widget->priv->display_width; gdouble scale_y = - (gdouble) widget_height / GST_VIDEO_INFO_HEIGHT (&frame.info); + (gdouble) widget_height / gst_widget->priv->display_height; GstVideoRectangle result; gst_widget->priv->v_info = frame.info; @@ -127,8 +133,8 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) src.x = 0; src.y = 0; - src.w = GST_VIDEO_INFO_WIDTH (&frame.info); - src.h = GST_VIDEO_INFO_HEIGHT (&frame.info); + src.w = gst_widget->priv->display_width; + src.h = gst_widget->priv->display_height; dst.x = 0; dst.y = 0; @@ -145,6 +151,12 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) result.h = widget_height; } + scale_x *= + (gdouble) gst_widget->priv->display_width / (gdouble) frame.info.width; + scale_y *= + (gdouble) gst_widget->priv->display_height / + (gdouble) frame.info.height; + cairo_translate (cr, result.x, result.y); cairo_scale (cr, scale_x, scale_y); cairo_rectangle (cr, 0, 0, result.w, result.h); @@ -189,6 +201,10 @@ gtk_gst_widget_set_property (GObject * object, guint prop_id, case PROP_FORCE_ASPECT_RATIO: gtk_widget->priv->force_aspect_ratio = g_value_get_boolean (value); break; + case PROP_PIXEL_ASPECT_RATIO: + gtk_widget->priv->par_n = gst_value_get_fraction_numerator (value); + gtk_widget->priv->par_d = gst_value_get_fraction_denominator (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -205,6 +221,10 @@ gtk_gst_widget_get_property (GObject * object, guint prop_id, GValue * value, case PROP_FORCE_ASPECT_RATIO: g_value_set_boolean (value, gtk_widget->priv->force_aspect_ratio); break; + case PROP_PIXEL_ASPECT_RATIO: + gst_value_set_fraction (value, gtk_widget->priv->par_n, + gtk_widget->priv->par_d); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -230,6 +250,11 @@ gtk_gst_widget_class_init (GtkGstWidgetClass * klass) DEFAULT_FORCE_ASPECT_RATIO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_klass, 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)); + widget_klass->draw = gtk_gst_widget_draw; widget_klass->get_preferred_width = gtk_gst_widget_get_preferred_width; widget_klass->get_preferred_height = gtk_gst_widget_get_preferred_height; @@ -241,6 +266,8 @@ gtk_gst_widget_init (GtkGstWidget * widget) widget->priv = GTK_GST_WIDGET_GET_PRIVATE (widget); widget->priv->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; + widget->priv->par_n = DEFAULT_PAR_N; + widget->priv->par_d = DEFAULT_PAR_D; g_mutex_init (&widget->priv->lock); } @@ -284,6 +311,66 @@ _queue_resize (GtkGstWidget * widget) return G_SOURCE_REMOVE; } +static gboolean +_calculate_par (GtkGstWidget * widget, GstVideoInfo * info) +{ + gboolean ok; + gint width, height; + gint par_n, par_d; + gint display_par_n, display_par_d; + guint display_ratio_num, display_ratio_den; + + width = GST_VIDEO_INFO_WIDTH (info); + height = GST_VIDEO_INFO_HEIGHT (info); + + par_n = GST_VIDEO_INFO_PAR_N (info); + par_d = GST_VIDEO_INFO_PAR_D (info); + + if (!par_n) + par_n = 1; + + /* get display's PAR */ + if (widget->priv->par_n != 0 && widget->priv->par_d != 0) { + display_par_n = widget->priv->par_n; + display_par_d = widget->priv->par_d; + } else { + display_par_n = 1; + display_par_d = 1; + } + + ok = gst_video_calculate_display_ratio (&display_ratio_num, + &display_ratio_den, width, height, par_n, par_d, display_par_n, + display_par_d); + + if (!ok) + return FALSE; + + GST_LOG ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n, display_par_d); + + if (height % display_ratio_den == 0) { + GST_DEBUG ("keeping video height"); + widget->priv->display_width = (guint) + gst_util_uint64_scale_int (height, display_ratio_num, + display_ratio_den); + widget->priv->display_height = height; + } else if (width % display_ratio_num == 0) { + GST_DEBUG ("keeping video width"); + widget->priv->display_width = width; + widget->priv->display_height = (guint) + gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num); + } else { + GST_DEBUG ("approximating while keeping video height"); + widget->priv->display_width = (guint) + gst_util_uint64_scale_int (height, display_ratio_num, + display_ratio_den); + widget->priv->display_height = height; + } + GST_DEBUG ("scaling to %dx%d", widget->priv->display_width, + widget->priv->display_height); + + return TRUE; +} + gboolean gtk_gst_widget_set_caps (GtkGstWidget * widget, GstCaps * caps) { @@ -306,6 +393,11 @@ gtk_gst_widget_set_caps (GtkGstWidget * widget, GstCaps * caps) g_mutex_lock (&widget->priv->lock); + if (!_calculate_par (widget, &v_info)) { + g_mutex_unlock (&widget->priv->lock); + return FALSE; + } + gst_caps_replace (&widget->priv->caps, caps); widget->priv->v_info = v_info; widget->priv->negotiated = TRUE; From 8497b84e0db813bfc5b2b99259d49a81f5d4d5d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Jun 2015 20:13:57 +0200 Subject: [PATCH 046/128] gtk: Sync properties from the sink to the widget upon widget creation --- ext/gtk/gstgtkglsink.c | 4 ++-- ext/gtk/gstgtksink.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 660bf03592..1f2a9e92c8 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -169,10 +169,10 @@ gst_gtk_gl_sink_get_widget (GstGtkGLSink * gtk_sink) gtk_sink->widget = (GtkGstGLWidget *) 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); + "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); + "pixel-aspect-ratio", 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. */ diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index 67fe7de381..09487b750c 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -166,10 +166,10 @@ gst_gtk_sink_get_widget (GstGtkSink * gtk_sink) gtk_sink->widget = (GtkGstWidget *) gtk_gst_widget_new (); gtk_sink->bind_aspect_ratio = g_object_bind_property (gtk_sink, "force-aspect-ratio", gtk_sink->widget, - "force-aspect-ratio", G_BINDING_BIDIRECTIONAL); + "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); + "pixel-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); /* Take the floating ref, other wise the destruction of the container will * make this widget disapear possibly before we are done. */ From 05fa796c251c177cf1fd46ec44944dcb1a93a69d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Jun 2015 20:35:38 +0200 Subject: [PATCH 047/128] gtk: Implement ignore-alpha property and enable it by default --- ext/gtk/gstgtkglsink.c | 17 +++++++++++++++ ext/gtk/gstgtkglsink.h | 3 +++ ext/gtk/gstgtksink.c | 17 +++++++++++++++ ext/gtk/gstgtksink.h | 3 +++ ext/gtk/gtkgstglwidget.c | 19 +++++++++++++++- ext/gtk/gtkgstwidget.c | 47 ++++++++++++++++++++++++++++++++++++++-- 6 files changed, 103 insertions(+), 3 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 1f2a9e92c8..2a77aec350 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -35,6 +35,7 @@ GST_DEBUG_CATEGORY (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, @@ -70,6 +71,7 @@ enum PROP_WIDGET, PROP_FORCE_ASPECT_RATIO, PROP_PIXEL_ASPECT_RATIO, + PROP_IGNORE_ALPHA, }; enum @@ -120,6 +122,11 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) "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)); @@ -141,6 +148,7 @@ 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 @@ -173,6 +181,9 @@ gst_gtk_gl_sink_get_widget (GstGtkGLSink * gtk_sink) 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. */ @@ -199,6 +210,9 @@ gst_gtk_gl_sink_get_property (GObject * object, guint prop_id, 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; @@ -219,6 +233,9 @@ gst_gtk_gl_sink_set_property (GObject * object, guint prop_id, 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; diff --git a/ext/gtk/gstgtkglsink.h b/ext/gtk/gstgtkglsink.h index eaf2f0c433..844b28bd3f 100644 --- a/ext/gtk/gstgtkglsink.h +++ b/ext/gtk/gstgtkglsink.h @@ -73,6 +73,9 @@ struct _GstGtkGLSink gint par_d; GBinding *bind_pixel_aspect_ratio; + gboolean ignore_alpha; + GBinding *bind_ignore_alpha; + GstGtkGLSinkPrivate *priv; }; diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index 09487b750c..be5bf15e76 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -61,6 +61,7 @@ GST_STATIC_PAD_TEMPLATE ("sink", #define DEFAULT_FORCE_ASPECT_RATIO TRUE #define DEFAULT_PAR_N 0 #define DEFAULT_PAR_D 1 +#define DEFAULT_IGNORE_ALPHA TRUE enum { @@ -68,6 +69,7 @@ enum PROP_WIDGET, PROP_FORCE_ASPECT_RATIO, PROP_PIXEL_ASPECT_RATIO, + PROP_IGNORE_ALPHA, }; enum @@ -118,6 +120,11 @@ gst_gtk_sink_class_init (GstGtkSinkClass * klass) "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_sink_template)); @@ -138,6 +145,7 @@ gst_gtk_sink_init (GstGtkSink * 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 @@ -170,6 +178,9 @@ gst_gtk_sink_get_widget (GstGtkSink * gtk_sink) 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, other wise the destruction of the container will * make this widget disapear possibly before we are done. */ @@ -194,6 +205,9 @@ gst_gtk_sink_get_property (GObject * object, guint prop_id, 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; @@ -214,6 +228,9 @@ gst_gtk_sink_set_property (GObject * object, guint prop_id, 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; diff --git a/ext/gtk/gstgtksink.h b/ext/gtk/gstgtksink.h index d3e0b7b1ef..ded85d78ab 100644 --- a/ext/gtk/gstgtksink.h +++ b/ext/gtk/gstgtksink.h @@ -64,6 +64,9 @@ struct _GstGtkSink gint par_d; GBinding *bind_pixel_aspect_ratio; + gboolean ignore_alpha; + GBinding *bind_ignore_alpha; + GstGtkSinkPrivate *priv; }; diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 26fa0dcd4a..adca9cdf61 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -59,12 +59,14 @@ G_DEFINE_TYPE_WITH_CODE (GtkGstGLWidget, gtk_gst_gl_widget, GTK_TYPE_GL_AREA, #define DEFAULT_FORCE_ASPECT_RATIO TRUE #define DEFAULT_PAR_N 0 #define DEFAULT_PAR_D 1 +#define DEFAULT_IGNORE_ALPHA TRUE enum { PROP_0, PROP_FORCE_ASPECT_RATIO, PROP_PIXEL_ASPECT_RATIO, + PROP_IGNORE_ALPHA, }; struct _GtkGstGLWidgetPrivate @@ -74,6 +76,7 @@ struct _GtkGstGLWidgetPrivate /* properties */ gboolean force_aspect_ratio; gint par_n, par_d; + gboolean ignore_alpha; gint display_width; gint display_height; @@ -452,6 +455,11 @@ gtk_gst_gl_widget_set_property (GObject * object, guint prop_id, gtk_widget->priv->par_n = gst_value_get_fraction_numerator (value); gtk_widget->priv->par_d = gst_value_get_fraction_denominator (value); break; + case PROP_IGNORE_ALPHA: + gtk_widget->priv->ignore_alpha = g_value_get_boolean (value); + gtk_gl_area_set_has_alpha ((GtkGLArea *) gtk_widget, + !gtk_widget->priv->ignore_alpha); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -472,6 +480,9 @@ gtk_gst_gl_widget_get_property (GObject * object, guint prop_id, GValue * value, gst_value_set_fraction (value, gtk_widget->priv->par_n, gtk_widget->priv->par_d); break; + case PROP_IGNORE_ALPHA: + g_value_set_boolean (value, gtk_widget->priv->ignore_alpha); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -503,6 +514,11 @@ gtk_gst_gl_widget_class_init (GtkGstGLWidgetClass * klass) "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_klass, 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)); + gl_widget_klass->render = gtk_gst_gl_widget_render; widget_klass->get_preferred_width = gtk_gst_gl_widget_get_preferred_width; @@ -519,6 +535,7 @@ gtk_gst_gl_widget_init (GtkGstGLWidget * widget) widget->priv->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; widget->priv->par_n = DEFAULT_PAR_N; widget->priv->par_d = DEFAULT_PAR_D; + widget->priv->ignore_alpha = DEFAULT_IGNORE_ALPHA; g_mutex_init (&widget->priv->lock); @@ -544,7 +561,7 @@ gtk_gst_gl_widget_init (GtkGstGLWidget * widget) if (!widget->priv->display) widget->priv->display = gst_gl_display_new (); - gtk_gl_area_set_has_alpha ((GtkGLArea *) widget, FALSE); + gtk_gl_area_set_has_alpha ((GtkGLArea *) widget, !widget->priv->ignore_alpha); } GtkWidget * diff --git a/ext/gtk/gtkgstwidget.c b/ext/gtk/gtkgstwidget.c index 7607bd53b7..ac3e5a9e0b 100644 --- a/ext/gtk/gtkgstwidget.c +++ b/ext/gtk/gtkgstwidget.c @@ -43,12 +43,14 @@ G_DEFINE_TYPE (GtkGstWidget, gtk_gst_widget, GTK_TYPE_DRAWING_AREA); #define DEFAULT_FORCE_ASPECT_RATIO TRUE #define DEFAULT_PAR_N 0 #define DEFAULT_PAR_D 1 +#define DEFAULT_IGNORE_ALPHA TRUE enum { PROP_0, PROP_FORCE_ASPECT_RATIO, PROP_PIXEL_ASPECT_RATIO, + PROP_IGNORE_ALPHA, }; struct _GtkGstWidgetPrivate @@ -58,6 +60,7 @@ struct _GtkGstWidgetPrivate /* properties */ gboolean force_aspect_ratio; gint par_n, par_d; + gboolean ignore_alpha; gint display_width; gint display_height; @@ -151,6 +154,30 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) result.h = widget_height; } + if (gst_widget->priv->ignore_alpha) { + GdkRGBA color = { 0.0, 0.0, 0.0, 1.0 }; + + gdk_cairo_set_source_rgba (cr, &color); + if (result.x > 0) { + cairo_rectangle (cr, 0, 0, result.x, widget_height); + cairo_fill (cr); + } + if (result.y > 0) { + cairo_rectangle (cr, 0, 0, widget_width, result.y); + cairo_fill (cr); + } + if (result.w < widget_width) { + cairo_rectangle (cr, result.x + result.w, 0, widget_width - result.w, + widget_height); + cairo_fill (cr); + } + if (result.h < widget_height) { + cairo_rectangle (cr, 0, result.y + result.h, widget_width, + widget_height - result.h); + cairo_fill (cr); + } + } + scale_x *= (gdouble) gst_widget->priv->display_width / (gdouble) frame.info.width; scale_y *= @@ -169,8 +196,13 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) } else { GdkRGBA color; - gtk_style_context_get_color (gtk_widget_get_style_context (widget), 0, - &color); + if (gst_widget->priv->ignore_alpha) { + color.red = color.blue = color.green = 0.0; + color.alpha = 1.0; + } else { + gtk_style_context_get_color (gtk_widget_get_style_context (widget), + GTK_STATE_FLAG_NORMAL, &color); + } gdk_cairo_set_source_rgba (cr, &color); cairo_rectangle (cr, 0, 0, widget_width, widget_height); cairo_fill (cr); @@ -205,6 +237,9 @@ gtk_gst_widget_set_property (GObject * object, guint prop_id, gtk_widget->priv->par_n = gst_value_get_fraction_numerator (value); gtk_widget->priv->par_d = gst_value_get_fraction_denominator (value); break; + case PROP_IGNORE_ALPHA: + gtk_widget->priv->ignore_alpha = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -224,6 +259,8 @@ gtk_gst_widget_get_property (GObject * object, guint prop_id, GValue * value, case PROP_PIXEL_ASPECT_RATIO: gst_value_set_fraction (value, gtk_widget->priv->par_n, gtk_widget->priv->par_d); + case PROP_IGNORE_ALPHA: + g_value_set_boolean (value, gtk_widget->priv->ignore_alpha); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -255,6 +292,11 @@ gtk_gst_widget_class_init (GtkGstWidgetClass * klass) "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_klass, 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)); + widget_klass->draw = gtk_gst_widget_draw; widget_klass->get_preferred_width = gtk_gst_widget_get_preferred_width; widget_klass->get_preferred_height = gtk_gst_widget_get_preferred_height; @@ -268,6 +310,7 @@ gtk_gst_widget_init (GtkGstWidget * widget) widget->priv->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; widget->priv->par_n = DEFAULT_PAR_N; widget->priv->par_d = DEFAULT_PAR_D; + widget->priv->ignore_alpha = DEFAULT_IGNORE_ALPHA; g_mutex_init (&widget->priv->lock); } From bd9ec0f3334b460babf61cac9a60e34cad11ceb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Jun 2015 20:39:59 +0200 Subject: [PATCH 048/128] gtk: Cairo color formats are in native endianness, GStreamer's in memory order CAIRO_FORMAT_ARGB32 is ARGB on big endian and BGRA on little endian. --- ext/gtk/gstgtksink.c | 8 +++++++- ext/gtk/gtkgstwidget.c | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index be5bf15e76..baf495088c 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -51,11 +51,17 @@ static gboolean gst_gtk_sink_set_caps (GstBaseSink * bsink, GstCaps * caps); static GstFlowReturn gst_gtk_sink_show_frame (GstVideoSink * bsink, GstBuffer * buf); +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#define FORMATS "BGRA" +#else +#define FORMATS "ARGB" +#endif + static GstStaticPadTemplate gst_gtk_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("BGRA")) + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (FORMATS)) ); #define DEFAULT_FORCE_ASPECT_RATIO TRUE diff --git a/ext/gtk/gtkgstwidget.c b/ext/gtk/gtkgstwidget.c index ac3e5a9e0b..2f4b0bf102 100644 --- a/ext/gtk/gtkgstwidget.c +++ b/ext/gtk/gtkgstwidget.c @@ -431,8 +431,13 @@ gtk_gst_widget_set_caps (GtkGstWidget * widget, GstCaps * caps) return FALSE; /* FIXME: support other formats */ +#if G_BYTE_ORDER == G_LITTLE_ENDIAN g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&v_info) == GST_VIDEO_FORMAT_BGRA, FALSE); +#else + g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&v_info) == + GST_VIDEO_FORMAT_ARGB, FALSE); +#endif g_mutex_lock (&widget->priv->lock); From 166e33d64c53fc12ec26cf6a54d150dde9362280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Jun 2015 20:45:11 +0200 Subject: [PATCH 049/128] gtksink: Add support for xRGB/BGRx --- ext/gtk/gstgtksink.c | 4 ++-- ext/gtk/gtkgstwidget.c | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index baf495088c..2c5d3ed3eb 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -52,9 +52,9 @@ static GstFlowReturn gst_gtk_sink_show_frame (GstVideoSink * bsink, GstBuffer * buf); #if G_BYTE_ORDER == G_LITTLE_ENDIAN -#define FORMATS "BGRA" +#define FORMATS "{ BGRx, BGRA }" #else -#define FORMATS "ARGB" +#define FORMATS "{ xRGB, ARGB }" #endif static GstStaticPadTemplate gst_gtk_sink_template = diff --git a/ext/gtk/gtkgstwidget.c b/ext/gtk/gtkgstwidget.c index 2f4b0bf102..023d3766ab 100644 --- a/ext/gtk/gtkgstwidget.c +++ b/ext/gtk/gtkgstwidget.c @@ -124,12 +124,18 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) gdouble scale_y = (gdouble) widget_height / gst_widget->priv->display_height; GstVideoRectangle result; + cairo_format_t format; gst_widget->priv->v_info = frame.info; + if (frame.info.finfo->format == GST_VIDEO_FORMAT_ARGB || + frame.info.finfo->format == GST_VIDEO_FORMAT_BGRA) { + format = CAIRO_FORMAT_ARGB32; + } else { + format = CAIRO_FORMAT_RGB24; + } surface = cairo_image_surface_create_for_data (frame.data[0], - CAIRO_FORMAT_ARGB32, frame.info.width, frame.info.height, - frame.info.stride[0]); + format, frame.info.width, frame.info.height, frame.info.stride[0]); if (gst_widget->priv->force_aspect_ratio) { GstVideoRectangle src, dst; @@ -433,10 +439,12 @@ gtk_gst_widget_set_caps (GtkGstWidget * widget, GstCaps * caps) /* FIXME: support other formats */ #if G_BYTE_ORDER == G_LITTLE_ENDIAN g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&v_info) == - GST_VIDEO_FORMAT_BGRA, FALSE); + GST_VIDEO_FORMAT_BGRA || GST_VIDEO_INFO_FORMAT (&v_info) == + GST_VIDEO_FORMAT_BGRx, FALSE); #else g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&v_info) == - GST_VIDEO_FORMAT_ARGB, FALSE); + GST_VIDEO_FORMAT_ARGB || GST_VIDEO_INFO_FORMAT (&v_info) == + GST_VIDEO_FORMAT_xRGB, FALSE); #endif g_mutex_lock (&widget->priv->lock); From 5cabeb34151fabe908c618256beed774b88114b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Jun 2015 21:24:01 +0200 Subject: [PATCH 050/128] gtk: Use the display width/height for the widget's preferred width/height --- ext/gtk/gtkgstglwidget.c | 4 ++-- ext/gtk/gtkgstwidget.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index adca9cdf61..d9b65e3c11 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -107,7 +107,7 @@ gtk_gst_gl_widget_get_preferred_width (GtkWidget * widget, gint * min, gint * natural) { GtkGstGLWidget *gst_widget = (GtkGstGLWidget *) widget; - gint video_width = GST_VIDEO_INFO_WIDTH (&gst_widget->priv->v_info); + gint video_width = gst_widget->priv->display_width; if (!gst_widget->priv->negotiated) video_width = 10; @@ -123,7 +123,7 @@ gtk_gst_gl_widget_get_preferred_height (GtkWidget * widget, gint * min, gint * natural) { GtkGstGLWidget *gst_widget = (GtkGstGLWidget *) widget; - gint video_height = GST_VIDEO_INFO_HEIGHT (&gst_widget->priv->v_info); + gint video_height = gst_widget->priv->display_height; if (!gst_widget->priv->negotiated) video_height = 10; diff --git a/ext/gtk/gtkgstwidget.c b/ext/gtk/gtkgstwidget.c index 023d3766ab..36a787423f 100644 --- a/ext/gtk/gtkgstwidget.c +++ b/ext/gtk/gtkgstwidget.c @@ -76,7 +76,7 @@ gtk_gst_widget_get_preferred_width (GtkWidget * widget, gint * min, gint * natural) { GtkGstWidget *gst_widget = (GtkGstWidget *) widget; - gint video_width = GST_VIDEO_INFO_WIDTH (&gst_widget->priv->v_info); + gint video_width = gst_widget->priv->display_width; if (!gst_widget->priv->negotiated) video_width = 10; @@ -92,7 +92,7 @@ gtk_gst_widget_get_preferred_height (GtkWidget * widget, gint * min, gint * natural) { GtkGstWidget *gst_widget = (GtkGstWidget *) widget; - gint video_height = GST_VIDEO_INFO_HEIGHT (&gst_widget->priv->v_info); + gint video_height = gst_widget->priv->display_height; if (!gst_widget->priv->negotiated) video_height = 10; From e410c770f5885e5cba4c652da1f527c549007c19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Jun 2015 21:29:46 +0200 Subject: [PATCH 051/128] gtkglwidget: Calculate the viewport size ourselves Getting the current viewport and modifying it relatively will produce an interesting feedback loop during widget resizing. Over a few frames we will gradually move the viewport a bit until it converged again, adding unnecessary additional borders at the top and left. --- ext/gtk/gtkgstglwidget.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index d9b65e3c11..96ac861230 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -210,22 +210,24 @@ _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) if (gst_widget->priv->force_aspect_ratio) { GstVideoRectangle src, dst, result; - gint gtk_viewport[4]; + gint widget_width, widget_height, widget_scale; gl->ClearColor (0.0, 0.0, 0.0, 0.0); gl->Clear (GL_COLOR_BUFFER_BIT); - gl->GetIntegerv (GL_VIEWPORT, gtk_viewport); + widget_scale = gtk_widget_get_scale_factor ((GtkWidget *) gst_widget); + widget_width = gtk_widget_get_allocated_width ((GtkWidget *) gst_widget); + widget_height = gtk_widget_get_allocated_height ((GtkWidget *) gst_widget); src.x = 0; src.y = 0; src.w = gst_widget->priv->display_width; src.h = gst_widget->priv->display_height; - dst.x = gtk_viewport[0]; - dst.y = gtk_viewport[1]; - dst.w = gtk_viewport[2]; - dst.h = gtk_viewport[3]; + dst.x = 0; + dst.y = 0; + dst.w = widget_width * widget_scale; + dst.h = widget_height * widget_scale; gst_video_sink_center_rect (src, dst, &result, TRUE); From 577ca6a0e8762c1d96bbf427dc49c11868c593a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Jun 2015 21:32:43 +0200 Subject: [PATCH 052/128] gtkglwidget: Const'ify another array --- ext/gtk/gtkgstglwidget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 96ac861230..e7e12210cd 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -206,7 +206,7 @@ static void _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) { const GstGLFuncs *gl = gst_widget->priv->context->gl_vtable; - GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; + const GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; if (gst_widget->priv->force_aspect_ratio) { GstVideoRectangle src, dst, result; From cb10f1b290646b2e068f9e34baab6489bc920f3b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 6 Jul 2015 19:33:35 +0200 Subject: [PATCH 053/128] gtkglsink: Release the widget lock when trying to get the GL context Otherwise we might be waiting for the lock on the main loop (for example in the ->render vmethod) and thus we will deadlock. --- ext/gtk/gtkgstglwidget.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index e7e12210cd..81950342d5 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -683,7 +683,9 @@ gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * widget) } if (!widget->priv->other_context) { + g_mutex_unlock (&widget->priv->lock); _invoke_on_main ((ThreadFunc) _get_gl_context, widget); + g_mutex_lock (&widget->priv->lock); } if (!GST_GL_IS_CONTEXT (widget->priv->other_context)) { From c55e55f48b4d2671814c12c976fb0bf9a1b8fe00 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Tue, 16 Jun 2015 16:21:26 -0400 Subject: [PATCH 054/128] GstGtkGLSink: fix possible warning in finalize If the element is finalized before going in READY state the widget could still be NULL. https://bugzilla.gnome.org/show_bug.cgi?id=751104 --- ext/gtk/gstgtkglsink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 2a77aec350..cee44ba6a2 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -156,7 +156,7 @@ gst_gtk_gl_sink_finalize (GObject * object) { GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (object);; - g_object_unref (gtk_sink->widget); + g_clear_object (>k_sink->widget); G_OBJECT_CLASS (parent_class)->finalize (object); } From 9f39a9964a07e6d118a4994dc275265931df65da Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 17 Jun 2015 09:36:40 -0400 Subject: [PATCH 055/128] GstGtkGLSink: Post error if widget gets destroyed https://bugzilla.gnome.org/show_bug.cgi?id=751104 --- ext/gtk/gstgtkglsink.c | 14 ++++++++++++++ ext/gtk/gstgtkglsink.h | 1 + 2 files changed, 15 insertions(+) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index cee44ba6a2..6f7c2b5c3f 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -161,6 +161,12 @@ gst_gtk_gl_sink_finalize (GObject * object) G_OBJECT_CLASS (parent_class)->finalize (object); } +static void +widget_destroy_cb (GtkWidget * widget, GstGtkGLSink * gtk_sink) +{ + g_atomic_int_set (>k_sink->widget_destroyed, 1); +} + static GtkGstGLWidget * gst_gtk_gl_sink_get_widget (GstGtkGLSink * gtk_sink) { @@ -188,6 +194,8 @@ gst_gtk_gl_sink_get_widget (GstGtkGLSink * gtk_sink) /* 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; } @@ -426,6 +434,12 @@ gst_gtk_gl_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) gtk_gst_gl_widget_set_buffer (gtk_sink->widget, buf); + if (g_atomic_int_get (>k_sink->widget_destroyed)) { + GST_ELEMENT_ERROR (gtk_sink, RESOURCE, NOT_FOUND, + ("%s", "Output widget was destroyed"), (NULL)); + return GST_FLOW_ERROR; + } + return GST_FLOW_OK; } diff --git a/ext/gtk/gstgtkglsink.h b/ext/gtk/gstgtkglsink.h index 844b28bd3f..4944ce6d35 100644 --- a/ext/gtk/gstgtkglsink.h +++ b/ext/gtk/gstgtkglsink.h @@ -54,6 +54,7 @@ struct _GstGtkGLSink GstVideoSink parent; GtkGstGLWidget *widget; + gboolean widget_destroyed; GstVideoInfo v_info; GstBufferPool *pool; From c3f1f2d78bf622893cf15bf68ff63245566d7906 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 17 Jun 2015 09:36:57 -0400 Subject: [PATCH 056/128] GstGtkGLSink: Ensure widget has a toplevel parent Checking for a parent is not enough, it must have a toplevel one. If widget has no toplevel parent then add it in a GtkWindow, that make it usable from gst-launch-1.0. https://bugzilla.gnome.org/show_bug.cgi?id=751104 --- ext/gtk/gstgtkglsink.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 6f7c2b5c3f..1a98c02213 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -314,6 +314,7 @@ 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)), @@ -326,10 +327,17 @@ gst_gtk_gl_sink_change_state (GstElement * element, GstStateChange transition) /* After this point, gtk_sink->widget will always be set */ - if (!gtk_widget_get_parent (GTK_WIDGET (gtk_sink->widget))) { - GST_ERROR_OBJECT (gtk_sink, - "gtkglsink widget needs to be parented to work."); - return GST_STATE_CHANGE_FAILURE; + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (gtk_sink->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 (gtk_sink->widget)) From 469ea207547c76b11afff57166316666bbe086ee Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Thu, 9 Jul 2015 13:03:23 +1000 Subject: [PATCH 057/128] gtk: add to the generic/states test --- ext/gtk/gtkgstglwidget.c | 2 +- ext/gtk/gtkgstwidget.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 81950342d5..2e108c9f93 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -586,7 +586,7 @@ gtk_gst_gl_widget_set_buffer (GtkGstGLWidget * widget, GstBuffer * buffer) GMainContext *main_context = g_main_context_default (); g_return_if_fail (GTK_IS_GST_GL_WIDGET (widget)); - g_return_if_fail (widget->priv->negotiated); + g_return_if_fail (buffer == NULL || widget->priv->negotiated); g_mutex_lock (&widget->priv->lock); diff --git a/ext/gtk/gtkgstwidget.c b/ext/gtk/gtkgstwidget.c index 36a787423f..e232eebe88 100644 --- a/ext/gtk/gtkgstwidget.c +++ b/ext/gtk/gtkgstwidget.c @@ -341,7 +341,7 @@ gtk_gst_widget_set_buffer (GtkGstWidget * widget, GstBuffer * buffer) GMainContext *main_context = g_main_context_default (); g_return_if_fail (GTK_IS_GST_WIDGET (widget)); - g_return_if_fail (widget->priv->negotiated); + g_return_if_fail (buffer == NULL || widget->priv->negotiated); g_mutex_lock (&widget->priv->lock); From 5db1a0027a56818b8b2e9e86dbd6a71e63d5f651 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 15 Jul 2015 11:44:30 -0400 Subject: [PATCH 058/128] gtksinks: Remove undefined private structure The classes contains a private structure which are not defined, hence unused. --- ext/gtk/gstgtkglsink.h | 3 --- ext/gtk/gstgtksink.h | 3 --- 2 files changed, 6 deletions(-) diff --git a/ext/gtk/gstgtkglsink.h b/ext/gtk/gstgtkglsink.h index 4944ce6d35..d1c65c00a8 100644 --- a/ext/gtk/gstgtkglsink.h +++ b/ext/gtk/gstgtkglsink.h @@ -29,7 +29,6 @@ typedef struct _GstGtkGLSink GstGtkGLSink; typedef struct _GstGtkGLSinkClass GstGtkGLSinkClass; -typedef struct _GstGtkGLSinkPrivate GstGtkGLSinkPrivate; #include @@ -76,8 +75,6 @@ struct _GstGtkGLSink gboolean ignore_alpha; GBinding *bind_ignore_alpha; - - GstGtkGLSinkPrivate *priv; }; /** diff --git a/ext/gtk/gstgtksink.h b/ext/gtk/gstgtksink.h index ded85d78ab..f7b6ba7506 100644 --- a/ext/gtk/gstgtksink.h +++ b/ext/gtk/gstgtksink.h @@ -28,7 +28,6 @@ typedef struct _GstGtkSink GstGtkSink; typedef struct _GstGtkSinkClass GstGtkSinkClass; -typedef struct _GstGtkSinkPrivate GstGtkSinkPrivate; #include @@ -66,8 +65,6 @@ struct _GstGtkSink gboolean ignore_alpha; GBinding *bind_ignore_alpha; - - GstGtkSinkPrivate *priv; }; /** From 8d9fbc5e49241e109a10c4e52ebeb90422d6cb02 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 15 Jul 2015 11:47:51 -0400 Subject: [PATCH 059/128] gtkgstwidget: Add missing break in get_property --- ext/gtk/gtkgstwidget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/gtk/gtkgstwidget.c b/ext/gtk/gtkgstwidget.c index e232eebe88..3e2f9bb286 100644 --- a/ext/gtk/gtkgstwidget.c +++ b/ext/gtk/gtkgstwidget.c @@ -265,6 +265,7 @@ gtk_gst_widget_get_property (GObject * object, guint prop_id, GValue * value, case PROP_PIXEL_ASPECT_RATIO: gst_value_set_fraction (value, gtk_widget->priv->par_n, gtk_widget->priv->par_d); + break; case PROP_IGNORE_ALPHA: g_value_set_boolean (value, gtk_widget->priv->ignore_alpha); break; From 1a7c9b82f4dd17a55da8a383c59b43ed06e23b85 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 15 Jul 2015 14:32:42 -0400 Subject: [PATCH 060/128] gtk: Fix race between queue_draw and destroy In GTK dispose can be called before the last ref is reached. This happens when you close the container window. The dispose will be explicitly called, and destroyed notify will be fired. This patch fixes this race by properly tracking the widget state. In the sink, we now set the widget pointer to NULL, so the widget will properly get created again if you set your pipeline to NULL state after the widget was destroy, and set it back to PLAYING. https://bugzilla.gnome.org/show_bug.cgi?id=751104 --- ext/gtk/gstgtkglsink.c | 18 +++++++++++++---- ext/gtk/gstgtkglsink.h | 1 - ext/gtk/gstgtksink.c | 19 +++++++++++++++--- ext/gtk/gtkgstglwidget.c | 43 ++++++++++++++++++++++++++++------------ ext/gtk/gtkgstwidget.c | 38 ++++++++++++++++++++++++++--------- 5 files changed, 89 insertions(+), 30 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 1a98c02213..cbb0e948bb 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -164,7 +164,9 @@ gst_gtk_gl_sink_finalize (GObject * object) static void widget_destroy_cb (GtkWidget * widget, GstGtkGLSink * gtk_sink) { - g_atomic_int_set (>k_sink->widget_destroyed, 1); + GST_OBJECT_LOCK (gtk_sink); + g_clear_object (>k_sink->widget); + GST_OBJECT_UNLOCK (gtk_sink); } static GtkGstGLWidget * @@ -367,7 +369,10 @@ gst_gtk_gl_sink_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: - gtk_gst_gl_widget_set_buffer (gtk_sink->widget, NULL); + GST_OBJECT_LOCK (gtk_sink); + if (gtk_sink->widget) + gtk_gst_gl_widget_set_buffer (gtk_sink->widget, NULL); + GST_OBJECT_UNLOCK (gtk_sink); break; case GST_STATE_CHANGE_READY_TO_NULL: if (gtk_sink->display) { @@ -440,14 +445,19 @@ gst_gtk_gl_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) gtk_sink = GST_GTK_GL_SINK (vsink); - gtk_gst_gl_widget_set_buffer (gtk_sink->widget, buf); + GST_OBJECT_LOCK (vsink); - if (g_atomic_int_get (>k_sink->widget_destroyed)) { + 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_gl_widget_set_buffer (gtk_sink->widget, buf); + + GST_OBJECT_UNLOCK (vsink); + return GST_FLOW_OK; } diff --git a/ext/gtk/gstgtkglsink.h b/ext/gtk/gstgtkglsink.h index d1c65c00a8..985486fb24 100644 --- a/ext/gtk/gstgtkglsink.h +++ b/ext/gtk/gstgtkglsink.h @@ -53,7 +53,6 @@ struct _GstGtkGLSink GstVideoSink parent; GtkGstGLWidget *widget; - gboolean widget_destroyed; GstVideoInfo v_info; GstBufferPool *pool; diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index 2c5d3ed3eb..524ff5ab6c 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -294,7 +294,10 @@ gst_gtk_sink_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: - gtk_gst_widget_set_buffer (gtk_sink->widget, NULL); + GST_OBJECT_LOCK (gtk_sink); + if (gtk_sink->widget) + gtk_gst_widget_set_buffer (gtk_sink->widget, NULL); + GST_OBJECT_UNLOCK (gtk_sink); break; case GST_STATE_CHANGE_READY_TO_NULL: break; @@ -353,8 +356,18 @@ gst_gtk_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) gtk_sink = GST_GTK_SINK (vsink); - if (gtk_sink->widget) - gtk_gst_widget_set_buffer (gtk_sink->widget, buf); + 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_widget_set_buffer (gtk_sink->widget, buf); + + GST_OBJECT_UNLOCK (vsink); return GST_FLOW_OK; } diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 2e108c9f93..3d05d37b7d 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -100,6 +100,10 @@ struct _GtkGstGLWidgetPrivate GLint attr_position; GLint attr_texture; GLuint current_tex; + + /* Pending queued idles callback */ + guint draw_id; + guint resize_id; }; static void @@ -430,15 +434,17 @@ gtk_gst_gl_widget_finalize (GObject * object) _invoke_on_main ((ThreadFunc) _reset_gl, widget); } - if (widget->priv->context) { + if (widget->priv->context) gst_object_unref (widget->priv->context); - widget->priv->context = NULL; - } - if (widget->priv->display) { + if (widget->priv->display) gst_object_unref (widget->priv->display); - widget->priv->display = NULL; - } + + if (widget->priv->draw_id) + g_source_remove (widget->priv->draw_id); + + if (widget->priv->resize_id) + g_source_remove (widget->priv->resize_id); G_OBJECT_CLASS (gtk_gst_gl_widget_parent_class)->finalize (object); } @@ -575,6 +581,10 @@ gtk_gst_gl_widget_new (void) static gboolean _queue_draw (GtkGstGLWidget * widget) { + g_mutex_lock (&widget->priv->lock); + widget->priv->draw_id = 0; + g_mutex_unlock (&widget->priv->lock); + gtk_widget_queue_draw (GTK_WIDGET (widget)); return G_SOURCE_REMOVE; @@ -583,8 +593,6 @@ _queue_draw (GtkGstGLWidget * widget) void gtk_gst_gl_widget_set_buffer (GtkGstGLWidget * widget, GstBuffer * buffer) { - GMainContext *main_context = g_main_context_default (); - g_return_if_fail (GTK_IS_GST_GL_WIDGET (widget)); g_return_if_fail (buffer == NULL || widget->priv->negotiated); @@ -593,9 +601,12 @@ gtk_gst_gl_widget_set_buffer (GtkGstGLWidget * widget, GstBuffer * buffer) gst_buffer_replace (&widget->priv->buffer, buffer); widget->priv->new_buffer = TRUE; - g_mutex_unlock (&widget->priv->lock); + if (!widget->priv->draw_id) { + widget->priv->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT, + (GSourceFunc) _queue_draw, widget, NULL); + } - g_main_context_invoke (main_context, (GSourceFunc) _queue_draw, widget); + g_mutex_unlock (&widget->priv->lock); } static void @@ -664,6 +675,10 @@ _get_gl_context (GtkGstGLWidget * gst_widget) static gboolean _queue_resize (GtkGstGLWidget * widget) { + g_mutex_lock (&widget->priv->lock); + widget->priv->resize_id = 0; + g_mutex_unlock (&widget->priv->lock); + gtk_widget_queue_resize (GTK_WIDGET (widget)); return G_SOURCE_REMOVE; @@ -770,7 +785,6 @@ _calculate_par (GtkGstGLWidget * widget, GstVideoInfo * info) gboolean gtk_gst_gl_widget_set_caps (GtkGstGLWidget * widget, GstCaps * caps) { - GMainContext *main_context = g_main_context_default (); GstVideoInfo v_info; g_return_val_if_fail (GTK_IS_GST_GL_WIDGET (widget), FALSE); @@ -801,9 +815,12 @@ gtk_gst_gl_widget_set_caps (GtkGstGLWidget * widget, GstCaps * caps) widget->priv->v_info = v_info; widget->priv->negotiated = TRUE; - g_mutex_unlock (&widget->priv->lock); + if (!widget->priv->resize_id) { + widget->priv->resize_id = g_idle_add_full (G_PRIORITY_DEFAULT, + (GSourceFunc) _queue_resize, widget, NULL); + } - g_main_context_invoke (main_context, (GSourceFunc) _queue_resize, widget); + g_mutex_unlock (&widget->priv->lock); return TRUE; } diff --git a/ext/gtk/gtkgstwidget.c b/ext/gtk/gtkgstwidget.c index 3e2f9bb286..3fbb0ca4ed 100644 --- a/ext/gtk/gtkgstwidget.c +++ b/ext/gtk/gtkgstwidget.c @@ -69,6 +69,10 @@ struct _GtkGstWidgetPrivate GstBuffer *buffer; GstCaps *caps; GstVideoInfo v_info; + + /* Pending queued idles callback */ + guint draw_id; + guint resize_id; }; static void @@ -226,6 +230,12 @@ gtk_gst_widget_finalize (GObject * object) gst_buffer_replace (&widget->priv->buffer, NULL); g_mutex_clear (&widget->priv->lock); + if (widget->priv->draw_id) + g_source_remove (widget->priv->draw_id); + + if (widget->priv->resize_id) + g_source_remove (widget->priv->resize_id); + G_OBJECT_CLASS (gtk_gst_widget_parent_class)->finalize (object); } @@ -331,6 +341,10 @@ gtk_gst_widget_new (void) static gboolean _queue_draw (GtkGstWidget * widget) { + g_mutex_lock (&widget->priv->lock); + widget->priv->draw_id = 0; + g_mutex_unlock (&widget->priv->lock); + gtk_widget_queue_draw (GTK_WIDGET (widget)); return G_SOURCE_REMOVE; @@ -339,8 +353,6 @@ _queue_draw (GtkGstWidget * widget) void gtk_gst_widget_set_buffer (GtkGstWidget * widget, GstBuffer * buffer) { - GMainContext *main_context = g_main_context_default (); - g_return_if_fail (GTK_IS_GST_WIDGET (widget)); g_return_if_fail (buffer == NULL || widget->priv->negotiated); @@ -348,14 +360,21 @@ gtk_gst_widget_set_buffer (GtkGstWidget * widget, GstBuffer * buffer) gst_buffer_replace (&widget->priv->buffer, buffer); - g_mutex_unlock (&widget->priv->lock); + if (!widget->priv->draw_id) { + widget->priv->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT, + (GSourceFunc) _queue_draw, widget, NULL); + } - g_main_context_invoke (main_context, (GSourceFunc) _queue_draw, widget); + g_mutex_unlock (&widget->priv->lock); } static gboolean _queue_resize (GtkGstWidget * widget) { + g_mutex_lock (&widget->priv->lock); + widget->priv->resize_id = 0; + g_mutex_unlock (&widget->priv->lock); + gtk_widget_queue_resize (GTK_WIDGET (widget)); return G_SOURCE_REMOVE; @@ -424,7 +443,6 @@ _calculate_par (GtkGstWidget * widget, GstVideoInfo * info) gboolean gtk_gst_widget_set_caps (GtkGstWidget * widget, GstCaps * caps) { - GMainContext *main_context = g_main_context_default (); GstVideoInfo v_info; g_return_val_if_fail (GTK_IS_GST_WIDGET (widget), FALSE); @@ -455,15 +473,17 @@ gtk_gst_widget_set_caps (GtkGstWidget * widget, GstCaps * caps) return FALSE; } + gst_buffer_replace (&widget->priv->buffer, NULL); gst_caps_replace (&widget->priv->caps, caps); widget->priv->v_info = v_info; widget->priv->negotiated = TRUE; + if (!widget->priv->resize_id) { + widget->priv->resize_id = g_idle_add_full (G_PRIORITY_DEFAULT, + (GSourceFunc) _queue_resize, widget, NULL); + } + g_mutex_unlock (&widget->priv->lock); - gtk_widget_queue_resize (GTK_WIDGET (widget)); - - g_main_context_invoke (main_context, (GSourceFunc) _queue_resize, widget); - return TRUE; } From 999bdd72c924a09c76ce6553f1fdb9fcb4f83dd6 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 15 Jul 2015 14:35:02 -0400 Subject: [PATCH 061/128] gtksink: Ensure the copy pasted code remains the same Move back the default property at the same place they are in the other sink. This helps when using a diff viewer to synchronized this unfortunate copy paste. https://bugzilla.gnome.org/show_bug.cgi?id=751104 --- ext/gtk/gstgtksink.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index 524ff5ab6c..215ea937bb 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -32,6 +32,11 @@ GST_DEBUG_CATEGORY (gst_debug_gtk_sink); #define GST_CAT_DEFAULT gst_debug_gtk_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_sink_finalize (GObject * object); static void gst_gtk_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * param_spec); @@ -64,11 +69,6 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (FORMATS)) ); -#define DEFAULT_FORCE_ASPECT_RATIO TRUE -#define DEFAULT_PAR_N 0 -#define DEFAULT_PAR_D 1 -#define DEFAULT_IGNORE_ALPHA TRUE - enum { PROP_0, From d43e3e693c29534d84997aa857f1152567212da4 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 15 Jul 2015 16:56:33 -0400 Subject: [PATCH 062/128] gtksink: Create a window if the widget is unparented The same way as it's now done with the gtkglsink, create a top level window if the widget is not parented. https://bugzilla.gnome.org/show_bug.cgi?id=751104 --- ext/gtk/gstgtksink.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index 215ea937bb..9c442e39a2 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -159,11 +159,19 @@ gst_gtk_sink_finalize (GObject * object) { GstGtkSink *gtk_sink = GST_GTK_SINK (object);; - g_object_unref (gtk_sink->widget); + g_clear_object (>k_sink->widget); G_OBJECT_CLASS (parent_class)->finalize (object); } +static void +widget_destroy_cb (GtkWidget * widget, GstGtkSink * gtk_sink) +{ + GST_OBJECT_LOCK (gtk_sink); + g_clear_object (>k_sink->widget); + GST_OBJECT_UNLOCK (gtk_sink); +} + static GtkGstWidget * gst_gtk_sink_get_widget (GstGtkSink * gtk_sink) { @@ -191,6 +199,8 @@ gst_gtk_sink_get_widget (GstGtkSink * gtk_sink) /* Take the floating ref, other wise 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; } @@ -268,6 +278,7 @@ gst_gtk_sink_change_state (GstElement * element, GstStateChange transition) { GstGtkSink *gtk_sink = GST_GTK_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)), @@ -277,6 +288,22 @@ gst_gtk_sink_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_NULL_TO_READY: if (gst_gtk_sink_get_widget (gtk_sink) == NULL) return GST_STATE_CHANGE_FAILURE; + + /* After this point, gtk_sink->widget will always be set */ + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (gtk_sink->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+ Cairo renderer"); + gtk_container_add (GTK_CONTAINER (window), toplevel); + gtk_widget_show_all (window); + } + break; case GST_STATE_CHANGE_READY_TO_PAUSED: break; From 5243f5678db4f526b5b4dd4c89578c4cdaa411d3 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 15 Jul 2015 17:35:22 -0400 Subject: [PATCH 063/128] gtkgstglwidget: Remove unused gl_caps --- ext/gtk/gtkgstglwidget.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 3d05d37b7d..67993f24b9 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -83,7 +83,6 @@ struct _GtkGstGLWidgetPrivate gboolean negotiated; GstBuffer *buffer; - GstCaps *gl_caps; GstCaps *caps; GstVideoInfo v_info; gboolean new_buffer; @@ -409,7 +408,6 @@ _reset (GtkGstGLWidget * gst_widget) gst_buffer_replace (&gst_widget->priv->buffer, NULL); gst_caps_replace (&gst_widget->priv->caps, NULL); - gst_caps_replace (&gst_widget->priv->gl_caps, NULL); gst_widget->priv->negotiated = FALSE; gst_widget->priv->initted = FALSE; @@ -803,10 +801,6 @@ gtk_gst_gl_widget_set_caps (GtkGstGLWidget * widget, GstCaps * caps) gst_caps_replace (&widget->priv->caps, caps); - widget->priv->gl_caps = gst_video_info_to_caps (&v_info); - gst_caps_set_features (widget->priv->gl_caps, 0, - gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY)); - if (!_calculate_par (widget, &v_info)) { g_mutex_unlock (&widget->priv->lock); return FALSE; From 688e5dd7c4af42dbd498263f7fb47c09a580d478 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 16 Jul 2015 12:51:34 -0400 Subject: [PATCH 064/128] gtk: Add GtkGstBaseWidget This is a "pseudo" base class. Basically it's a shared instance and class structure and a shared set of function between the two widget. It cannot have it's own type like normal base class since the one instance will implement GtkGLArea while the other implements GtkDrawingAreay. To workaround this, the parent instance and class is a union of both. https://bugzilla.gnome.org/show_bug.cgi?id=752441 --- ext/gtk/Makefile.am | 2 + ext/gtk/gtkgstbasewidget.c | 318 +++++++++++++++++++++++++++++++++++++ ext/gtk/gtkgstbasewidget.h | 94 +++++++++++ 3 files changed, 414 insertions(+) create mode 100644 ext/gtk/gtkgstbasewidget.c create mode 100644 ext/gtk/gtkgstbasewidget.h diff --git a/ext/gtk/Makefile.am b/ext/gtk/Makefile.am index 45d0be0d28..58b4e3f965 100644 --- a/ext/gtk/Makefile.am +++ b/ext/gtk/Makefile.am @@ -8,6 +8,8 @@ lib_LTLIBRARIES = # source sources = \ + gtkgstbasewidget.c \ + gtkgstbasewidget.h \ gtkgstwidget.c \ gtkgstwidget.h \ gstgtksink.c \ diff --git a/ext/gtk/gtkgstbasewidget.c b/ext/gtk/gtkgstbasewidget.c new file mode 100644 index 0000000000..972541ff7a --- /dev/null +++ b/ext/gtk/gtkgstbasewidget.c @@ -0,0 +1,318 @@ +/* + * GStreamer + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "gtkgstbasewidget.h" + +#define DEFAULT_FORCE_ASPECT_RATIO TRUE +#define DEFAULT_PAR_N 0 +#define DEFAULT_PAR_D 1 +#define DEFAULT_IGNORE_ALPHA TRUE + +enum +{ + PROP_0, + PROP_FORCE_ASPECT_RATIO, + PROP_PIXEL_ASPECT_RATIO, + PROP_IGNORE_ALPHA, +}; + +static void +gtk_gst_base_widget_get_preferred_width (GtkWidget * widget, gint * min, + gint * natural) +{ + GtkGstBaseWidget *gst_widget = (GtkGstBaseWidget *) widget; + gint video_width = gst_widget->display_width; + + if (!gst_widget->negotiated) + video_width = 10; + + if (min) + *min = 1; + if (natural) + *natural = video_width; +} + +static void +gtk_gst_base_widget_get_preferred_height (GtkWidget * widget, gint * min, + gint * natural) +{ + GtkGstBaseWidget *gst_widget = (GtkGstBaseWidget *) widget; + gint video_height = gst_widget->display_height; + + if (!gst_widget->negotiated) + video_height = 10; + + if (min) + *min = 1; + if (natural) + *natural = video_height; +} + +static void +gtk_gst_base_widget_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GtkGstBaseWidget *gtk_widget = GTK_GST_BASE_WIDGET (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + gtk_widget->force_aspect_ratio = g_value_get_boolean (value); + break; + case PROP_PIXEL_ASPECT_RATIO: + gtk_widget->par_n = gst_value_get_fraction_numerator (value); + gtk_widget->par_d = gst_value_get_fraction_denominator (value); + break; + case PROP_IGNORE_ALPHA: + gtk_widget->ignore_alpha = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_gst_base_widget_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GtkGstBaseWidget *gtk_widget = GTK_GST_BASE_WIDGET (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + g_value_set_boolean (value, gtk_widget->force_aspect_ratio); + break; + case PROP_PIXEL_ASPECT_RATIO: + gst_value_set_fraction (value, gtk_widget->par_n, gtk_widget->par_d); + break; + case PROP_IGNORE_ALPHA: + g_value_set_boolean (value, gtk_widget->ignore_alpha); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +_queue_resize (GtkGstBaseWidget * widget) +{ + GTK_GST_BASE_WIDGET_LOCK (widget); + widget->resize_id = 0; + + GTK_GST_BASE_WIDGET_UNLOCK (widget); + + gtk_widget_queue_resize (GTK_WIDGET (widget)); + + return G_SOURCE_REMOVE; +} + +static gboolean +_calculate_par (GtkGstBaseWidget * widget, GstVideoInfo * info) +{ + gboolean ok; + gint width, height; + gint par_n, par_d; + gint display_par_n, display_par_d; + guint display_ratio_num, display_ratio_den; + + width = GST_VIDEO_INFO_WIDTH (info); + height = GST_VIDEO_INFO_HEIGHT (info); + + par_n = GST_VIDEO_INFO_PAR_N (info); + par_d = GST_VIDEO_INFO_PAR_D (info); + + if (!par_n) + par_n = 1; + + /* get display's PAR */ + if (widget->par_n != 0 && widget->par_d != 0) { + display_par_n = widget->par_n; + display_par_d = widget->par_d; + } else { + display_par_n = 1; + display_par_d = 1; + } + + ok = gst_video_calculate_display_ratio (&display_ratio_num, + &display_ratio_den, width, height, par_n, par_d, display_par_n, + display_par_d); + + if (!ok) + return FALSE; + + GST_LOG ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n, display_par_d); + + if (height % display_ratio_den == 0) { + GST_DEBUG ("keeping video height"); + widget->display_width = (guint) + gst_util_uint64_scale_int (height, display_ratio_num, + display_ratio_den); + widget->display_height = height; + } else if (width % display_ratio_num == 0) { + GST_DEBUG ("keeping video width"); + widget->display_width = width; + widget->display_height = (guint) + gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num); + } else { + GST_DEBUG ("approximating while keeping video height"); + widget->display_width = (guint) + gst_util_uint64_scale_int (height, display_ratio_num, + display_ratio_den); + widget->display_height = height; + } + + GST_DEBUG ("scaling to %dx%d", widget->display_width, widget->display_height); + + return TRUE; +} + +static gboolean +_queue_draw (GtkGstBaseWidget * widget) +{ + GTK_GST_BASE_WIDGET_LOCK (widget); + widget->draw_id = 0; + GTK_GST_BASE_WIDGET_UNLOCK (widget); + + gtk_widget_queue_draw (GTK_WIDGET (widget)); + + return G_SOURCE_REMOVE; +} + +void +gtk_gst_base_widget_class_init (GtkGstBaseWidgetClass * klass) +{ + GObjectClass *gobject_klass = (GObjectClass *) klass; + GtkWidgetClass *widget_klass = (GtkWidgetClass *) klass; + + gobject_klass->set_property = gtk_gst_base_widget_set_property; + gobject_klass->get_property = gtk_gst_base_widget_get_property; + + g_object_class_install_property (gobject_klass, 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_klass, 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_klass, 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)); + + widget_klass->get_preferred_width = gtk_gst_base_widget_get_preferred_width; + widget_klass->get_preferred_height = gtk_gst_base_widget_get_preferred_height; +} + +void +gtk_gst_base_widget_init (GtkGstBaseWidget * widget) +{ + widget->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; + widget->par_n = DEFAULT_PAR_N; + widget->par_d = DEFAULT_PAR_D; + widget->ignore_alpha = DEFAULT_IGNORE_ALPHA; + + g_mutex_init (&widget->lock); +} + +void +gtk_gst_base_widget_finalize (GObject * object) +{ + GtkGstBaseWidget *widget = GTK_GST_BASE_WIDGET (object); + + gst_buffer_replace (&widget->buffer, NULL); + g_mutex_clear (&widget->lock); + + if (widget->draw_id) + g_source_remove (widget->draw_id); + + if (widget->resize_id) + g_source_remove (widget->resize_id); +} + +gboolean +gtk_gst_base_widget_set_caps (GtkGstBaseWidget * widget, GstCaps * caps) +{ + GstVideoInfo v_info; + + if (widget->caps && gst_caps_is_equal_fixed (widget->caps, caps)) + return TRUE; + + if (!gst_video_info_from_caps (&v_info, caps)) + return FALSE; + + GTK_GST_BASE_WIDGET_LOCK (widget); + + /* FIXME this will cause black frame to be displayed, move this in the + * _queue_resize callback passing over the video info */ + + if (!_calculate_par (widget, &v_info)) { + GTK_GST_BASE_WIDGET_UNLOCK (widget); + return FALSE; + } + + if (widget->reset) + widget->reset (widget); + + gst_buffer_replace (&widget->buffer, NULL); + gst_caps_replace (&widget->caps, caps); + widget->v_info = v_info; + widget->negotiated = TRUE; + widget->new_buffer = TRUE; + + if (!widget->resize_id) { + widget->resize_id = g_idle_add_full (G_PRIORITY_DEFAULT, + (GSourceFunc) _queue_resize, widget, NULL); + } + + GTK_GST_BASE_WIDGET_UNLOCK (widget); + + return TRUE; +} + +void +gtk_gst_base_widget_set_buffer (GtkGstBaseWidget * widget, GstBuffer * buffer) +{ + /* As we have no type, this is better then no check */ + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (buffer == NULL || widget->negotiated); + + GTK_GST_BASE_WIDGET_LOCK (widget); + + gst_buffer_replace (&widget->buffer, buffer); + widget->new_buffer = TRUE; + + if (!widget->draw_id) { + widget->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT, + (GSourceFunc) _queue_draw, widget, NULL); + } + + GTK_GST_BASE_WIDGET_UNLOCK (widget); +} diff --git a/ext/gtk/gtkgstbasewidget.h b/ext/gtk/gtkgstbasewidget.h new file mode 100644 index 0000000000..e4242f192a --- /dev/null +++ b/ext/gtk/gtkgstbasewidget.h @@ -0,0 +1,94 @@ +/* + * GStreamer + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GTK_GST_BASE_WIDGET_H__ +#define __GTK_GST_BASE_WIDGET_H__ + +#include +#include +#include + +#define GTK_GST_BASE_WIDGET(w) ((GtkGstBaseWidget *)(w)) +#define GTK_GST_BASE_WIDGET_CLASS(k) ((GtkGstBaseWidgetClass *)(k)) +#define GTK_GST_BASE_WIDGET_LOCK(w) g_mutex_lock(&((GtkGstBaseWidget*)(w))->lock) +#define GTK_GST_BASE_WIDGET_UNLOCK(w) g_mutex_unlock(&((GtkGstBaseWidget*)(w))->lock) + +G_BEGIN_DECLS + +typedef struct _GtkGstBaseWidget GtkGstBaseWidget; +typedef struct _GtkGstBaseWidgetClass GtkGstBaseWidgetClass; + +struct _GtkGstBaseWidget +{ + union { + GtkDrawingArea drawing_area; +#if GTK_CHECK_VERSION(3, 15, 0) + GtkGLArea gl_area; +#endif + } parent; + + /* properties */ + gboolean force_aspect_ratio; + gint par_n, par_d; + gboolean ignore_alpha; + + gint display_width; + gint display_height; + + gboolean negotiated; + GstBuffer *buffer; + GstVideoInfo v_info; + gboolean new_buffer; + + /* Poor-man virtual */ + void (*reset) (GtkGstBaseWidget * widget); + + /*< private >*/ + GMutex lock; + GstCaps *caps; + + /* Pending queued idles callback */ + guint draw_id; + guint resize_id; +}; + +struct _GtkGstBaseWidgetClass +{ + union { + GtkDrawingAreaClass drawing_area_class; +#if GTK_CHECK_VERSION(3, 15, 0) + GtkGLAreaClass gl_area_class; +#endif + } parent_class; +}; + +/* For implementer */ +void gtk_gst_base_widget_class_init (GtkGstBaseWidgetClass * klass); +void gtk_gst_base_widget_init (GtkGstBaseWidget * widget); + +void gtk_gst_base_widget_finalize (GObject * object); + +/* API */ +gboolean gtk_gst_base_widget_set_caps (GtkGstBaseWidget * widget, GstCaps *caps); +void gtk_gst_base_widget_set_buffer (GtkGstBaseWidget * widget, GstBuffer *buffer); + +G_END_DECLS + +#endif /* __GTK_GST_BASE_WIDGET_H__ */ From 3ad1088ef385038ff117e027e7080d65d3a09464 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 16 Jul 2015 12:55:11 -0400 Subject: [PATCH 065/128] gtksink: Port to GtkGstBaseWidget https://bugzilla.gnome.org/show_bug.cgi?id=752441 --- ext/gtk/gstgtksink.c | 25 ++- ext/gtk/gstgtksink.h | 2 +- ext/gtk/gtkgstwidget.c | 346 +++-------------------------------------- ext/gtk/gtkgstwidget.h | 12 +- 4 files changed, 42 insertions(+), 343 deletions(-) diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index 9c442e39a2..c171c604a2 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -172,7 +172,7 @@ widget_destroy_cb (GtkWidget * widget, GstGtkSink * gtk_sink) GST_OBJECT_UNLOCK (gtk_sink); } -static GtkGstWidget * +static GtkGstBaseWidget * gst_gtk_sink_get_widget (GstGtkSink * gtk_sink) { if (gtk_sink->widget != NULL) @@ -185,7 +185,7 @@ gst_gtk_sink_get_widget (GstGtkSink * gtk_sink) return NULL; } - gtk_sink->widget = (GtkGstWidget *) gtk_gst_widget_new (); + gtk_sink->widget = (GtkGstBaseWidget *) gtk_gst_widget_new (); gtk_sink->bind_aspect_ratio = g_object_bind_property (gtk_sink, "force-aspect-ratio", gtk_sink->widget, "force-aspect-ratio", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); @@ -323,7 +323,7 @@ gst_gtk_sink_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_PAUSED_TO_READY: GST_OBJECT_LOCK (gtk_sink); if (gtk_sink->widget) - gtk_gst_widget_set_buffer (gtk_sink->widget, NULL); + gtk_gst_base_widget_set_buffer (gtk_sink->widget, NULL); GST_OBJECT_UNLOCK (gtk_sink); break; case GST_STATE_CHANGE_READY_TO_NULL: @@ -368,8 +368,19 @@ gst_gtk_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) if (!gst_video_info_from_caps (>k_sink->v_info, caps)) return FALSE; - if (!gtk_gst_widget_set_caps (gtk_sink->widget, caps)) + 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_gst_base_widget_set_caps (gtk_sink->widget, caps)) + return FALSE; + + GST_OBJECT_UNLOCK (gtk_sink); return TRUE; } @@ -386,15 +397,15 @@ gst_gtk_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) GST_OBJECT_LOCK (vsink); if (gtk_sink->widget == NULL) { - GST_OBJECT_UNLOCK (vsink); + GST_OBJECT_UNLOCK (gtk_sink); GST_ELEMENT_ERROR (gtk_sink, RESOURCE, NOT_FOUND, ("%s", "Output widget was destroyed"), (NULL)); return GST_FLOW_ERROR; } - gtk_gst_widget_set_buffer (gtk_sink->widget, buf); + gtk_gst_base_widget_set_buffer (gtk_sink->widget, buf); - GST_OBJECT_UNLOCK (vsink); + GST_OBJECT_UNLOCK (gtk_sink); return GST_FLOW_OK; } diff --git a/ext/gtk/gstgtksink.h b/ext/gtk/gstgtksink.h index f7b6ba7506..40eaa948d0 100644 --- a/ext/gtk/gstgtksink.h +++ b/ext/gtk/gstgtksink.h @@ -53,7 +53,7 @@ struct _GstGtkSink GstVideoInfo v_info; - GtkGstWidget *widget; + GtkGstBaseWidget *widget; /* properties */ gboolean force_aspect_ratio; diff --git a/ext/gtk/gtkgstwidget.c b/ext/gtk/gtkgstwidget.c index 3fbb0ca4ed..58326d76f9 100644 --- a/ext/gtk/gtkgstwidget.c +++ b/ext/gtk/gtkgstwidget.c @@ -37,80 +37,10 @@ G_DEFINE_TYPE (GtkGstWidget, gtk_gst_widget, GTK_TYPE_DRAWING_AREA); -#define GTK_GST_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ - GTK_TYPE_GST_WIDGET, GtkGstWidgetPrivate)) - -#define DEFAULT_FORCE_ASPECT_RATIO TRUE -#define DEFAULT_PAR_N 0 -#define DEFAULT_PAR_D 1 -#define DEFAULT_IGNORE_ALPHA TRUE - -enum -{ - PROP_0, - PROP_FORCE_ASPECT_RATIO, - PROP_PIXEL_ASPECT_RATIO, - PROP_IGNORE_ALPHA, -}; - -struct _GtkGstWidgetPrivate -{ - GMutex lock; - - /* properties */ - gboolean force_aspect_ratio; - gint par_n, par_d; - gboolean ignore_alpha; - - gint display_width; - gint display_height; - - gboolean negotiated; - GstBuffer *buffer; - GstCaps *caps; - GstVideoInfo v_info; - - /* Pending queued idles callback */ - guint draw_id; - guint resize_id; -}; - -static void -gtk_gst_widget_get_preferred_width (GtkWidget * widget, gint * min, - gint * natural) -{ - GtkGstWidget *gst_widget = (GtkGstWidget *) widget; - gint video_width = gst_widget->priv->display_width; - - if (!gst_widget->priv->negotiated) - video_width = 10; - - if (min) - *min = 1; - if (natural) - *natural = video_width; -} - -static void -gtk_gst_widget_get_preferred_height (GtkWidget * widget, gint * min, - gint * natural) -{ - GtkGstWidget *gst_widget = (GtkGstWidget *) widget; - gint video_height = gst_widget->priv->display_height; - - if (!gst_widget->priv->negotiated) - video_height = 10; - - if (min) - *min = 1; - if (natural) - *natural = video_height; -} - static gboolean gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) { - GtkGstWidget *gst_widget = (GtkGstWidget *) widget; + GtkGstBaseWidget *gst_widget = (GtkGstBaseWidget *) widget; guint widget_width, widget_height; cairo_surface_t *surface; GstVideoFrame frame; @@ -118,19 +48,18 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) widget_width = gtk_widget_get_allocated_width (widget); widget_height = gtk_widget_get_allocated_height (widget); - g_mutex_lock (&gst_widget->priv->lock); + GTK_GST_BASE_WIDGET_LOCK (gst_widget); /* failed to map the video frame */ - if (gst_widget->priv->negotiated && gst_widget->priv->buffer - && gst_video_frame_map (&frame, &gst_widget->priv->v_info, - gst_widget->priv->buffer, GST_MAP_READ)) { - gdouble scale_x = (gdouble) widget_width / gst_widget->priv->display_width; - gdouble scale_y = - (gdouble) widget_height / gst_widget->priv->display_height; + if (gst_widget->negotiated && gst_widget->buffer + && gst_video_frame_map (&frame, &gst_widget->v_info, + gst_widget->buffer, GST_MAP_READ)) { + gdouble scale_x = (gdouble) widget_width / gst_widget->display_width; + gdouble scale_y = (gdouble) widget_height / gst_widget->display_height; GstVideoRectangle result; cairo_format_t format; - gst_widget->priv->v_info = frame.info; + gst_widget->v_info = frame.info; if (frame.info.finfo->format == GST_VIDEO_FORMAT_ARGB || frame.info.finfo->format == GST_VIDEO_FORMAT_BGRA) { format = CAIRO_FORMAT_ARGB32; @@ -141,13 +70,13 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) surface = cairo_image_surface_create_for_data (frame.data[0], format, frame.info.width, frame.info.height, frame.info.stride[0]); - if (gst_widget->priv->force_aspect_ratio) { + if (gst_widget->force_aspect_ratio) { GstVideoRectangle src, dst; src.x = 0; src.y = 0; - src.w = gst_widget->priv->display_width; - src.h = gst_widget->priv->display_height; + src.w = gst_widget->display_width; + src.h = gst_widget->display_height; dst.x = 0; dst.y = 0; @@ -164,7 +93,7 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) result.h = widget_height; } - if (gst_widget->priv->ignore_alpha) { + if (gst_widget->ignore_alpha) { GdkRGBA color = { 0.0, 0.0, 0.0, 1.0 }; gdk_cairo_set_source_rgba (cr, &color); @@ -188,11 +117,9 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) } } - scale_x *= - (gdouble) gst_widget->priv->display_width / (gdouble) frame.info.width; + scale_x *= (gdouble) gst_widget->display_width / (gdouble) frame.info.width; scale_y *= - (gdouble) gst_widget->priv->display_height / - (gdouble) frame.info.height; + (gdouble) gst_widget->display_height / (gdouble) frame.info.height; cairo_translate (cr, result.x, result.y); cairo_scale (cr, scale_x, scale_y); @@ -206,7 +133,7 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) } else { GdkRGBA color; - if (gst_widget->priv->ignore_alpha) { + if (gst_widget->ignore_alpha) { color.red = color.blue = color.green = 0.0; color.alpha = 1.0; } else { @@ -218,118 +145,33 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) cairo_fill (cr); } - g_mutex_unlock (&gst_widget->priv->lock); + GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); return FALSE; } static void gtk_gst_widget_finalize (GObject * object) { - GtkGstWidget *widget = GTK_GST_WIDGET_CAST (object); - - gst_buffer_replace (&widget->priv->buffer, NULL); - g_mutex_clear (&widget->priv->lock); - - if (widget->priv->draw_id) - g_source_remove (widget->priv->draw_id); - - if (widget->priv->resize_id) - g_source_remove (widget->priv->resize_id); + gtk_gst_base_widget_finalize (object); G_OBJECT_CLASS (gtk_gst_widget_parent_class)->finalize (object); } -static void -gtk_gst_widget_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GtkGstWidget *gtk_widget = GTK_GST_WIDGET (object); - - switch (prop_id) { - case PROP_FORCE_ASPECT_RATIO: - gtk_widget->priv->force_aspect_ratio = g_value_get_boolean (value); - break; - case PROP_PIXEL_ASPECT_RATIO: - gtk_widget->priv->par_n = gst_value_get_fraction_numerator (value); - gtk_widget->priv->par_d = gst_value_get_fraction_denominator (value); - break; - case PROP_IGNORE_ALPHA: - gtk_widget->priv->ignore_alpha = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gtk_gst_widget_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GtkGstWidget *gtk_widget = GTK_GST_WIDGET (object); - - switch (prop_id) { - case PROP_FORCE_ASPECT_RATIO: - g_value_set_boolean (value, gtk_widget->priv->force_aspect_ratio); - break; - case PROP_PIXEL_ASPECT_RATIO: - gst_value_set_fraction (value, gtk_widget->priv->par_n, - gtk_widget->priv->par_d); - break; - case PROP_IGNORE_ALPHA: - g_value_set_boolean (value, gtk_widget->priv->ignore_alpha); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - static void gtk_gst_widget_class_init (GtkGstWidgetClass * klass) { GObjectClass *gobject_klass = (GObjectClass *) klass; GtkWidgetClass *widget_klass = (GtkWidgetClass *) klass; - g_type_class_add_private (klass, sizeof (GtkGstWidgetPrivate)); - - gobject_klass->set_property = gtk_gst_widget_set_property; - gobject_klass->get_property = gtk_gst_widget_get_property; + gtk_gst_base_widget_class_init (GTK_GST_BASE_WIDGET_CLASS (klass)); gobject_klass->finalize = gtk_gst_widget_finalize; - - g_object_class_install_property (gobject_klass, 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_klass, 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_klass, 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)); - widget_klass->draw = gtk_gst_widget_draw; - widget_klass->get_preferred_width = gtk_gst_widget_get_preferred_width; - widget_klass->get_preferred_height = gtk_gst_widget_get_preferred_height; } static void gtk_gst_widget_init (GtkGstWidget * widget) { - widget->priv = GTK_GST_WIDGET_GET_PRIVATE (widget); - - widget->priv->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; - widget->priv->par_n = DEFAULT_PAR_N; - widget->priv->par_d = DEFAULT_PAR_D; - widget->priv->ignore_alpha = DEFAULT_IGNORE_ALPHA; - - g_mutex_init (&widget->priv->lock); + gtk_gst_base_widget_init (GTK_GST_BASE_WIDGET (widget)); } GtkWidget * @@ -337,153 +179,3 @@ gtk_gst_widget_new (void) { return (GtkWidget *) g_object_new (GTK_TYPE_GST_WIDGET, NULL); } - -static gboolean -_queue_draw (GtkGstWidget * widget) -{ - g_mutex_lock (&widget->priv->lock); - widget->priv->draw_id = 0; - g_mutex_unlock (&widget->priv->lock); - - gtk_widget_queue_draw (GTK_WIDGET (widget)); - - return G_SOURCE_REMOVE; -} - -void -gtk_gst_widget_set_buffer (GtkGstWidget * widget, GstBuffer * buffer) -{ - g_return_if_fail (GTK_IS_GST_WIDGET (widget)); - g_return_if_fail (buffer == NULL || widget->priv->negotiated); - - g_mutex_lock (&widget->priv->lock); - - gst_buffer_replace (&widget->priv->buffer, buffer); - - if (!widget->priv->draw_id) { - widget->priv->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT, - (GSourceFunc) _queue_draw, widget, NULL); - } - - g_mutex_unlock (&widget->priv->lock); -} - -static gboolean -_queue_resize (GtkGstWidget * widget) -{ - g_mutex_lock (&widget->priv->lock); - widget->priv->resize_id = 0; - g_mutex_unlock (&widget->priv->lock); - - gtk_widget_queue_resize (GTK_WIDGET (widget)); - - return G_SOURCE_REMOVE; -} - -static gboolean -_calculate_par (GtkGstWidget * widget, GstVideoInfo * info) -{ - gboolean ok; - gint width, height; - gint par_n, par_d; - gint display_par_n, display_par_d; - guint display_ratio_num, display_ratio_den; - - width = GST_VIDEO_INFO_WIDTH (info); - height = GST_VIDEO_INFO_HEIGHT (info); - - par_n = GST_VIDEO_INFO_PAR_N (info); - par_d = GST_VIDEO_INFO_PAR_D (info); - - if (!par_n) - par_n = 1; - - /* get display's PAR */ - if (widget->priv->par_n != 0 && widget->priv->par_d != 0) { - display_par_n = widget->priv->par_n; - display_par_d = widget->priv->par_d; - } else { - display_par_n = 1; - display_par_d = 1; - } - - ok = gst_video_calculate_display_ratio (&display_ratio_num, - &display_ratio_den, width, height, par_n, par_d, display_par_n, - display_par_d); - - if (!ok) - return FALSE; - - GST_LOG ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n, display_par_d); - - if (height % display_ratio_den == 0) { - GST_DEBUG ("keeping video height"); - widget->priv->display_width = (guint) - gst_util_uint64_scale_int (height, display_ratio_num, - display_ratio_den); - widget->priv->display_height = height; - } else if (width % display_ratio_num == 0) { - GST_DEBUG ("keeping video width"); - widget->priv->display_width = width; - widget->priv->display_height = (guint) - gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num); - } else { - GST_DEBUG ("approximating while keeping video height"); - widget->priv->display_width = (guint) - gst_util_uint64_scale_int (height, display_ratio_num, - display_ratio_den); - widget->priv->display_height = height; - } - GST_DEBUG ("scaling to %dx%d", widget->priv->display_width, - widget->priv->display_height); - - return TRUE; -} - -gboolean -gtk_gst_widget_set_caps (GtkGstWidget * widget, GstCaps * caps) -{ - GstVideoInfo v_info; - - g_return_val_if_fail (GTK_IS_GST_WIDGET (widget), FALSE); - g_return_val_if_fail (GST_IS_CAPS (caps), FALSE); - g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE); - - if (widget->priv->caps && gst_caps_is_equal_fixed (widget->priv->caps, caps)) - return TRUE; - - if (!gst_video_info_from_caps (&v_info, caps)) - return FALSE; - - /* FIXME: support other formats */ -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&v_info) == - GST_VIDEO_FORMAT_BGRA || GST_VIDEO_INFO_FORMAT (&v_info) == - GST_VIDEO_FORMAT_BGRx, FALSE); -#else - g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&v_info) == - GST_VIDEO_FORMAT_ARGB || GST_VIDEO_INFO_FORMAT (&v_info) == - GST_VIDEO_FORMAT_xRGB, FALSE); -#endif - - g_mutex_lock (&widget->priv->lock); - - if (!_calculate_par (widget, &v_info)) { - g_mutex_unlock (&widget->priv->lock); - return FALSE; - } - - gst_buffer_replace (&widget->priv->buffer, NULL); - gst_caps_replace (&widget->priv->caps, caps); - widget->priv->v_info = v_info; - widget->priv->negotiated = TRUE; - - if (!widget->priv->resize_id) { - widget->priv->resize_id = g_idle_add_full (G_PRIORITY_DEFAULT, - (GSourceFunc) _queue_resize, widget, NULL); - } - - g_mutex_unlock (&widget->priv->lock); - - return TRUE; -} diff --git a/ext/gtk/gtkgstwidget.h b/ext/gtk/gtkgstwidget.h index 29adafffa2..427eebac40 100644 --- a/ext/gtk/gtkgstwidget.h +++ b/ext/gtk/gtkgstwidget.h @@ -24,6 +24,8 @@ #include #include +#include "gtkgstbasewidget.h" + G_BEGIN_DECLS GType gtk_gst_widget_get_type (void); @@ -36,7 +38,6 @@ GType gtk_gst_widget_get_type (void); typedef struct _GtkGstWidget GtkGstWidget; typedef struct _GtkGstWidgetClass GtkGstWidgetClass; -typedef struct _GtkGstWidgetPrivate GtkGstWidgetPrivate; /** * GtkGstWidget: @@ -46,9 +47,7 @@ typedef struct _GtkGstWidgetPrivate GtkGstWidgetPrivate; struct _GtkGstWidget { /* */ - GtkDrawingArea parent; - - GtkGstWidgetPrivate *priv; + GtkGstBaseWidget base; }; /** @@ -59,14 +58,11 @@ struct _GtkGstWidget struct _GtkGstWidgetClass { /* */ - GtkDrawingAreaClass object_class; + GtkGstBaseWidgetClass base_class; }; GtkWidget * gtk_gst_widget_new (void); -gboolean gtk_gst_widget_set_caps (GtkGstWidget * widget, GstCaps *caps); -void gtk_gst_widget_set_buffer (GtkGstWidget * widget, GstBuffer *buffer); - G_END_DECLS #endif /* __GTK_GST_WIDGET_H__ */ From 4c201f3aa68853215107f90f0cdfe16895d1e579 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 16 Jul 2015 14:30:42 -0400 Subject: [PATCH 066/128] gtkglsink: Port to GtkGstBaseWidget https://bugzilla.gnome.org/show_bug.cgi?id=752441 --- ext/gtk/gstgtkglsink.c | 38 ++- ext/gtk/gstgtkglsink.h | 2 +- ext/gtk/gtkgstglwidget.c | 577 ++++++++++----------------------------- ext/gtk/gtkgstglwidget.h | 8 +- 4 files changed, 181 insertions(+), 444 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index cbb0e948bb..8d380c3f1c 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -169,7 +169,7 @@ widget_destroy_cb (GtkWidget * widget, GstGtkGLSink * gtk_sink) GST_OBJECT_UNLOCK (gtk_sink); } -static GtkGstGLWidget * +static GtkGstBaseWidget * gst_gtk_gl_sink_get_widget (GstGtkGLSink * gtk_sink) { if (gtk_sink->widget != NULL) @@ -182,7 +182,7 @@ gst_gtk_gl_sink_get_widget (GstGtkGLSink * gtk_sink) return NULL; } - gtk_sink->widget = (GtkGstGLWidget *) gtk_gst_gl_widget_new (); + 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); @@ -323,13 +323,16 @@ gst_gtk_gl_sink_change_state (GstElement * element, GstStateChange transition) gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition))); switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: + 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 (gtk_sink->widget)); + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (gst_widget)); if (!gtk_widget_is_toplevel (toplevel)) { GtkWidget *window; @@ -342,17 +345,17 @@ gst_gtk_gl_sink_change_state (GstElement * element, GstStateChange transition) gtk_widget_show_all (window); } - if (!gtk_gst_gl_widget_init_winsys (gtk_sink->widget)) + if (!gtk_gst_gl_widget_init_winsys (gst_widget)) return GST_STATE_CHANGE_FAILURE; - gtk_sink->display = gtk_gst_gl_widget_get_display (gtk_sink->widget); - gtk_sink->context = gtk_gst_gl_widget_get_context (gtk_sink->widget); - gtk_sink->gtk_context = - gtk_gst_gl_widget_get_gtk_context (gtk_sink->widget); + 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: @@ -371,7 +374,7 @@ gst_gtk_gl_sink_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_PAUSED_TO_READY: GST_OBJECT_LOCK (gtk_sink); if (gtk_sink->widget) - gtk_gst_gl_widget_set_buffer (gtk_sink->widget, NULL); + gtk_gst_base_widget_set_buffer (gtk_sink->widget, NULL); GST_OBJECT_UNLOCK (gtk_sink); break; case GST_STATE_CHANGE_READY_TO_NULL: @@ -430,8 +433,19 @@ gst_gtk_gl_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) if (!gst_video_info_from_caps (>k_sink->v_info, caps)) return FALSE; - if (!gtk_gst_gl_widget_set_caps (gtk_sink->widget, caps)) + 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_gst_base_widget_set_caps (gtk_sink->widget, caps)) + return FALSE; + + GST_OBJECT_UNLOCK (gtk_sink); return TRUE; } @@ -454,7 +468,7 @@ gst_gtk_gl_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) return GST_FLOW_ERROR; } - gtk_gst_gl_widget_set_buffer (gtk_sink->widget, buf); + gtk_gst_base_widget_set_buffer (gtk_sink->widget, buf); GST_OBJECT_UNLOCK (vsink); diff --git a/ext/gtk/gstgtkglsink.h b/ext/gtk/gstgtkglsink.h index 985486fb24..fdc62727c8 100644 --- a/ext/gtk/gstgtkglsink.h +++ b/ext/gtk/gstgtkglsink.h @@ -52,7 +52,7 @@ struct _GstGtkGLSink /* */ GstVideoSink parent; - GtkGstGLWidget *widget; + GtkGstBaseWidget *widget; GstVideoInfo v_info; GstBufferPool *pool; diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 67993f24b9..b721984785 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -56,35 +56,9 @@ G_DEFINE_TYPE_WITH_CODE (GtkGstGLWidget, gtk_gst_gl_widget, GTK_TYPE_GL_AREA, #define GTK_GST_GL_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ GTK_TYPE_GST_GL_WIDGET, GtkGstGLWidgetPrivate)) -#define DEFAULT_FORCE_ASPECT_RATIO TRUE -#define DEFAULT_PAR_N 0 -#define DEFAULT_PAR_D 1 -#define DEFAULT_IGNORE_ALPHA TRUE - -enum -{ - PROP_0, - PROP_FORCE_ASPECT_RATIO, - PROP_PIXEL_ASPECT_RATIO, - PROP_IGNORE_ALPHA, -}; - struct _GtkGstGLWidgetPrivate { - GMutex lock; - /* properties */ - gboolean force_aspect_ratio; - gint par_n, par_d; - gboolean ignore_alpha; - - gint display_width; - gint display_height; - - gboolean negotiated; - GstBuffer *buffer; - GstCaps *caps; - GstVideoInfo v_info; gboolean new_buffer; gboolean initted; @@ -99,44 +73,8 @@ struct _GtkGstGLWidgetPrivate GLint attr_position; GLint attr_texture; GLuint current_tex; - - /* Pending queued idles callback */ - guint draw_id; - guint resize_id; }; -static void -gtk_gst_gl_widget_get_preferred_width (GtkWidget * widget, gint * min, - gint * natural) -{ - GtkGstGLWidget *gst_widget = (GtkGstGLWidget *) widget; - gint video_width = gst_widget->priv->display_width; - - if (!gst_widget->priv->negotiated) - video_width = 10; - - if (min) - *min = 1; - if (natural) - *natural = video_width; -} - -static void -gtk_gst_gl_widget_get_preferred_height (GtkWidget * widget, gint * min, - gint * natural) -{ - GtkGstGLWidget *gst_widget = (GtkGstGLWidget *) widget; - gint video_height = gst_widget->priv->display_height; - - if (!gst_widget->priv->negotiated) - video_height = 10; - - if (min) - *min = 1; - if (natural) - *natural = video_height; -} - static const GLfloat vertices[] = { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, @@ -147,51 +85,53 @@ static const GLfloat vertices[] = { static void gtk_gst_gl_widget_bind_buffer (GtkGstGLWidget * gst_widget) { - const GstGLFuncs *gl = gst_widget->priv->context->gl_vtable; + GtkGstGLWidgetPrivate *priv = gst_widget->priv; + const GstGLFuncs *gl = priv->context->gl_vtable; - gl->BindBuffer (GL_ARRAY_BUFFER, gst_widget->priv->vertex_buffer); + gl->BindBuffer (GL_ARRAY_BUFFER, priv->vertex_buffer); /* Load the vertex position */ - gl->VertexAttribPointer (gst_widget->priv->attr_position, 3, GL_FLOAT, - GL_FALSE, 5 * sizeof (GLfloat), (void *) 0); + gl->VertexAttribPointer (priv->attr_position, 3, GL_FLOAT, GL_FALSE, + 5 * sizeof (GLfloat), (void *) 0); /* Load the texture coordinate */ - gl->VertexAttribPointer (gst_widget->priv->attr_texture, 2, GL_FLOAT, - GL_FALSE, 5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat))); + gl->VertexAttribPointer (priv->attr_texture, 2, GL_FLOAT, GL_FALSE, + 5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat))); - gl->EnableVertexAttribArray (gst_widget->priv->attr_position); - gl->EnableVertexAttribArray (gst_widget->priv->attr_texture); + gl->EnableVertexAttribArray (priv->attr_position); + gl->EnableVertexAttribArray (priv->attr_texture); } static void gtk_gst_gl_widget_unbind_buffer (GtkGstGLWidget * gst_widget) { - const GstGLFuncs *gl = gst_widget->priv->context->gl_vtable; + GtkGstGLWidgetPrivate *priv = gst_widget->priv; + const GstGLFuncs *gl = priv->context->gl_vtable; gl->BindBuffer (GL_ARRAY_BUFFER, 0); - gl->DisableVertexAttribArray (gst_widget->priv->attr_position); - gl->DisableVertexAttribArray (gst_widget->priv->attr_texture); + gl->DisableVertexAttribArray (priv->attr_position); + gl->DisableVertexAttribArray (priv->attr_texture); } static void gtk_gst_gl_widget_init_redisplay (GtkGstGLWidget * gst_widget) { - const GstGLFuncs *gl = gst_widget->priv->context->gl_vtable; + GtkGstGLWidgetPrivate *priv = gst_widget->priv; + const GstGLFuncs *gl = priv->context->gl_vtable; - gst_widget->priv->shader = gst_gl_shader_new (gst_widget->priv->context); + priv->shader = gst_gl_shader_new (priv->context); - gst_gl_shader_compile_with_default_vf_and_check - (gst_widget->priv->shader, &gst_widget->priv->attr_position, - &gst_widget->priv->attr_texture); + gst_gl_shader_compile_with_default_vf_and_check (priv->shader, + &priv->attr_position, &priv->attr_texture); if (gl->GenVertexArrays) { - gl->GenVertexArrays (1, &gst_widget->priv->vao); - gl->BindVertexArray (gst_widget->priv->vao); + gl->GenVertexArrays (1, &priv->vao); + gl->BindVertexArray (priv->vao); } - gl->GenBuffers (1, &gst_widget->priv->vertex_buffer); - gl->BindBuffer (GL_ARRAY_BUFFER, gst_widget->priv->vertex_buffer); + gl->GenBuffers (1, &priv->vertex_buffer); + gl->BindBuffer (GL_ARRAY_BUFFER, priv->vertex_buffer); gl->BufferData (GL_ARRAY_BUFFER, 4 * 5 * sizeof (GLfloat), vertices, GL_STATIC_DRAW); @@ -202,16 +142,17 @@ gtk_gst_gl_widget_init_redisplay (GtkGstGLWidget * gst_widget) gl->BindBuffer (GL_ARRAY_BUFFER, 0); - gst_widget->priv->initted = TRUE; + priv->initted = TRUE; } static void _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) { - const GstGLFuncs *gl = gst_widget->priv->context->gl_vtable; + GtkGstGLWidgetPrivate *priv = gst_widget->priv; + const GstGLFuncs *gl = priv->context->gl_vtable; const GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; - if (gst_widget->priv->force_aspect_ratio) { + if (gst_widget->base.force_aspect_ratio) { GstVideoRectangle src, dst, result; gint widget_width, widget_height, widget_scale; @@ -224,8 +165,8 @@ _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) src.x = 0; src.y = 0; - src.w = gst_widget->priv->display_width; - src.h = gst_widget->priv->display_height; + src.w = gst_widget->base.display_width; + src.h = gst_widget->base.display_height; dst.x = 0; dst.y = 0; @@ -237,16 +178,16 @@ _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) gl->Viewport (result.x, result.y, result.w, result.h); } - gst_gl_shader_use (gst_widget->priv->shader); + gst_gl_shader_use (priv->shader); if (gl->BindVertexArray) - gl->BindVertexArray (gst_widget->priv->vao); + gl->BindVertexArray (priv->vao); else gtk_gst_gl_widget_bind_buffer (gst_widget); gl->ActiveTexture (GL_TEXTURE0); gl->BindTexture (GL_TEXTURE_2D, tex); - gst_gl_shader_set_uniform_1i (gst_widget->priv->shader, "tex", 0); + gst_gl_shader_set_uniform_1i (priv->shader, "tex", 0); gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); @@ -261,42 +202,42 @@ _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) static gboolean gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) { - GtkGstGLWidget *gst_widget = (GtkGstGLWidget *) widget; + GtkGstGLWidgetPrivate *priv = GTK_GST_GL_WIDGET (widget)->priv; + GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget); - g_mutex_lock (&gst_widget->priv->lock); + GTK_GST_BASE_WIDGET_LOCK (widget); - if (!gst_widget->priv->initted && gst_widget->priv->context) - gtk_gst_gl_widget_init_redisplay (gst_widget); + if (!priv->initted && priv->context) + gtk_gst_gl_widget_init_redisplay (GTK_GST_GL_WIDGET (widget)); - if (gst_widget->priv->initted && gst_widget->priv->negotiated - && gst_widget->priv->buffer) { + if (priv->initted && base_widget->negotiated && base_widget->buffer) { GST_DEBUG ("rendering buffer %p with gdk context %p", - gst_widget->priv->buffer, context); + base_widget->buffer, context); - gst_gl_context_activate (gst_widget->priv->other_context, TRUE); + gst_gl_context_activate (priv->other_context, TRUE); - if (gst_widget->priv->new_buffer || gst_widget->priv->current_tex == 0) { + if (base_widget->new_buffer || priv->current_tex == 0) { GstVideoFrame gl_frame; GstGLSyncMeta *sync_meta; - if (!gst_video_frame_map (&gl_frame, &gst_widget->priv->v_info, - gst_widget->priv->buffer, GST_MAP_READ | GST_MAP_GL)) { + if (!gst_video_frame_map (&gl_frame, &base_widget->v_info, + base_widget->buffer, GST_MAP_READ | GST_MAP_GL)) { goto error; } - sync_meta = gst_buffer_get_gl_sync_meta (gst_widget->priv->buffer); + sync_meta = gst_buffer_get_gl_sync_meta (base_widget->buffer); if (sync_meta) { - gst_gl_sync_meta_set_sync_point (sync_meta, gst_widget->priv->context); - gst_gl_sync_meta_wait (sync_meta, gst_widget->priv->other_context); + gst_gl_sync_meta_set_sync_point (sync_meta, priv->context); + gst_gl_sync_meta_wait (sync_meta, priv->other_context); } - gst_widget->priv->current_tex = *(guint *) gl_frame.data[0]; + priv->current_tex = *(guint *) gl_frame.data[0]; gst_video_frame_unmap (&gl_frame); } - _redraw_texture (gst_widget, gst_widget->priv->current_tex); - gst_widget->priv->new_buffer = FALSE; + _redraw_texture (GTK_GST_GL_WIDGET (widget), priv->current_tex); + base_widget->new_buffer = FALSE; } else { error: /* FIXME: nothing to display */ @@ -304,10 +245,10 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) glClear (GL_COLOR_BUFFER_BIT); } - if (gst_widget->priv->other_context) - gst_gl_context_activate (gst_widget->priv->other_context, FALSE); + if (priv->other_context) + gst_gl_context_activate (priv->other_context, FALSE); - g_mutex_unlock (&gst_widget->priv->lock); + GTK_GST_BASE_WIDGET_UNLOCK (widget); return FALSE; } @@ -360,196 +301,117 @@ _invoke_on_main (ThreadFunc func, gpointer data) static void _reset_gl (GtkGstGLWidget * gst_widget) { - const GstGLFuncs *gl = gst_widget->priv->other_context->gl_vtable; + GtkGstGLWidgetPrivate *priv = gst_widget->priv; + const GstGLFuncs *gl = priv->other_context->gl_vtable; - if (!gst_widget->priv->gdk_context) - gst_widget->priv->gdk_context = - gtk_gl_area_get_context (GTK_GL_AREA (gst_widget)); - if (gst_widget->priv->gdk_context == NULL) + if (!priv->gdk_context) + priv->gdk_context = gtk_gl_area_get_context (GTK_GL_AREA (gst_widget)); + + if (priv->gdk_context == NULL) return; - gdk_gl_context_make_current (gst_widget->priv->gdk_context); - gst_gl_context_activate (gst_widget->priv->other_context, TRUE); + gdk_gl_context_make_current (priv->gdk_context); + gst_gl_context_activate (priv->other_context, TRUE); - if (gst_widget->priv->vao) { - gl->DeleteVertexArrays (1, &gst_widget->priv->vao); - gst_widget->priv->vao = 0; + if (priv->vao) { + gl->DeleteVertexArrays (1, &priv->vao); + priv->vao = 0; } - if (gst_widget->priv->vertex_buffer) { - gl->DeleteBuffers (1, &gst_widget->priv->vertex_buffer); - gst_widget->priv->vertex_buffer = 0; + if (priv->vertex_buffer) { + gl->DeleteBuffers (1, &priv->vertex_buffer); + priv->vertex_buffer = 0; } - if (gst_widget->priv->upload) { - gst_object_unref (gst_widget->priv->upload); - gst_widget->priv->upload = NULL; + if (priv->upload) { + gst_object_unref (priv->upload); + priv->upload = NULL; } - if (gst_widget->priv->shader) { - gst_object_unref (gst_widget->priv->shader); - gst_widget->priv->shader = NULL; + if (priv->shader) { + gst_object_unref (priv->shader); + priv->shader = NULL; } - gst_gl_context_activate (gst_widget->priv->other_context, FALSE); + gst_gl_context_activate (priv->other_context, FALSE); - gst_object_unref (gst_widget->priv->other_context); - gst_widget->priv->other_context = NULL; + gst_object_unref (priv->other_context); + priv->other_context = NULL; gdk_gl_context_clear_current (); - g_object_unref (gst_widget->priv->gdk_context); - gst_widget->priv->gdk_context = NULL; + g_object_unref (priv->gdk_context); + priv->gdk_context = NULL; } static void -_reset (GtkGstGLWidget * gst_widget) +_reset (GtkGstBaseWidget * base_widget) { - gst_buffer_replace (&gst_widget->priv->buffer, NULL); + GtkGstGLWidgetPrivate *priv = GTK_GST_GL_WIDGET (base_widget)->priv; - gst_caps_replace (&gst_widget->priv->caps, NULL); + priv->initted = FALSE; + priv->vao = 0; + priv->vertex_buffer = 0; + priv->attr_position = 0; + priv->attr_texture = 0; + priv->current_tex = 0; - gst_widget->priv->negotiated = FALSE; - gst_widget->priv->initted = FALSE; - gst_widget->priv->vao = 0; - gst_widget->priv->vertex_buffer = 0; - gst_widget->priv->attr_position = 0; - gst_widget->priv->attr_texture = 0; - gst_widget->priv->current_tex = 0; - gst_widget->priv->new_buffer = TRUE; + gtk_gl_area_set_has_alpha (GTK_GL_AREA (base_widget), + !base_widget->ignore_alpha); } static void gtk_gst_gl_widget_finalize (GObject * object) { - GtkGstGLWidget *widget = GTK_GST_GL_WIDGET_CAST (object); + GtkGstGLWidgetPrivate *priv = GTK_GST_GL_WIDGET (object)->priv; + GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (object); - g_mutex_clear (&widget->priv->lock); + _reset (base_widget); - _reset (widget); + if (priv->other_context) + _invoke_on_main ((ThreadFunc) _reset_gl, base_widget); - if (widget->priv->other_context) { - _invoke_on_main ((ThreadFunc) _reset_gl, widget); - } + if (priv->context) + gst_object_unref (priv->context); - if (widget->priv->context) - gst_object_unref (widget->priv->context); - - if (widget->priv->display) - gst_object_unref (widget->priv->display); - - if (widget->priv->draw_id) - g_source_remove (widget->priv->draw_id); - - if (widget->priv->resize_id) - g_source_remove (widget->priv->resize_id); + if (priv->display) + gst_object_unref (priv->display); + gtk_gst_base_widget_finalize (object); G_OBJECT_CLASS (gtk_gst_gl_widget_parent_class)->finalize (object); } -static void -gtk_gst_gl_widget_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GtkGstGLWidget *gtk_widget = GTK_GST_GL_WIDGET (object); - - switch (prop_id) { - case PROP_FORCE_ASPECT_RATIO: - gtk_widget->priv->force_aspect_ratio = g_value_get_boolean (value); - break; - case PROP_PIXEL_ASPECT_RATIO: - gtk_widget->priv->par_n = gst_value_get_fraction_numerator (value); - gtk_widget->priv->par_d = gst_value_get_fraction_denominator (value); - break; - case PROP_IGNORE_ALPHA: - gtk_widget->priv->ignore_alpha = g_value_get_boolean (value); - gtk_gl_area_set_has_alpha ((GtkGLArea *) gtk_widget, - !gtk_widget->priv->ignore_alpha); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gtk_gst_gl_widget_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GtkGstGLWidget *gtk_widget = GTK_GST_GL_WIDGET (object); - - switch (prop_id) { - case PROP_FORCE_ASPECT_RATIO: - g_value_set_boolean (value, gtk_widget->priv->force_aspect_ratio); - break; - case PROP_PIXEL_ASPECT_RATIO: - gst_value_set_fraction (value, gtk_widget->priv->par_n, - gtk_widget->priv->par_d); - break; - case PROP_IGNORE_ALPHA: - g_value_set_boolean (value, gtk_widget->priv->ignore_alpha); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - static void gtk_gst_gl_widget_class_init (GtkGstGLWidgetClass * klass) { GObjectClass *gobject_klass = (GObjectClass *) klass; - GtkWidgetClass *widget_klass = (GtkWidgetClass *) klass; GtkGLAreaClass *gl_widget_klass = (GtkGLAreaClass *) klass; + GtkGstBaseWidget *base_widget_klass = (GtkGstBaseWidget *) klass; g_type_class_add_private (klass, sizeof (GtkGstGLWidgetPrivate)); + gtk_gst_base_widget_class_init (GTK_GST_BASE_WIDGET_CLASS (klass)); - gobject_klass->set_property = gtk_gst_gl_widget_set_property; - gobject_klass->get_property = gtk_gst_gl_widget_get_property; gobject_klass->finalize = gtk_gst_gl_widget_finalize; - - g_object_class_install_property (gobject_klass, 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_klass, 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_klass, 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)); - gl_widget_klass->render = gtk_gst_gl_widget_render; - - widget_klass->get_preferred_width = gtk_gst_gl_widget_get_preferred_width; - widget_klass->get_preferred_height = gtk_gst_gl_widget_get_preferred_height; + base_widget_klass->reset = _reset; } static void -gtk_gst_gl_widget_init (GtkGstGLWidget * widget) +gtk_gst_gl_widget_init (GtkGstGLWidget * gst_widget) { + GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (gst_widget); GdkDisplay *display; + GtkGstGLWidgetPrivate *priv; - widget->priv = GTK_GST_GL_WIDGET_GET_PRIVATE (widget); + gtk_gst_base_widget_init (base_widget); - widget->priv->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; - widget->priv->par_n = DEFAULT_PAR_N; - widget->priv->par_d = DEFAULT_PAR_D; - widget->priv->ignore_alpha = DEFAULT_IGNORE_ALPHA; - - g_mutex_init (&widget->priv->lock); + gst_widget->priv = priv = GTK_GST_GL_WIDGET_GET_PRIVATE (gst_widget); display = gdk_display_get_default (); #if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11) if (GDK_IS_X11_DISPLAY (display)) - widget->priv->display = (GstGLDisplay *) + priv->display = (GstGLDisplay *) gst_gl_display_x11_new_with_display (gdk_x11_display_get_xdisplay (display)); #endif @@ -557,97 +419,63 @@ gtk_gst_gl_widget_init (GtkGstGLWidget * widget) if (GDK_IS_WAYLAND_DISPLAY (display)) { struct wl_display *wayland_display = gdk_wayland_display_get_wl_display (display); - widget->priv->display = (GstGLDisplay *) + priv->display = (GstGLDisplay *) gst_gl_display_wayland_new_with_display (wayland_display); } #endif (void) display; - if (!widget->priv->display) - widget->priv->display = gst_gl_display_new (); + if (!priv->display) + priv->display = gst_gl_display_new (); - gtk_gl_area_set_has_alpha ((GtkGLArea *) widget, !widget->priv->ignore_alpha); + gtk_gl_area_set_has_alpha (GTK_GL_AREA (gst_widget), + !base_widget->ignore_alpha); } -GtkWidget * -gtk_gst_gl_widget_new (void) -{ - return (GtkWidget *) g_object_new (GTK_TYPE_GST_GL_WIDGET, NULL); -} -static gboolean -_queue_draw (GtkGstGLWidget * widget) -{ - g_mutex_lock (&widget->priv->lock); - widget->priv->draw_id = 0; - g_mutex_unlock (&widget->priv->lock); - - gtk_widget_queue_draw (GTK_WIDGET (widget)); - - return G_SOURCE_REMOVE; -} - -void -gtk_gst_gl_widget_set_buffer (GtkGstGLWidget * widget, GstBuffer * buffer) -{ - g_return_if_fail (GTK_IS_GST_GL_WIDGET (widget)); - g_return_if_fail (buffer == NULL || widget->priv->negotiated); - - g_mutex_lock (&widget->priv->lock); - - gst_buffer_replace (&widget->priv->buffer, buffer); - widget->priv->new_buffer = TRUE; - - if (!widget->priv->draw_id) { - widget->priv->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT, - (GSourceFunc) _queue_draw, widget, NULL); - } - - g_mutex_unlock (&widget->priv->lock); -} static void _get_gl_context (GtkGstGLWidget * gst_widget) { + GtkGstGLWidgetPrivate *priv = gst_widget->priv; GstGLPlatform platform; GstGLAPI gl_api; guintptr gl_handle; gtk_widget_realize (GTK_WIDGET (gst_widget)); - if (gst_widget->priv->gdk_context) - g_object_unref (gst_widget->priv->gdk_context); - gst_widget->priv->gdk_context = - gtk_gl_area_get_context (GTK_GL_AREA (gst_widget)); - if (gst_widget->priv->gdk_context == NULL) { + if (priv->gdk_context) + g_object_unref (priv->gdk_context); + priv->gdk_context = gtk_gl_area_get_context (GTK_GL_AREA (gst_widget)); + if (priv->gdk_context == NULL) { g_assert_not_reached (); return; } - g_object_ref (gst_widget->priv->gdk_context); + g_object_ref (priv->gdk_context); - gdk_gl_context_make_current (gst_widget->priv->gdk_context); + gdk_gl_context_make_current (priv->gdk_context); #if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11) - if (GST_IS_GL_DISPLAY_X11 (gst_widget->priv->display)) { + if (GST_IS_GL_DISPLAY_X11 (priv->display)) { platform = GST_GL_PLATFORM_GLX; gl_api = gst_gl_context_get_current_gl_api (NULL, NULL); gl_handle = gst_gl_context_get_current_gl_context (platform); if (gl_handle) - gst_widget->priv->other_context = - gst_gl_context_new_wrapped (gst_widget->priv->display, gl_handle, + priv->other_context = + gst_gl_context_new_wrapped (priv->display, gl_handle, platform, gl_api); } #endif #if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND) - if (GST_IS_GL_DISPLAY_WAYLAND (gst_widget->priv->display)) { + if (GST_IS_GL_DISPLAY_WAYLAND (priv->display)) { platform = GST_GL_PLATFORM_EGL; gl_api = gst_gl_context_get_current_gl_api (NULL, NULL); gl_handle = gst_gl_context_get_current_gl_context (platform); if (gl_handle) - gst_widget->priv->other_context = - gst_gl_context_new_wrapped (gst_widget->priv->display, gl_handle, + priv->other_context = + gst_gl_context_new_wrapped (priv->display, gl_handle, platform, gl_api); } #endif @@ -656,166 +484,61 @@ _get_gl_context (GtkGstGLWidget * gst_widget) (void) gl_api; (void) gl_handle; - if (gst_widget->priv->other_context) { + if (priv->other_context) { GError *error = NULL; - gst_gl_context_activate (gst_widget->priv->other_context, TRUE); - if (!gst_gl_context_fill_info (gst_widget->priv->other_context, &error)) { + gst_gl_context_activate (priv->other_context, TRUE); + if (!gst_gl_context_fill_info (priv->other_context, &error)) { GST_ERROR ("failed to retreive gdk context info: %s", error->message); - g_object_unref (gst_widget->priv->other_context); - gst_widget->priv->other_context = NULL; + g_object_unref (priv->other_context); + priv->other_context = NULL; } else { - gst_gl_context_activate (gst_widget->priv->other_context, FALSE); + gst_gl_context_activate (priv->other_context, FALSE); } } } -static gboolean -_queue_resize (GtkGstGLWidget * widget) +GtkWidget * +gtk_gst_gl_widget_new (void) { - g_mutex_lock (&widget->priv->lock); - widget->priv->resize_id = 0; - g_mutex_unlock (&widget->priv->lock); - - gtk_widget_queue_resize (GTK_WIDGET (widget)); - - return G_SOURCE_REMOVE; + return (GtkWidget *) g_object_new (GTK_TYPE_GST_GL_WIDGET, NULL); } gboolean -gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * widget) +gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * gst_widget) { - g_return_val_if_fail (GTK_IS_GST_GL_WIDGET (widget), FALSE); + GtkGstGLWidgetPrivate *priv = gst_widget->priv; - g_mutex_lock (&widget->priv->lock); + g_return_val_if_fail (GTK_IS_GST_GL_WIDGET (gst_widget), FALSE); - if (widget->priv->display && widget->priv->gdk_context - && widget->priv->other_context) { - g_mutex_unlock (&widget->priv->lock); + GTK_GST_BASE_WIDGET_LOCK (gst_widget); + + if (priv->display && priv->gdk_context && priv->other_context) { + GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); return TRUE; } - if (!widget->priv->other_context) { - g_mutex_unlock (&widget->priv->lock); - _invoke_on_main ((ThreadFunc) _get_gl_context, widget); - g_mutex_lock (&widget->priv->lock); + if (!priv->other_context) { + GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); + _invoke_on_main ((ThreadFunc) _get_gl_context, gst_widget); + GTK_GST_BASE_WIDGET_LOCK (gst_widget); } - if (!GST_GL_IS_CONTEXT (widget->priv->other_context)) { - g_mutex_unlock (&widget->priv->lock); + if (!GST_GL_IS_CONTEXT (priv->other_context)) { + GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); return FALSE; } - widget->priv->context = gst_gl_context_new (widget->priv->display); + priv->context = gst_gl_context_new (priv->display); - if (!widget->priv->context) { - g_mutex_unlock (&widget->priv->lock); + if (!priv->context) { + GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); return FALSE; } - gst_gl_context_create (widget->priv->context, widget->priv->other_context, - NULL); - - g_mutex_unlock (&widget->priv->lock); - return TRUE; -} - -static gboolean -_calculate_par (GtkGstGLWidget * widget, GstVideoInfo * info) -{ - gboolean ok; - gint width, height; - gint par_n, par_d; - gint display_par_n, display_par_d; - guint display_ratio_num, display_ratio_den; - - width = GST_VIDEO_INFO_WIDTH (info); - height = GST_VIDEO_INFO_HEIGHT (info); - - par_n = GST_VIDEO_INFO_PAR_N (info); - par_d = GST_VIDEO_INFO_PAR_D (info); - - if (!par_n) - par_n = 1; - - /* get display's PAR */ - if (widget->priv->par_n != 0 && widget->priv->par_d != 0) { - display_par_n = widget->priv->par_n; - display_par_d = widget->priv->par_d; - } else { - display_par_n = 1; - display_par_d = 1; - } - - ok = gst_video_calculate_display_ratio (&display_ratio_num, - &display_ratio_den, width, height, par_n, par_d, display_par_n, - display_par_d); - - if (!ok) - return FALSE; - - GST_LOG ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n, display_par_d); - - if (height % display_ratio_den == 0) { - GST_DEBUG ("keeping video height"); - widget->priv->display_width = (guint) - gst_util_uint64_scale_int (height, display_ratio_num, - display_ratio_den); - widget->priv->display_height = height; - } else if (width % display_ratio_num == 0) { - GST_DEBUG ("keeping video width"); - widget->priv->display_width = width; - widget->priv->display_height = (guint) - gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num); - } else { - GST_DEBUG ("approximating while keeping video height"); - widget->priv->display_width = (guint) - gst_util_uint64_scale_int (height, display_ratio_num, - display_ratio_den); - widget->priv->display_height = height; - } - GST_DEBUG ("scaling to %dx%d", widget->priv->display_width, - widget->priv->display_height); - - return TRUE; -} - -gboolean -gtk_gst_gl_widget_set_caps (GtkGstGLWidget * widget, GstCaps * caps) -{ - GstVideoInfo v_info; - - g_return_val_if_fail (GTK_IS_GST_GL_WIDGET (widget), FALSE); - g_return_val_if_fail (GST_IS_CAPS (caps), FALSE); - g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE); - - if (widget->priv->caps && gst_caps_is_equal_fixed (widget->priv->caps, caps)) - return TRUE; - - if (!gst_video_info_from_caps (&v_info, caps)) - return FALSE; - - g_mutex_lock (&widget->priv->lock); - - _reset (widget); - - gst_caps_replace (&widget->priv->caps, caps); - - if (!_calculate_par (widget, &v_info)) { - g_mutex_unlock (&widget->priv->lock); - return FALSE; - } - - widget->priv->v_info = v_info; - widget->priv->negotiated = TRUE; - - if (!widget->priv->resize_id) { - widget->priv->resize_id = g_idle_add_full (G_PRIORITY_DEFAULT, - (GSourceFunc) _queue_resize, widget, NULL); - } - - g_mutex_unlock (&widget->priv->lock); + gst_gl_context_create (priv->context, priv->other_context, NULL); + GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); return TRUE; } diff --git a/ext/gtk/gtkgstglwidget.h b/ext/gtk/gtkgstglwidget.h index 923b5f3dc3..7f055c4818 100644 --- a/ext/gtk/gtkgstglwidget.h +++ b/ext/gtk/gtkgstglwidget.h @@ -25,6 +25,8 @@ #include #include +#include "gtkgstbasewidget.h" + G_BEGIN_DECLS GType gtk_gst_gl_widget_get_type (void); @@ -47,7 +49,7 @@ typedef struct _GtkGstGLWidgetPrivate GtkGstGLWidgetPrivate; struct _GtkGstGLWidget { /* */ - GtkGLArea parent; + GtkGstBaseWidget base; GtkGstGLWidgetPrivate *priv; }; @@ -60,14 +62,12 @@ struct _GtkGstGLWidget struct _GtkGstGLWidgetClass { /* */ - GtkGLAreaClass object_class; + GtkGstBaseWidgetClass base_class; }; GtkWidget * gtk_gst_gl_widget_new (void); gboolean gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * widget); -gboolean gtk_gst_gl_widget_set_caps (GtkGstGLWidget * widget, GstCaps *caps); -void gtk_gst_gl_widget_set_buffer (GtkGstGLWidget * widget, GstBuffer *buffer); GstGLDisplay * gtk_gst_gl_widget_get_display (GtkGstGLWidget * widget); GstGLContext * gtk_gst_gl_widget_get_context (GtkGstGLWidget * widget); GstGLContext * gtk_gst_gl_widget_get_gtk_context (GtkGstGLWidget * widget); From 2d7d6a8596ddb65b7973b68642048003a502c142 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 16 Jul 2015 15:59:59 -0400 Subject: [PATCH 067/128] gtkbasesink: Create a base class This contains all the common code between the gtkglsink and gtksink. https://bugzilla.gnome.org/show_bug.cgi?id=752441 --- ext/gtk/Makefile.am | 2 + ext/gtk/gstgtkbasesink.c | 364 +++++++++++++++++++++++++++++++++++++++ ext/gtk/gstgtkbasesink.h | 90 ++++++++++ 3 files changed, 456 insertions(+) create mode 100644 ext/gtk/gstgtkbasesink.c create mode 100644 ext/gtk/gstgtkbasesink.h diff --git a/ext/gtk/Makefile.am b/ext/gtk/Makefile.am index 58b4e3f965..f2e8c55184 100644 --- a/ext/gtk/Makefile.am +++ b/ext/gtk/Makefile.am @@ -12,6 +12,8 @@ sources = \ gtkgstbasewidget.h \ gtkgstwidget.c \ gtkgstwidget.h \ + gstgtkbasesink.c \ + gstgtkbasesink.h \ gstgtksink.c \ gstgtksink.h \ gstplugin.c \ diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c new file mode 100644 index 0000000000..f6aa195cd7 --- /dev/null +++ b/ext/gtk/gstgtkbasesink.c @@ -0,0 +1,364 @@ +/* + * GStreamer + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:gtkgstsink + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstgtkbasesink.h" + +GST_DEBUG_CATEGORY (gst_debug_gtk_base_sink); +#define GST_CAT_DEFAULT gst_debug_gtk_base_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_base_sink_finalize (GObject * object); +static void gst_gtk_base_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * param_spec); +static void gst_gtk_base_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * param_spec); + +static gboolean gst_gtk_base_sink_start (GstBaseSink * bsink); + +static GstStateChangeReturn +gst_gtk_base_sink_change_state (GstElement * element, + GstStateChange transition); + +static void gst_gtk_base_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, + GstClockTime * start, GstClockTime * end); +static gboolean gst_gtk_base_sink_set_caps (GstBaseSink * bsink, + GstCaps * caps); +static GstFlowReturn gst_gtk_base_sink_show_frame (GstVideoSink * bsink, + GstBuffer * buf); + +enum +{ + PROP_0, + PROP_WIDGET, + PROP_FORCE_ASPECT_RATIO, + PROP_PIXEL_ASPECT_RATIO, + PROP_IGNORE_ALPHA, +}; + +#define gst_gtk_base_sink_parent_class parent_class +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstGtkBaseSink, gst_gtk_base_sink, + GST_TYPE_VIDEO_SINK, GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_sink, + "gtkbasesink", 0, "Gtk Video Sink base class")); + +static void +gst_gtk_base_sink_class_init (GstGtkBaseSinkClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSinkClass *gstbasesink_class; + GstVideoSinkClass *gstvideosink_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesink_class = (GstBaseSinkClass *) klass; + gstvideosink_class = (GstVideoSinkClass *) klass; + + gobject_class->set_property = gst_gtk_base_sink_set_property; + gobject_class->get_property = gst_gtk_base_sink_get_property; + + 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)); + + gobject_class->finalize = gst_gtk_base_sink_finalize; + + gstelement_class->change_state = gst_gtk_base_sink_change_state; + gstbasesink_class->set_caps = gst_gtk_base_sink_set_caps; + gstbasesink_class->get_times = gst_gtk_base_sink_get_times; + gstbasesink_class->start = gst_gtk_base_sink_start; + + gstvideosink_class->show_frame = gst_gtk_base_sink_show_frame; +} + +static void +gst_gtk_base_sink_init (GstGtkBaseSink * 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_base_sink_finalize (GObject * object) +{ + GstGtkBaseSink *gtk_sink = GST_GTK_BASE_SINK (object);; + + g_clear_object (>k_sink->widget); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +widget_destroy_cb (GtkWidget * widget, GstGtkBaseSink * gtk_sink) +{ + GST_OBJECT_LOCK (gtk_sink); + g_clear_object (>k_sink->widget); + GST_OBJECT_UNLOCK (gtk_sink); +} + +static GtkGstBaseWidget * +gst_gtk_base_sink_get_widget (GstGtkBaseSink * 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; + } + + g_assert (GST_GTK_BASE_SINK_GET_CLASS (gtk_sink)->create_widget); + gtk_sink->widget = (GtkGstBaseWidget *) + GST_GTK_BASE_SINK_GET_CLASS (gtk_sink)->create_widget (); + + gtk_sink->bind_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, other wise 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_base_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstGtkBaseSink *gtk_sink = GST_GTK_BASE_SINK (object); + + switch (prop_id) { + case PROP_WIDGET: + g_value_set_object (value, gst_gtk_base_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_base_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstGtkBaseSink *gtk_sink = GST_GTK_BASE_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 +gst_gtk_base_sink_start (GstBaseSink * bsink) +{ + GstGtkBaseSink *gst_sink = GST_GTK_BASE_SINK (bsink); + GstGtkBaseSinkClass *klass = GST_GTK_BASE_SINK_GET_CLASS (bsink); + GtkWidget *toplevel; + + if (gst_gtk_base_sink_get_widget (gst_sink) == NULL) + return FALSE; + + /* After this point, gtk_sink->widget will always be set */ + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (gst_sink->widget)); + if (!gtk_widget_is_toplevel (toplevel)) { + GtkWidget *window; + + /* sanity check */ + g_assert (klass->window_title); + + /* 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), klass->window_title); + gtk_container_add (GTK_CONTAINER (window), toplevel); + gtk_widget_show_all (window); + } + + return TRUE; +} + +static GstStateChangeReturn +gst_gtk_base_sink_change_state (GstElement * element, GstStateChange transition) +{ + GstGtkBaseSink *gtk_sink = GST_GTK_BASE_SINK (element); + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + GST_DEBUG_OBJECT (element, "changing state: %s => %s", + gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)), + gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition))); + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + switch (transition) { + 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; + default: + break; + } + + return ret; +} + +static void +gst_gtk_base_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, + GstClockTime * start, GstClockTime * end) +{ + GstGtkBaseSink *gtk_sink; + + gtk_sink = GST_GTK_BASE_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_base_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) +{ + GstGtkBaseSink *gtk_sink = GST_GTK_BASE_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_gst_base_widget_set_caps (gtk_sink->widget, caps)) + return FALSE; + + GST_OBJECT_UNLOCK (gtk_sink); + + return TRUE; +} + +static GstFlowReturn +gst_gtk_base_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) +{ + GstGtkBaseSink *gtk_sink; + + GST_TRACE ("rendering buffer:%p", buf); + + gtk_sink = GST_GTK_BASE_SINK (vsink); + + GST_OBJECT_LOCK (vsink); + + 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 GST_FLOW_ERROR; + } + + gtk_gst_base_widget_set_buffer (gtk_sink->widget, buf); + + GST_OBJECT_UNLOCK (gtk_sink); + + return GST_FLOW_OK; +} diff --git a/ext/gtk/gstgtkbasesink.h b/ext/gtk/gstgtkbasesink.h new file mode 100644 index 0000000000..6158d81ed0 --- /dev/null +++ b/ext/gtk/gstgtkbasesink.h @@ -0,0 +1,90 @@ +/* + * GStreamer + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_GTK_BASE_SINK_H__ +#define __GST_GTK_BASE_SINK_H__ + +#include +#include +#include +#include + +#include "gtkgstbasewidget.h" + +#define GST_TYPE_GTK_BASE_SINK (gst_gtk_base_sink_get_type()) +#define GST_GTK_BASE_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GTK_BASE_SINK,GstGtkBaseSink)) +#define GST_GTK_BASE_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GTK_BASE_SINK,GstGtkBaseSinkClass)) +#define GST_GTK_BASE_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_GTK_BASE_SINK, GstGtkBaseSinkClass)) +#define GST_IS_GTK_BASE_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GTK_BASE_SINK)) +#define GST_IS_GTK_BASE_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GTK_BASE_SINK)) +#define GST_GTK_BASE_SINK_CAST(obj) ((GstGtkBaseSink*)(obj)) + +G_BEGIN_DECLS + +typedef struct _GstGtkBaseSink GstGtkBaseSink; +typedef struct _GstGtkBaseSinkClass GstGtkBaseSinkClass; + +GType gst_gtk_base_sink_get_type (void); + +/** + * GstGtkBaseSink: + * + * Opaque #GstGtkBaseSink object + */ +struct _GstGtkBaseSink +{ + /* */ + GstVideoSink parent; + + GstVideoInfo v_info; + + GtkGstBaseWidget *widget; + + /* properties */ + gboolean force_aspect_ratio; + GBinding *bind_aspect_ratio; + + gint par_n; + gint par_d; + GBinding *bind_pixel_aspect_ratio; + + gboolean ignore_alpha; + GBinding *bind_ignore_alpha; +}; + +/** + * GstGtkBaseSinkClass: + * + * The #GstGtkBaseSinkClass struct only contains private data + */ +struct _GstGtkBaseSinkClass +{ + GstVideoSinkClass object_class; + + /* metadata */ + const gchar *window_title; + + /* virtuals */ + GtkWidget* (*create_widget) (void); +}; + +G_END_DECLS + +#endif /* __GST_GTK_BASE_SINK_H__ */ From 0a4c1d8b52c0564d393b9051d241b9ec2c853fbd Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 16 Jul 2015 16:00:37 -0400 Subject: [PATCH 068/128] gtksink: Port to GstGtkBaseSink https://bugzilla.gnome.org/show_bug.cgi?id=752441 --- ext/gtk/gstgtksink.c | 351 +------------------------------------------ ext/gtk/gstgtksink.h | 36 ++--- 2 files changed, 16 insertions(+), 371 deletions(-) diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index c171c604a2..4659221640 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -27,35 +27,9 @@ #include "config.h" #endif +#include "gtkgstwidget.h" #include "gstgtksink.h" -GST_DEBUG_CATEGORY (gst_debug_gtk_sink); -#define GST_CAT_DEFAULT gst_debug_gtk_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_sink_finalize (GObject * object); -static void gst_gtk_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * param_spec); -static void gst_gtk_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * param_spec); - -static gboolean gst_gtk_sink_stop (GstBaseSink * bsink); - -static gboolean gst_gtk_sink_query (GstBaseSink * bsink, GstQuery * query); - -static GstStateChangeReturn -gst_gtk_sink_change_state (GstElement * element, GstStateChange transition); - -static void gst_gtk_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, - GstClockTime * start, GstClockTime * end); -static gboolean gst_gtk_sink_set_caps (GstBaseSink * bsink, GstCaps * caps); -static GstFlowReturn gst_gtk_sink_show_frame (GstVideoSink * bsink, - GstBuffer * buf); - #if G_BYTE_ORDER == G_LITTLE_ENDIAN #define FORMATS "{ BGRx, BGRA }" #else @@ -69,343 +43,30 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (FORMATS)) ); -enum -{ - PROP_0, - PROP_WIDGET, - PROP_FORCE_ASPECT_RATIO, - PROP_PIXEL_ASPECT_RATIO, - PROP_IGNORE_ALPHA, -}; - -enum -{ - SIGNAL_0, - LAST_SIGNAL -}; - #define gst_gtk_sink_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstGtkSink, gst_gtk_sink, - GST_TYPE_VIDEO_SINK, GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_sink, "gtksink", - 0, "Gtk Video Sink")); +G_DEFINE_TYPE (GstGtkSink, gst_gtk_sink, GST_TYPE_GTK_BASE_SINK); static void gst_gtk_sink_class_init (GstGtkSinkClass * klass) { - GObjectClass *gobject_class; GstElementClass *gstelement_class; - GstBaseSinkClass *gstbasesink_class; - GstVideoSinkClass *gstvideosink_class; + GstGtkBaseSinkClass *base_class; - gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; - gstbasesink_class = (GstBaseSinkClass *) klass; - gstvideosink_class = (GstVideoSinkClass *) klass; + base_class = (GstGtkBaseSinkClass *) klass; - gobject_class->set_property = gst_gtk_sink_set_property; - gobject_class->get_property = gst_gtk_sink_get_property; + base_class->create_widget = gtk_gst_widget_new; + base_class->window_title = "Gtk+ Cairo 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_sink_template)); - - gobject_class->finalize = gst_gtk_sink_finalize; - - gstelement_class->change_state = gst_gtk_sink_change_state; - gstbasesink_class->query = gst_gtk_sink_query; - gstbasesink_class->set_caps = gst_gtk_sink_set_caps; - gstbasesink_class->get_times = gst_gtk_sink_get_times; - gstbasesink_class->stop = gst_gtk_sink_stop; - - gstvideosink_class->show_frame = gst_gtk_sink_show_frame; } static void gst_gtk_sink_init (GstGtkSink * 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_sink_finalize (GObject * object) -{ - GstGtkSink *gtk_sink = GST_GTK_SINK (object);; - - g_clear_object (>k_sink->widget); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -widget_destroy_cb (GtkWidget * widget, GstGtkSink * gtk_sink) -{ - GST_OBJECT_LOCK (gtk_sink); - g_clear_object (>k_sink->widget); - GST_OBJECT_UNLOCK (gtk_sink); -} - -static GtkGstBaseWidget * -gst_gtk_sink_get_widget (GstGtkSink * 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_widget_new (); - gtk_sink->bind_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, other wise 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_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstGtkSink *gtk_sink = GST_GTK_SINK (object); - - switch (prop_id) { - case PROP_WIDGET: - g_value_set_object (value, gst_gtk_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_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstGtkSink *gtk_sink = GST_GTK_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 -gst_gtk_sink_query (GstBaseSink * bsink, GstQuery * query) -{ - gboolean res = FALSE; - - switch (GST_QUERY_TYPE (query)) { - default: - res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); - break; - } - - return res; -} - -static gboolean -gst_gtk_sink_stop (GstBaseSink * bsink) -{ - return TRUE; -} - -static GstStateChangeReturn -gst_gtk_sink_change_state (GstElement * element, GstStateChange transition) -{ - GstGtkSink *gtk_sink = GST_GTK_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: - if (gst_gtk_sink_get_widget (gtk_sink) == NULL) - return GST_STATE_CHANGE_FAILURE; - - /* After this point, gtk_sink->widget will always be set */ - - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (gtk_sink->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+ Cairo renderer"); - gtk_container_add (GTK_CONTAINER (window), toplevel); - gtk_widget_show_all (window); - } - - 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: - break; - default: - break; - } - - return ret; -} - -static void -gst_gtk_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, - GstClockTime * start, GstClockTime * end) -{ - GstGtkSink *gtk_sink; - - gtk_sink = GST_GTK_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_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) -{ - GstGtkSink *gtk_sink = GST_GTK_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_gst_base_widget_set_caps (gtk_sink->widget, caps)) - return FALSE; - - GST_OBJECT_UNLOCK (gtk_sink); - - return TRUE; -} - -static GstFlowReturn -gst_gtk_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) -{ - GstGtkSink *gtk_sink; - - GST_TRACE ("rendering buffer:%p", buf); - - gtk_sink = GST_GTK_SINK (vsink); - - GST_OBJECT_LOCK (vsink); - - 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 GST_FLOW_ERROR; - } - - gtk_gst_base_widget_set_buffer (gtk_sink->widget, buf); - - GST_OBJECT_UNLOCK (gtk_sink); - - return GST_FLOW_OK; } diff --git a/ext/gtk/gstgtksink.h b/ext/gtk/gstgtksink.h index 40eaa948d0..7dad3b0539 100644 --- a/ext/gtk/gstgtksink.h +++ b/ext/gtk/gstgtksink.h @@ -26,14 +26,8 @@ #include #include -typedef struct _GstGtkSink GstGtkSink; -typedef struct _GstGtkSinkClass GstGtkSinkClass; +#include "gstgtkbasesink.h" -#include - -G_BEGIN_DECLS - -GType gst_gtk_sink_get_type (void); #define GST_TYPE_GTK_SINK (gst_gtk_sink_get_type()) #define GST_GTK_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GTK_SINK,GstGtkSink)) #define GST_GTK_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GTK_SINK,GstGtkSinkClass)) @@ -41,6 +35,13 @@ GType gst_gtk_sink_get_type (void); #define GST_IS_GTK_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GTK_SINK)) #define GST_GTK_SINK_CAST(obj) ((GstGtkSink*)(obj)) +G_BEGIN_DECLS + +typedef struct _GstGtkSink GstGtkSink; +typedef struct _GstGtkSinkClass GstGtkSinkClass; + +GType gst_gtk_sink_get_type (void); + /** * GstGtkSink: * @@ -49,22 +50,7 @@ GType gst_gtk_sink_get_type (void); struct _GstGtkSink { /* */ - GstVideoSink parent; - - GstVideoInfo v_info; - - GtkGstBaseWidget *widget; - - /* properties */ - gboolean force_aspect_ratio; - GBinding *bind_aspect_ratio; - - gint par_n; - gint par_d; - GBinding *bind_pixel_aspect_ratio; - - gboolean ignore_alpha; - GBinding *bind_ignore_alpha; + GstGtkBaseSink parent; }; /** @@ -75,11 +61,9 @@ struct _GstGtkSink struct _GstGtkSinkClass { /* */ - GstVideoSinkClass object_class; + GstGtkBaseSinkClass object_class; }; -GstGtkSink * gst_gtk_sink_new (void); - G_END_DECLS #endif /* __GST_GTK_SINK_H__ */ From 5584005f96311936a6c742bae74fba660297d2fa Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 16 Jul 2015 16:49:32 -0400 Subject: [PATCH 069/128] gtkglsink: Port to GstGtkBaseSink base class https://bugzilla.gnome.org/show_bug.cgi?id=752441 --- ext/gtk/gstgtkglsink.c | 422 ++++++----------------------------------- ext/gtk/gstgtkglsink.h | 36 +--- 2 files changed, 64 insertions(+), 394 deletions(-) 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__ */ From d09949927582a41ef4d4d263b3b37137d8bf60b9 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 17 Jul 2015 13:05:05 -0400 Subject: [PATCH 070/128] gtkgstbasewidget: Pass already parsed VideoInfo As the base sink already parse the caps into VideoInfo it makes sense to pass in VideoInfo to the widget instead. https://bugzilla.gnome.org/show_bug.cgi?id=752441 --- ext/gtk/gstgtkbasesink.c | 2 +- ext/gtk/gtkgstbasewidget.c | 21 +++++++++------------ ext/gtk/gtkgstbasewidget.h | 3 +-- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index f6aa195cd7..6fd70b0223 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -330,7 +330,7 @@ gst_gtk_base_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) return FALSE; } - if (!gtk_gst_base_widget_set_caps (gtk_sink->widget, caps)) + if (!gtk_gst_base_widget_set_format (gtk_sink->widget, >k_sink->v_info)) return FALSE; GST_OBJECT_UNLOCK (gtk_sink); diff --git a/ext/gtk/gtkgstbasewidget.c b/ext/gtk/gtkgstbasewidget.c index 972541ff7a..1fd76b3c47 100644 --- a/ext/gtk/gtkgstbasewidget.c +++ b/ext/gtk/gtkgstbasewidget.c @@ -258,22 +258,20 @@ gtk_gst_base_widget_finalize (GObject * object) } gboolean -gtk_gst_base_widget_set_caps (GtkGstBaseWidget * widget, GstCaps * caps) +gtk_gst_base_widget_set_format (GtkGstBaseWidget * widget, + GstVideoInfo * v_info) { - GstVideoInfo v_info; - - if (widget->caps && gst_caps_is_equal_fixed (widget->caps, caps)) - return TRUE; - - if (!gst_video_info_from_caps (&v_info, caps)) - return FALSE; - GTK_GST_BASE_WIDGET_LOCK (widget); + if (gst_video_info_is_equal (&widget->v_info, v_info)) { + GTK_GST_BASE_WIDGET_UNLOCK (widget); + return TRUE; + } + /* FIXME this will cause black frame to be displayed, move this in the * _queue_resize callback passing over the video info */ - if (!_calculate_par (widget, &v_info)) { + if (!_calculate_par (widget, v_info)) { GTK_GST_BASE_WIDGET_UNLOCK (widget); return FALSE; } @@ -282,8 +280,7 @@ gtk_gst_base_widget_set_caps (GtkGstBaseWidget * widget, GstCaps * caps) widget->reset (widget); gst_buffer_replace (&widget->buffer, NULL); - gst_caps_replace (&widget->caps, caps); - widget->v_info = v_info; + widget->v_info = *v_info; widget->negotiated = TRUE; widget->new_buffer = TRUE; diff --git a/ext/gtk/gtkgstbasewidget.h b/ext/gtk/gtkgstbasewidget.h index e4242f192a..e39f25b7ab 100644 --- a/ext/gtk/gtkgstbasewidget.h +++ b/ext/gtk/gtkgstbasewidget.h @@ -62,7 +62,6 @@ struct _GtkGstBaseWidget /*< private >*/ GMutex lock; - GstCaps *caps; /* Pending queued idles callback */ guint draw_id; @@ -86,7 +85,7 @@ void gtk_gst_base_widget_init (GtkGstBaseWidget * wid void gtk_gst_base_widget_finalize (GObject * object); /* API */ -gboolean gtk_gst_base_widget_set_caps (GtkGstBaseWidget * widget, GstCaps *caps); +gboolean gtk_gst_base_widget_set_format (GtkGstBaseWidget * widget, GstVideoInfo *v_info); void gtk_gst_base_widget_set_buffer (GtkGstBaseWidget * widget, GstBuffer *buffer); G_END_DECLS From b2619df0ae02f4b9e6752463963f26f67ac43635 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 17 Jul 2015 14:36:56 -0400 Subject: [PATCH 071/128] gtkgstbasewidget: Fix black frame on resize This is solved by only applying the new format when the next buffer is to be rendered and on the GTK thread. https://bugzilla.gnome.org/show_bug.cgi?id=752441 --- ext/gtk/gtkgstbasewidget.c | 88 ++++++++++++++++++++------------------ ext/gtk/gtkgstbasewidget.h | 13 ++++-- 2 files changed, 55 insertions(+), 46 deletions(-) diff --git a/ext/gtk/gtkgstbasewidget.c b/ext/gtk/gtkgstbasewidget.c index 1fd76b3c47..0cfed24b17 100644 --- a/ext/gtk/gtkgstbasewidget.c +++ b/ext/gtk/gtkgstbasewidget.c @@ -116,19 +116,6 @@ gtk_gst_base_widget_get_property (GObject * object, guint prop_id, } } -static gboolean -_queue_resize (GtkGstBaseWidget * widget) -{ - GTK_GST_BASE_WIDGET_LOCK (widget); - widget->resize_id = 0; - - GTK_GST_BASE_WIDGET_UNLOCK (widget); - - gtk_widget_queue_resize (GTK_WIDGET (widget)); - - return G_SOURCE_REMOVE; -} - static gboolean _calculate_par (GtkGstBaseWidget * widget, GstVideoInfo * info) { @@ -136,7 +123,6 @@ _calculate_par (GtkGstBaseWidget * widget, GstVideoInfo * info) gint width, height; gint par_n, par_d; gint display_par_n, display_par_d; - guint display_ratio_num, display_ratio_den; width = GST_VIDEO_INFO_WIDTH (info); height = GST_VIDEO_INFO_HEIGHT (info); @@ -156,14 +142,31 @@ _calculate_par (GtkGstBaseWidget * widget, GstVideoInfo * info) display_par_d = 1; } - ok = gst_video_calculate_display_ratio (&display_ratio_num, - &display_ratio_den, width, height, par_n, par_d, display_par_n, + + ok = gst_video_calculate_display_ratio (&widget->display_ratio_num, + &widget->display_ratio_den, width, height, par_n, par_d, display_par_n, display_par_d); - if (!ok) - return FALSE; + if (ok) { + GST_LOG ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n, + display_par_d); + return TRUE; + } - GST_LOG ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n, display_par_d); + return FALSE; +} + +static void +_apply_par (GtkGstBaseWidget * widget) +{ + guint display_ratio_num, display_ratio_den; + gint width, height; + + width = GST_VIDEO_INFO_WIDTH (&widget->v_info); + height = GST_VIDEO_INFO_HEIGHT (&widget->v_info); + + display_ratio_num = widget->display_ratio_num; + display_ratio_den = widget->display_ratio_den; if (height % display_ratio_den == 0) { GST_DEBUG ("keeping video height"); @@ -185,18 +188,33 @@ _calculate_par (GtkGstBaseWidget * widget, GstVideoInfo * info) } GST_DEBUG ("scaling to %dx%d", widget->display_width, widget->display_height); - - return TRUE; } +/* note, buffer is not refrence, it's only passed for pointer comparision */ static gboolean _queue_draw (GtkGstBaseWidget * widget) { GTK_GST_BASE_WIDGET_LOCK (widget); widget->draw_id = 0; - GTK_GST_BASE_WIDGET_UNLOCK (widget); - gtk_widget_queue_draw (GTK_WIDGET (widget)); + if (widget->pending_resize) { + widget->pending_resize = FALSE; + + if (widget->reset) + widget->reset (widget); + + widget->v_info = widget->pending_v_info; + widget->negotiated = TRUE; + widget->new_buffer = TRUE; + + _apply_par (widget); + + gtk_widget_queue_resize (GTK_WIDGET (widget)); + } else { + gtk_widget_queue_draw (GTK_WIDGET (widget)); + } + + GTK_GST_BASE_WIDGET_UNLOCK (widget); return G_SOURCE_REMOVE; } @@ -239,6 +257,9 @@ gtk_gst_base_widget_init (GtkGstBaseWidget * widget) widget->par_d = DEFAULT_PAR_D; widget->ignore_alpha = DEFAULT_IGNORE_ALPHA; + gst_video_info_init (&widget->v_info); + gst_video_info_init (&widget->pending_v_info); + g_mutex_init (&widget->lock); } @@ -252,9 +273,6 @@ gtk_gst_base_widget_finalize (GObject * object) if (widget->draw_id) g_source_remove (widget->draw_id); - - if (widget->resize_id) - g_source_remove (widget->resize_id); } gboolean @@ -268,26 +286,13 @@ gtk_gst_base_widget_set_format (GtkGstBaseWidget * widget, return TRUE; } - /* FIXME this will cause black frame to be displayed, move this in the - * _queue_resize callback passing over the video info */ - if (!_calculate_par (widget, v_info)) { GTK_GST_BASE_WIDGET_UNLOCK (widget); return FALSE; } - if (widget->reset) - widget->reset (widget); - - gst_buffer_replace (&widget->buffer, NULL); - widget->v_info = *v_info; - widget->negotiated = TRUE; - widget->new_buffer = TRUE; - - if (!widget->resize_id) { - widget->resize_id = g_idle_add_full (G_PRIORITY_DEFAULT, - (GSourceFunc) _queue_resize, widget, NULL); - } + widget->pending_resize = TRUE; + widget->pending_v_info = *v_info; GTK_GST_BASE_WIDGET_UNLOCK (widget); @@ -299,7 +304,6 @@ gtk_gst_base_widget_set_buffer (GtkGstBaseWidget * widget, GstBuffer * buffer) { /* As we have no type, this is better then no check */ g_return_if_fail (GTK_IS_WIDGET (widget)); - g_return_if_fail (buffer == NULL || widget->negotiated); GTK_GST_BASE_WIDGET_LOCK (widget); diff --git a/ext/gtk/gtkgstbasewidget.h b/ext/gtk/gtkgstbasewidget.h index e39f25b7ab..568027d781 100644 --- a/ext/gtk/gtkgstbasewidget.h +++ b/ext/gtk/gtkgstbasewidget.h @@ -57,15 +57,20 @@ struct _GtkGstBaseWidget GstVideoInfo v_info; gboolean new_buffer; + /* resize */ + gboolean pending_resize; + GstVideoInfo pending_v_info; + guint display_ratio_num; + guint display_ratio_den; + /* Poor-man virtual */ void (*reset) (GtkGstBaseWidget * widget); /*< private >*/ GMutex lock; - /* Pending queued idles callback */ + /* Pending draw idles callback */ guint draw_id; - guint resize_id; }; struct _GtkGstBaseWidgetClass @@ -85,8 +90,8 @@ void gtk_gst_base_widget_init (GtkGstBaseWidget * wid void gtk_gst_base_widget_finalize (GObject * object); /* API */ -gboolean gtk_gst_base_widget_set_format (GtkGstBaseWidget * widget, GstVideoInfo *v_info); -void gtk_gst_base_widget_set_buffer (GtkGstBaseWidget * widget, GstBuffer *buffer); +gboolean gtk_gst_base_widget_set_format (GtkGstBaseWidget * widget, GstVideoInfo * v_info); +void gtk_gst_base_widget_set_buffer (GtkGstBaseWidget * widget, GstBuffer * buffer); G_END_DECLS From 067051f6feda65b7960dd9308868fb87a885add3 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 17 Jul 2015 15:08:53 -0400 Subject: [PATCH 072/128] gtkglsink: Don't leak vertex array and buffers This is now possible since reset is always called from the main thread. https://bugzilla.gnome.org/show_bug.cgi?id=752441 --- ext/gtk/gtkgstglwidget.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index b721984785..ba01e604ea 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -360,6 +360,26 @@ _reset (GtkGstBaseWidget * base_widget) !base_widget->ignore_alpha); } +/* called from main thread */ +static void +gtk_gst_gl_widget_reset (GtkGstBaseWidget * base_widget) +{ + GtkGstGLWidgetPrivate *priv = GTK_GST_GL_WIDGET (base_widget)->priv; + const GstGLFuncs *gl = priv->other_context->gl_vtable; + + _reset (base_widget); + + if (priv->vao) { + gl->DeleteVertexArrays (1, &priv->vao); + priv->vao = 0; + } + + if (priv->vertex_buffer) { + gl->DeleteBuffers (1, &priv->vertex_buffer); + priv->vertex_buffer = 0; + } +} + static void gtk_gst_gl_widget_finalize (GObject * object) { @@ -393,7 +413,7 @@ gtk_gst_gl_widget_class_init (GtkGstGLWidgetClass * klass) gobject_klass->finalize = gtk_gst_gl_widget_finalize; gl_widget_klass->render = gtk_gst_gl_widget_render; - base_widget_klass->reset = _reset; + base_widget_klass->reset = gtk_gst_gl_widget_reset; } static void From 6fdedfc68a459d95299f4e3fec4c87f8eb2304c9 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 17 Jul 2015 15:57:37 -0400 Subject: [PATCH 073/128] gtksink: "widget" must be access from main thread Document that "widget" property must be accessed from the main thread (where GTK is running). This is the same for state transition on these elements. It is very natural to do so un GTK applications. --- ext/gtk/gstgtkbasesink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index 6fd70b0223..d53d77c584 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -88,7 +88,8 @@ gst_gtk_base_sink_class_init (GstGtkBaseSinkClass * klass) g_object_class_install_property (gobject_class, PROP_WIDGET, g_param_spec_object ("widget", "Gtk Widget", - "The GtkWidget to place in the widget heirachy", + "The GtkWidget to place in the widget hierarchy " + "(must only be get from the GTK main thread)", GTK_TYPE_WIDGET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO, From ef6bfe0eb4155e356e31b3470e1842e44ba9f0c4 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 17 Jul 2015 16:00:01 -0400 Subject: [PATCH 074/128] gtkgstglwidget: Cleanup unused private member new_buffer has been moved to base class. Also cleanup the properties comment, which are also all moved into the base class. --- ext/gtk/gtkgstglwidget.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index ba01e604ea..a17dd6b75d 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -58,9 +58,6 @@ G_DEFINE_TYPE_WITH_CODE (GtkGstGLWidget, gtk_gst_gl_widget, GTK_TYPE_GL_AREA, struct _GtkGstGLWidgetPrivate { - /* properties */ - gboolean new_buffer; - gboolean initted; GstGLDisplay *display; GdkGLContext *gdk_context; From ca97f5121a9fb733dd0d69d22895ac649afe1b91 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Sat, 18 Jul 2015 17:19:18 +1000 Subject: [PATCH 075/128] glcontext: fix get_current_gl_api on x11/nvidia drivers They require to get_proc_address some functions through the platform specific {glX,egl}GetProcAddress rather than the default GL library symbol lookup. --- ext/gtk/gtkgstglwidget.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index a17dd6b75d..c2cc46b8a5 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -477,7 +477,7 @@ _get_gl_context (GtkGstGLWidget * gst_widget) #if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11) if (GST_IS_GL_DISPLAY_X11 (priv->display)) { platform = GST_GL_PLATFORM_GLX; - gl_api = gst_gl_context_get_current_gl_api (NULL, NULL); + gl_api = gst_gl_context_get_current_gl_api (platform, NULL, NULL); gl_handle = gst_gl_context_get_current_gl_context (platform); if (gl_handle) priv->other_context = @@ -488,7 +488,7 @@ _get_gl_context (GtkGstGLWidget * gst_widget) #if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND) if (GST_IS_GL_DISPLAY_WAYLAND (priv->display)) { platform = GST_GL_PLATFORM_EGL; - gl_api = gst_gl_context_get_current_gl_api (NULL, NULL); + gl_api = gst_gl_context_get_current_gl_api (platform, NULL, NULL); gl_handle = gst_gl_context_get_current_gl_context (platform); if (gl_handle) priv->other_context = From b1d22b05152cbf6619d9686b05277d08ff17e6e2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 20 Jul 2015 11:09:20 +0200 Subject: [PATCH 076/128] gtk: Log GDK GL error when failling creating GdkGLContext --- ext/gtk/gtkgstglwidget.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index c2cc46b8a5..f8b8d267e7 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -51,7 +51,8 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); G_DEFINE_TYPE_WITH_CODE (GtkGstGLWidget, gtk_gst_gl_widget, GTK_TYPE_GL_AREA, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gtkgstglwidget", 0, - "Gtk Gst GL Widget");); + "Gtk Gst GL Widget"); + ); #define GTK_GST_GL_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ GTK_TYPE_GST_GL_WIDGET, GtkGstGLWidgetPrivate)) @@ -466,6 +467,10 @@ _get_gl_context (GtkGstGLWidget * gst_widget) g_object_unref (priv->gdk_context); priv->gdk_context = gtk_gl_area_get_context (GTK_GL_AREA (gst_widget)); if (priv->gdk_context == NULL) { + GError *error = gtk_gl_area_get_error (GTK_GL_AREA (gst_widget)); + + GST_ERROR_OBJECT (gst_widget, "Error creating GdkGLContext : %s", + error ? error->message : "No error set by Gdk"); g_assert_not_reached (); return; } From 47f3f98366618cea3e8002ad272cda8a4ec42d2a Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Tue, 21 Jul 2015 11:23:21 +0100 Subject: [PATCH 077/128] gstglwidget: use gst_gl_display_create_context Also handle the failure case. https://bugzilla.gnome.org/show_bug.cgi?id=750310 --- ext/gtk/gtkgstglwidget.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index f8b8d267e7..378632cb0b 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -530,6 +530,7 @@ gboolean gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * gst_widget) { GtkGstGLWidgetPrivate *priv = gst_widget->priv; + GError *error = NULL; g_return_val_if_fail (GTK_IS_GST_GL_WIDGET (gst_widget), FALSE); @@ -551,15 +552,13 @@ gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * gst_widget) return FALSE; } - priv->context = gst_gl_context_new (priv->display); - - if (!priv->context) { + if (!gst_gl_display_create_context (priv->display, priv->other_context, + &priv->context, &error)) { + g_clear_error (&error); GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); return FALSE; } - gst_gl_context_create (priv->context, priv->other_context, NULL); - GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); return TRUE; } From 6164fb5b45fc42b62798b7de9f70f6cb33f45ac4 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 11 Aug 2015 13:34:59 +0200 Subject: [PATCH 078/128] gtk: implement GstNavigation interface Now we can push key/mouse input into the pipeline for DVD use cases. --- ext/gtk/gstgtkbasesink.c | 37 ++++++++++++- ext/gtk/gtkgstbasewidget.c | 104 +++++++++++++++++++++++++++++++++++++ ext/gtk/gtkgstbasewidget.h | 2 + 3 files changed, 142 insertions(+), 1 deletion(-) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index d53d77c584..d0744a0c9e 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -56,6 +56,9 @@ static gboolean gst_gtk_base_sink_set_caps (GstBaseSink * bsink, static GstFlowReturn gst_gtk_base_sink_show_frame (GstVideoSink * bsink, GstBuffer * buf); +static void +gst_gtk_base_sink_navigation_interface_init (GstNavigationInterface * iface); + enum { PROP_0, @@ -67,7 +70,10 @@ enum #define gst_gtk_base_sink_parent_class parent_class G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstGtkBaseSink, gst_gtk_base_sink, - GST_TYPE_VIDEO_SINK, GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_sink, + GST_TYPE_VIDEO_SINK, + G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION, + gst_gtk_base_sink_navigation_interface_init); + GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_sink, "gtkbasesink", 0, "Gtk Video Sink base class")); static void @@ -179,6 +185,10 @@ gst_gtk_base_sink_get_widget (GstGtkBaseSink * gtk_sink) g_signal_connect (gtk_sink->widget, "destroy", G_CALLBACK (widget_destroy_cb), gtk_sink); + /* back pointer */ + gtk_gst_base_widget_set_element (GTK_GST_BASE_WIDGET (gtk_sink->widget), + GST_ELEMENT (gtk_sink)); + return gtk_sink->widget; } @@ -230,6 +240,31 @@ gst_gtk_base_sink_set_property (GObject * object, guint prop_id, } } +static void +gst_gtk_base_sink_navigation_send_event (GstNavigation * navigation, + GstStructure * structure) +{ + GstGtkBaseSink *sink = GST_GTK_BASE_SINK (navigation); + GstEvent *event; + GstPad *pad; + + event = gst_event_new_navigation (structure); + pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink)); + + GST_TRACE_OBJECT (sink, "navigation event %" GST_PTR_FORMAT, structure); + + if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) + gst_pad_send_event (pad, event); + + gst_object_unref (pad); +} + +static void +gst_gtk_base_sink_navigation_interface_init (GstNavigationInterface * iface) +{ + iface->send_event = gst_gtk_base_sink_navigation_send_event; +} + static gboolean gst_gtk_base_sink_start (GstBaseSink * bsink) { diff --git a/ext/gtk/gtkgstbasewidget.c b/ext/gtk/gtkgstbasewidget.c index 0cfed24b17..4870fa4130 100644 --- a/ext/gtk/gtkgstbasewidget.c +++ b/ext/gtk/gtkgstbasewidget.c @@ -219,6 +219,85 @@ _queue_draw (GtkGstBaseWidget * widget) return G_SOURCE_REMOVE; } +static const gchar * +_gdk_key_to_navigation_string (guint keyval) +{ + /* TODO: expand */ + switch (keyval) { +#define KEY(key) case GDK_KEY_ ## key: return G_STRINGIFY(key) + KEY (Up); + KEY (Down); + KEY (Left); + KEY (Right); + KEY (Home); + KEY (End); +#undef KEY + default: + return NULL; + } +} + +static gboolean +gtk_gst_base_widget_key_event (GtkWidget * widget, GdkEventKey * event) +{ + GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget); + GstElement *element; + + if ((element = g_weak_ref_get (&base_widget->element))) { + if (GST_IS_NAVIGATION (element)) { + const gchar *str = _gdk_key_to_navigation_string (event->keyval); + const gchar *key_type = + event->type == GDK_KEY_PRESS ? "key-press" : "key-release"; + + if (!str) + str = event->string; + + gst_navigation_send_key_event (GST_NAVIGATION (element), key_type, str); + } + g_object_unref (element); + } + + return TRUE; +} + +static gboolean +gtk_gst_base_widget_button_event (GtkWidget * widget, GdkEventButton * event) +{ + GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget); + GstElement *element; + + if ((element = g_weak_ref_get (&base_widget->element))) { + if (GST_IS_NAVIGATION (element)) { + const gchar *key_type = + event->type == + GDK_BUTTON_PRESS ? "mouse-button-press" : "mouse-button-release"; + + gst_navigation_send_mouse_event (GST_NAVIGATION (element), key_type, + event->button, event->x, event->y); + } + g_object_unref (element); + } + + return TRUE; +} + +static gboolean +gtk_gst_base_widget_motion_event (GtkWidget * widget, GdkEventMotion * event) +{ + GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget); + GstElement *element; + + if ((element = g_weak_ref_get (&base_widget->element))) { + if (GST_IS_NAVIGATION (element)) { + gst_navigation_send_mouse_event (GST_NAVIGATION (element), "motion-move", + 0, event->x, event->y); + } + g_object_unref (element); + } + + return TRUE; +} + void gtk_gst_base_widget_class_init (GtkGstBaseWidgetClass * klass) { @@ -247,11 +326,18 @@ gtk_gst_base_widget_class_init (GtkGstBaseWidgetClass * klass) widget_klass->get_preferred_width = gtk_gst_base_widget_get_preferred_width; widget_klass->get_preferred_height = gtk_gst_base_widget_get_preferred_height; + widget_klass->key_press_event = gtk_gst_base_widget_key_event; + widget_klass->key_release_event = gtk_gst_base_widget_key_event; + widget_klass->button_press_event = gtk_gst_base_widget_button_event; + widget_klass->button_release_event = gtk_gst_base_widget_button_event; + widget_klass->motion_notify_event = gtk_gst_base_widget_motion_event; } void gtk_gst_base_widget_init (GtkGstBaseWidget * widget) { + int event_mask; + widget->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; widget->par_n = DEFAULT_PAR_N; widget->par_d = DEFAULT_PAR_D; @@ -260,7 +346,17 @@ gtk_gst_base_widget_init (GtkGstBaseWidget * widget) gst_video_info_init (&widget->v_info); gst_video_info_init (&widget->pending_v_info); + g_weak_ref_init (&widget->element, NULL); g_mutex_init (&widget->lock); + + gtk_widget_set_can_focus (GTK_WIDGET (widget), TRUE); + event_mask = gtk_widget_get_events (GTK_WIDGET (widget)); + event_mask |= GDK_KEY_PRESS_MASK + | GDK_KEY_RELEASE_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK; + gtk_widget_set_events (GTK_WIDGET (widget), event_mask); } void @@ -270,11 +366,19 @@ gtk_gst_base_widget_finalize (GObject * object) gst_buffer_replace (&widget->buffer, NULL); g_mutex_clear (&widget->lock); + g_weak_ref_clear (&widget->element); if (widget->draw_id) g_source_remove (widget->draw_id); } +void +gtk_gst_base_widget_set_element (GtkGstBaseWidget * widget, + GstElement * element) +{ + g_weak_ref_set (&widget->element, element); +} + gboolean gtk_gst_base_widget_set_format (GtkGstBaseWidget * widget, GstVideoInfo * v_info) diff --git a/ext/gtk/gtkgstbasewidget.h b/ext/gtk/gtkgstbasewidget.h index 568027d781..a402385625 100644 --- a/ext/gtk/gtkgstbasewidget.h +++ b/ext/gtk/gtkgstbasewidget.h @@ -68,6 +68,7 @@ struct _GtkGstBaseWidget /*< private >*/ GMutex lock; + GWeakRef element; /* Pending draw idles callback */ guint draw_id; @@ -92,6 +93,7 @@ void gtk_gst_base_widget_finalize (GObject * object); /* API */ gboolean gtk_gst_base_widget_set_format (GtkGstBaseWidget * widget, GstVideoInfo * v_info); void gtk_gst_base_widget_set_buffer (GtkGstBaseWidget * widget, GstBuffer * buffer); +void gtk_gst_base_widget_set_element (GtkGstBaseWidget * widget, GstElement * element); G_END_DECLS From 68dd460c4e202e109e2a6534b65d40f7340f02d8 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Wed, 12 Aug 2015 00:14:14 +0200 Subject: [PATCH 079/128] gtk: correct navigation events for window scaling i.e. take into account the possiblity of scaling in the sink or through GDK_SCALE. Fixes DVD Menus with a scaled gtkwidget --- ext/gtk/gtkgstbasewidget.c | 77 +++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/ext/gtk/gtkgstbasewidget.c b/ext/gtk/gtkgstbasewidget.c index 4870fa4130..fc41fcfbda 100644 --- a/ext/gtk/gtkgstbasewidget.c +++ b/ext/gtk/gtkgstbasewidget.c @@ -260,6 +260,72 @@ gtk_gst_base_widget_key_event (GtkWidget * widget, GdkEventKey * event) return TRUE; } +static void +_fit_stream_to_allocated_size (GtkGstBaseWidget * base_widget, + GtkAllocation * allocation, GstVideoRectangle * result) +{ + if (base_widget->force_aspect_ratio) { + GstVideoRectangle src, dst; + + src.x = 0; + src.y = 0; + src.w = base_widget->display_width; + src.h = base_widget->display_height; + + dst.x = 0; + dst.y = 0; + dst.w = allocation->width; + dst.h = allocation->height; + + gst_video_sink_center_rect (src, dst, result, TRUE); + } else { + result->x = 0; + result->y = 0; + result->w = allocation->width; + result->h = allocation->height; + } +} + +static void +_display_size_to_stream_size (GtkGstBaseWidget * base_widget, gdouble x, + gdouble y, gdouble * stream_x, gdouble * stream_y) +{ + gdouble stream_width, stream_height; + GtkAllocation allocation; + GstVideoRectangle result; + + gtk_widget_get_allocation (GTK_WIDGET (base_widget), &allocation); + _fit_stream_to_allocated_size (base_widget, &allocation, &result); + + stream_width = (gdouble) GST_VIDEO_INFO_WIDTH (&base_widget->v_info); + stream_height = (gdouble) GST_VIDEO_INFO_HEIGHT (&base_widget->v_info); + + /* from display coordinates to stream coordinates */ + if (result.w > 0) + *stream_x = (x - result.x) / result.w * stream_width; + else + *stream_x = 0.; + + /* clip to stream size */ + if (*stream_x < 0.) + *stream_x = 0.; + if (*stream_x > GST_VIDEO_INFO_WIDTH (&base_widget->v_info)) + *stream_x = GST_VIDEO_INFO_WIDTH (&base_widget->v_info); + + /* same for y-axis */ + if (result.h > 0) + *stream_y = (y - result.y) / result.h * stream_height; + else + *stream_y = 0.; + + if (*stream_y < 0.) + *stream_y = 0.; + if (*stream_y > GST_VIDEO_INFO_HEIGHT (&base_widget->v_info)) + *stream_y = GST_VIDEO_INFO_HEIGHT (&base_widget->v_info); + + GST_TRACE ("transform %fx%f into %fx%f", x, y, *stream_x, *stream_y); +} + static gboolean gtk_gst_base_widget_button_event (GtkWidget * widget, GdkEventButton * event) { @@ -271,9 +337,12 @@ gtk_gst_base_widget_button_event (GtkWidget * widget, GdkEventButton * event) const gchar *key_type = event->type == GDK_BUTTON_PRESS ? "mouse-button-press" : "mouse-button-release"; + gdouble x, y; + + _display_size_to_stream_size (base_widget, event->x, event->y, &x, &y); gst_navigation_send_mouse_event (GST_NAVIGATION (element), key_type, - event->button, event->x, event->y); + event->button, x, y); } g_object_unref (element); } @@ -289,8 +358,12 @@ gtk_gst_base_widget_motion_event (GtkWidget * widget, GdkEventMotion * event) if ((element = g_weak_ref_get (&base_widget->element))) { if (GST_IS_NAVIGATION (element)) { + gdouble x, y; + + _display_size_to_stream_size (base_widget, event->x, event->y, &x, &y); + gst_navigation_send_mouse_event (GST_NAVIGATION (element), "motion-move", - 0, event->x, event->y); + 0, x, y); } g_object_unref (element); } From f277cb04985aec2792437b0303022a5cc480afd1 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Wed, 12 Aug 2015 00:18:20 +0200 Subject: [PATCH 080/128] gtk: fix motion event name s/motion/mouse/ Fixes hover interaction with DVD menus --- ext/gtk/gtkgstbasewidget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/gtk/gtkgstbasewidget.c b/ext/gtk/gtkgstbasewidget.c index fc41fcfbda..d5ba788462 100644 --- a/ext/gtk/gtkgstbasewidget.c +++ b/ext/gtk/gtkgstbasewidget.c @@ -362,7 +362,7 @@ gtk_gst_base_widget_motion_event (GtkWidget * widget, GdkEventMotion * event) _display_size_to_stream_size (base_widget, event->x, event->y, &x, &y); - gst_navigation_send_mouse_event (GST_NAVIGATION (element), "motion-move", + gst_navigation_send_mouse_event (GST_NAVIGATION (element), "mouse-move", 0, x, y); } g_object_unref (element); From 9afab22dd9c5703953e3d40f23a3ad1b5ec8f8cf Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 14 Aug 2015 18:07:15 +0200 Subject: [PATCH 081/128] gtkglsink: Remove reset path The reset path is bogus and there is no reason to get rid of these things during resize. --- ext/gtk/gtkgstbasewidget.c | 3 --- ext/gtk/gtkgstbasewidget.h | 3 --- ext/gtk/gtkgstglwidget.c | 42 -------------------------------------- 3 files changed, 48 deletions(-) diff --git a/ext/gtk/gtkgstbasewidget.c b/ext/gtk/gtkgstbasewidget.c index d5ba788462..4202a22ff3 100644 --- a/ext/gtk/gtkgstbasewidget.c +++ b/ext/gtk/gtkgstbasewidget.c @@ -200,9 +200,6 @@ _queue_draw (GtkGstBaseWidget * widget) if (widget->pending_resize) { widget->pending_resize = FALSE; - if (widget->reset) - widget->reset (widget); - widget->v_info = widget->pending_v_info; widget->negotiated = TRUE; widget->new_buffer = TRUE; diff --git a/ext/gtk/gtkgstbasewidget.h b/ext/gtk/gtkgstbasewidget.h index a402385625..0a05ca54d5 100644 --- a/ext/gtk/gtkgstbasewidget.h +++ b/ext/gtk/gtkgstbasewidget.h @@ -63,9 +63,6 @@ struct _GtkGstBaseWidget guint display_ratio_num; guint display_ratio_den; - /* Poor-man virtual */ - void (*reset) (GtkGstBaseWidget * widget); - /*< private >*/ GMutex lock; GWeakRef element; diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 378632cb0b..998428107a 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -342,50 +342,12 @@ _reset_gl (GtkGstGLWidget * gst_widget) priv->gdk_context = NULL; } -static void -_reset (GtkGstBaseWidget * base_widget) -{ - GtkGstGLWidgetPrivate *priv = GTK_GST_GL_WIDGET (base_widget)->priv; - - priv->initted = FALSE; - priv->vao = 0; - priv->vertex_buffer = 0; - priv->attr_position = 0; - priv->attr_texture = 0; - priv->current_tex = 0; - - gtk_gl_area_set_has_alpha (GTK_GL_AREA (base_widget), - !base_widget->ignore_alpha); -} - -/* called from main thread */ -static void -gtk_gst_gl_widget_reset (GtkGstBaseWidget * base_widget) -{ - GtkGstGLWidgetPrivate *priv = GTK_GST_GL_WIDGET (base_widget)->priv; - const GstGLFuncs *gl = priv->other_context->gl_vtable; - - _reset (base_widget); - - if (priv->vao) { - gl->DeleteVertexArrays (1, &priv->vao); - priv->vao = 0; - } - - if (priv->vertex_buffer) { - gl->DeleteBuffers (1, &priv->vertex_buffer); - priv->vertex_buffer = 0; - } -} - static void gtk_gst_gl_widget_finalize (GObject * object) { GtkGstGLWidgetPrivate *priv = GTK_GST_GL_WIDGET (object)->priv; GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (object); - _reset (base_widget); - if (priv->other_context) _invoke_on_main ((ThreadFunc) _reset_gl, base_widget); @@ -404,14 +366,12 @@ gtk_gst_gl_widget_class_init (GtkGstGLWidgetClass * klass) { GObjectClass *gobject_klass = (GObjectClass *) klass; GtkGLAreaClass *gl_widget_klass = (GtkGLAreaClass *) klass; - GtkGstBaseWidget *base_widget_klass = (GtkGstBaseWidget *) klass; g_type_class_add_private (klass, sizeof (GtkGstGLWidgetPrivate)); gtk_gst_base_widget_class_init (GTK_GST_BASE_WIDGET_CLASS (klass)); gobject_klass->finalize = gtk_gst_gl_widget_finalize; gl_widget_klass->render = gtk_gst_gl_widget_render; - base_widget_klass->reset = gtk_gst_gl_widget_reset; } static void @@ -451,8 +411,6 @@ gtk_gst_gl_widget_init (GtkGstGLWidget * gst_widget) !base_widget->ignore_alpha); } - - static void _get_gl_context (GtkGstGLWidget * gst_widget) { From cf44f5013a0b6bc6fb6dfbf4bf580d1907a62ace Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Sat, 15 Aug 2015 15:08:11 +0200 Subject: [PATCH 082/128] gtkglsink: Fix unsafe handling of buffer life time We need to keep the active buffer (the one we have retreive a texture id from) otherwise it's racy and upstream may upload new content before we have rendered or during later redisplay. --- ext/gtk/gtkgstbasewidget.c | 6 +-- ext/gtk/gtkgstbasewidget.h | 2 +- ext/gtk/gtkgstglwidget.c | 87 +++++++++++++++++++++++--------------- ext/gtk/gtkgstwidget.c | 9 ++++ 4 files changed, 65 insertions(+), 39 deletions(-) diff --git a/ext/gtk/gtkgstbasewidget.c b/ext/gtk/gtkgstbasewidget.c index 4202a22ff3..5c7cda31cb 100644 --- a/ext/gtk/gtkgstbasewidget.c +++ b/ext/gtk/gtkgstbasewidget.c @@ -190,7 +190,6 @@ _apply_par (GtkGstBaseWidget * widget) GST_DEBUG ("scaling to %dx%d", widget->display_width, widget->display_height); } -/* note, buffer is not refrence, it's only passed for pointer comparision */ static gboolean _queue_draw (GtkGstBaseWidget * widget) { @@ -202,7 +201,6 @@ _queue_draw (GtkGstBaseWidget * widget) widget->v_info = widget->pending_v_info; widget->negotiated = TRUE; - widget->new_buffer = TRUE; _apply_par (widget); @@ -434,6 +432,7 @@ gtk_gst_base_widget_finalize (GObject * object) { GtkGstBaseWidget *widget = GTK_GST_BASE_WIDGET (object); + gst_buffer_replace (&widget->pending_buffer, NULL); gst_buffer_replace (&widget->buffer, NULL); g_mutex_clear (&widget->lock); g_weak_ref_clear (&widget->element); @@ -481,8 +480,7 @@ gtk_gst_base_widget_set_buffer (GtkGstBaseWidget * widget, GstBuffer * buffer) GTK_GST_BASE_WIDGET_LOCK (widget); - gst_buffer_replace (&widget->buffer, buffer); - widget->new_buffer = TRUE; + gst_buffer_replace (&widget->pending_buffer, buffer); if (!widget->draw_id) { widget->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT, diff --git a/ext/gtk/gtkgstbasewidget.h b/ext/gtk/gtkgstbasewidget.h index 0a05ca54d5..13737c6322 100644 --- a/ext/gtk/gtkgstbasewidget.h +++ b/ext/gtk/gtkgstbasewidget.h @@ -53,9 +53,9 @@ struct _GtkGstBaseWidget gint display_height; gboolean negotiated; + GstBuffer *pending_buffer; GstBuffer *buffer; GstVideoInfo v_info; - gboolean new_buffer; /* resize */ gboolean pending_resize; diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 998428107a..dc24535aa0 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -197,6 +197,13 @@ _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) gl->BindTexture (GL_TEXTURE_2D, 0); } +static inline void +_draw_black (void) +{ + glClearColor (0.0, 0.0, 0.0, 0.0); + glClear (GL_COLOR_BUFFER_BIT); +} + static gboolean gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) { @@ -205,44 +212,56 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) GTK_GST_BASE_WIDGET_LOCK (widget); - if (!priv->initted && priv->context) + if (!priv->context || !priv->other_context) + goto done; + + gst_gl_context_activate (priv->other_context, TRUE); + + if (!priv->initted) gtk_gst_gl_widget_init_redisplay (GTK_GST_GL_WIDGET (widget)); - if (priv->initted && base_widget->negotiated && base_widget->buffer) { - GST_DEBUG ("rendering buffer %p with gdk context %p", - base_widget->buffer, context); - - gst_gl_context_activate (priv->other_context, TRUE); - - if (base_widget->new_buffer || priv->current_tex == 0) { - GstVideoFrame gl_frame; - GstGLSyncMeta *sync_meta; - - if (!gst_video_frame_map (&gl_frame, &base_widget->v_info, - base_widget->buffer, GST_MAP_READ | GST_MAP_GL)) { - goto error; - } - - sync_meta = gst_buffer_get_gl_sync_meta (base_widget->buffer); - if (sync_meta) { - gst_gl_sync_meta_set_sync_point (sync_meta, priv->context); - gst_gl_sync_meta_wait (sync_meta, priv->other_context); - } - - priv->current_tex = *(guint *) gl_frame.data[0]; - - gst_video_frame_unmap (&gl_frame); - } - - _redraw_texture (GTK_GST_GL_WIDGET (widget), priv->current_tex); - base_widget->new_buffer = FALSE; - } else { - error: - /* FIXME: nothing to display */ - glClearColor (0.0, 0.0, 0.0, 0.0); - glClear (GL_COLOR_BUFFER_BIT); + if (!priv->initted || !base_widget->negotiated) { + _draw_black (); + goto done; } + /* Upload latest buffer */ + if (base_widget->pending_buffer) { + GstBuffer *buffer = base_widget->pending_buffer; + GstVideoFrame gl_frame; + GstGLSyncMeta *sync_meta; + + if (!gst_video_frame_map (&gl_frame, &base_widget->v_info, buffer, + GST_MAP_READ | GST_MAP_GL)) { + _draw_black (); + goto done; + } + + + sync_meta = gst_buffer_get_gl_sync_meta (buffer); + if (sync_meta) { + gst_gl_sync_meta_set_sync_point (sync_meta, priv->context); + gst_gl_sync_meta_wait (sync_meta, priv->other_context); + } + + priv->current_tex = *(guint *) gl_frame.data[0]; + + gst_video_frame_unmap (&gl_frame); + + if (base_widget->buffer) + gst_buffer_unref (base_widget->buffer); + + /* Keep the buffer to ensure current_tex stay valid */ + base_widget->buffer = buffer; + base_widget->pending_buffer = NULL; + } + + GST_DEBUG ("rendering buffer %p with gdk context %p", + base_widget->buffer, context); + + _redraw_texture (GTK_GST_GL_WIDGET (widget), priv->current_tex); + +done: if (priv->other_context) gst_gl_context_activate (priv->other_context, FALSE); diff --git a/ext/gtk/gtkgstwidget.c b/ext/gtk/gtkgstwidget.c index 58326d76f9..5fe238a545 100644 --- a/ext/gtk/gtkgstwidget.c +++ b/ext/gtk/gtkgstwidget.c @@ -50,6 +50,15 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) GTK_GST_BASE_WIDGET_LOCK (gst_widget); + /* There is not much to optimize in term of redisplay, so simply swap the + * pending_buffer with the active buffer */ + if (gst_widget->pending_buffer) { + if (gst_widget->buffer) + gst_buffer_unref (gst_widget->buffer); + gst_widget->buffer = gst_widget->pending_buffer; + gst_widget->pending_buffer = NULL; + } + /* failed to map the video frame */ if (gst_widget->negotiated && gst_widget->buffer && gst_video_frame_map (&frame, &gst_widget->v_info, From aaf14659c1a3be32cf593647115c74d948148fae Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Sat, 15 Aug 2015 15:12:27 +0200 Subject: [PATCH 083/128] gtkglsink: Add overlay composition support Rendering composition overlay in GL with additional high resolution overlay being added. --- ext/gtk/gstgtkglsink.c | 79 ++++++++++++++++++++++++++++++++++++++++ ext/gtk/gstgtkglsink.h | 4 ++ ext/gtk/gtkgstglwidget.c | 10 +++++ 3 files changed, 93 insertions(+) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index cecad05fc6..16797d32c7 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -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; +} diff --git a/ext/gtk/gstgtkglsink.h b/ext/gtk/gstgtkglsink.h index dee1024786..789cf33f66 100644 --- a/ext/gtk/gstgtkglsink.h +++ b/ext/gtk/gstgtkglsink.h @@ -60,6 +60,10 @@ struct _GstGtkGLSink GstGLUpload *upload; GstBuffer *uploaded_buffer; + + /* read/write with object lock */ + gint display_width; + gint display_height; }; /** diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index dc24535aa0..cdce3aa547 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -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); From b9e27180ec18c62d35dd63014cc4c9facdecf41e Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Sat, 15 Aug 2015 14:31:15 +0200 Subject: [PATCH 084/128] glsink: Enable sync meta on pools we offer As the upload is asynchronous, we need to enable the sync meta to gain correct rendering. The buffer pool receiver don't know about that. --- ext/gtk/gstgtkglsink.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 16797d32c7..d59880c53f 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -249,6 +249,9 @@ gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, caps, size, 0, 0); + gst_buffer_pool_config_add_option (config, + GST_BUFFER_POOL_OPTION_GL_SYNC_META); + if (!gst_buffer_pool_set_config (pool, config)) goto config_failed; From 69c4630f1d0be84acea0b3e502962a12571d291b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 19 Aug 2015 13:52:21 +0300 Subject: [PATCH 085/128] gtk/gl: Use our GL function table instead of directly calling GL functions Otherwise we would have to link the plugin to the GL libraries directly. --- ext/gtk/gtkgstglwidget.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index cdce3aa547..1b2cadb011 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -202,10 +202,12 @@ _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) } static inline void -_draw_black (void) +_draw_black (GstGLContext * context) { - glClearColor (0.0, 0.0, 0.0, 0.0); - glClear (GL_COLOR_BUFFER_BIT); + const GstGLFuncs *gl = context->gl_vtable; + + gl->ClearColor (0.0, 0.0, 0.0, 0.0); + gl->Clear (GL_COLOR_BUFFER_BIT); } static gboolean @@ -225,7 +227,7 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) gtk_gst_gl_widget_init_redisplay (GTK_GST_GL_WIDGET (widget)); if (!priv->initted || !base_widget->negotiated) { - _draw_black (); + _draw_black (priv->other_context); goto done; } @@ -237,7 +239,7 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) if (!gst_video_frame_map (&gl_frame, &base_widget->v_info, buffer, GST_MAP_READ | GST_MAP_GL)) { - _draw_black (); + _draw_black (priv->other_context); goto done; } From f96d22bd457ac81df19015c416917576d82fce69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 31 Aug 2015 18:06:31 +0100 Subject: [PATCH 086/128] gtk, qt, gl: fix typo in debug and error messages --- ext/gtk/gtkgstglwidget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 1b2cadb011..79599b46fa 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -500,7 +500,7 @@ _get_gl_context (GtkGstGLWidget * gst_widget) gst_gl_context_activate (priv->other_context, TRUE); if (!gst_gl_context_fill_info (priv->other_context, &error)) { - GST_ERROR ("failed to retreive gdk context info: %s", error->message); + GST_ERROR ("failed to retrieve gdk context info: %s", error->message); g_object_unref (priv->other_context); priv->other_context = NULL; } else { From 6a119aec8d65b1ff827b765b938a3c185c7b43f1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 4 Sep 2015 15:43:40 +0200 Subject: [PATCH 087/128] gtk: Do not consider GtkEvents as handled Applications might still want to use them after the sink transformed them into GstNavigation events --- ext/gtk/gtkgstbasewidget.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/gtk/gtkgstbasewidget.c b/ext/gtk/gtkgstbasewidget.c index 5c7cda31cb..390ac246b7 100644 --- a/ext/gtk/gtkgstbasewidget.c +++ b/ext/gtk/gtkgstbasewidget.c @@ -252,7 +252,7 @@ gtk_gst_base_widget_key_event (GtkWidget * widget, GdkEventKey * event) g_object_unref (element); } - return TRUE; + return FALSE; } static void @@ -342,7 +342,7 @@ gtk_gst_base_widget_button_event (GtkWidget * widget, GdkEventButton * event) g_object_unref (element); } - return TRUE; + return FALSE; } static gboolean @@ -363,7 +363,7 @@ gtk_gst_base_widget_motion_event (GtkWidget * widget, GdkEventMotion * event) g_object_unref (element); } - return TRUE; + return FALSE; } void From 115691c50839d3aff9725bc985e54600115cecd9 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Thu, 10 Sep 2015 00:07:18 +1000 Subject: [PATCH 088/128] gtk, qt: more specifically define the compile time requirements Otherwise we could include headers/configurations that will never been installed. https://bugzilla.gnome.org/show_bug.cgi?id=754732 --- ext/gtk/gtkgstglwidget.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 79599b46fa..164fca336f 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -27,13 +27,13 @@ #include "gtkgstglwidget.h" #include -#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11) +#if GST_GL_HAVE_WINDOW_X11 && GST_GL_HAVE_PLATFORM_GLX && defined (GDK_WINDOWING_X11) #include #include #include #endif -#if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND) +#if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (GDK_WINDOWING_WAYLAND) #include #include #endif @@ -418,13 +418,13 @@ gtk_gst_gl_widget_init (GtkGstGLWidget * gst_widget) display = gdk_display_get_default (); -#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11) +#if GST_GL_HAVE_WINDOW_X11 && GST_GL_HAVE_PLATFORM_GLX && defined (GDK_WINDOWING_X11) if (GDK_IS_X11_DISPLAY (display)) priv->display = (GstGLDisplay *) gst_gl_display_x11_new_with_display (gdk_x11_display_get_xdisplay (display)); #endif -#if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND) +#if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (GDK_WINDOWING_WAYLAND) if (GDK_IS_WAYLAND_DISPLAY (display)) { struct wl_display *wayland_display = gdk_wayland_display_get_wl_display (display); @@ -468,7 +468,7 @@ _get_gl_context (GtkGstGLWidget * gst_widget) gdk_gl_context_make_current (priv->gdk_context); -#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11) +#if GST_GL_HAVE_WINDOW_X11 && GST_GL_HAVE_PLATFORM_GLX && defined (GDK_WINDOWING_X11) if (GST_IS_GL_DISPLAY_X11 (priv->display)) { platform = GST_GL_PLATFORM_GLX; gl_api = gst_gl_context_get_current_gl_api (platform, NULL, NULL); @@ -479,7 +479,7 @@ _get_gl_context (GtkGstGLWidget * gst_widget) platform, gl_api); } #endif -#if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND) +#if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (GDK_WINDOWING_WAYLAND) if (GST_IS_GL_DISPLAY_WAYLAND (priv->display)) { platform = GST_GL_PLATFORM_EGL; gl_api = gst_gl_context_get_current_gl_api (platform, NULL, NULL); From 35812bce5183a1606967d65edc4ca81667865d45 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Thu, 17 Sep 2015 13:35:02 +0900 Subject: [PATCH 089/128] gl: Fix GError leaks during failures https://bugzilla.gnome.org/show_bug.cgi?id=755140 --- ext/gtk/gtkgstglwidget.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 164fca336f..b16725fc96 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -460,6 +460,7 @@ _get_gl_context (GtkGstGLWidget * gst_widget) GST_ERROR_OBJECT (gst_widget, "Error creating GdkGLContext : %s", error ? error->message : "No error set by Gdk"); + g_clear_error (&error); g_assert_not_reached (); return; } @@ -501,6 +502,7 @@ _get_gl_context (GtkGstGLWidget * gst_widget) gst_gl_context_activate (priv->other_context, TRUE); if (!gst_gl_context_fill_info (priv->other_context, &error)) { GST_ERROR ("failed to retrieve gdk context info: %s", error->message); + g_clear_error (&error); g_object_unref (priv->other_context); priv->other_context = NULL; } else { From a006d5aabb9146a86d4edca650a078bbeceeb72e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 19 Sep 2015 11:46:37 +0200 Subject: [PATCH 090/128] gtkglsink: Hide and clean the GtkWindow we might create When stopping the sink we should always hide the window. https://bugzilla.gnome.org/show_bug.cgi?id=755249 --- ext/gtk/gstgtkbasesink.c | 28 +++++++++++++++++++++------- ext/gtk/gstgtkbasesink.h | 2 ++ ext/gtk/gstgtkglsink.c | 2 +- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index d0744a0c9e..42f74261a7 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -44,6 +44,7 @@ static void gst_gtk_base_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * param_spec); static gboolean gst_gtk_base_sink_start (GstBaseSink * bsink); +static gboolean gst_gtk_base_sink_stop (GstBaseSink * bsink); static GstStateChangeReturn gst_gtk_base_sink_change_state (GstElement * element, @@ -121,6 +122,7 @@ gst_gtk_base_sink_class_init (GstGtkBaseSinkClass * klass) gstbasesink_class->set_caps = gst_gtk_base_sink_set_caps; gstbasesink_class->get_times = gst_gtk_base_sink_get_times; gstbasesink_class->start = gst_gtk_base_sink_start; + gstbasesink_class->stop = gst_gtk_base_sink_stop; gstvideosink_class->show_frame = gst_gtk_base_sink_show_frame; } @@ -279,18 +281,30 @@ gst_gtk_base_sink_start (GstBaseSink * bsink) toplevel = gtk_widget_get_toplevel (GTK_WIDGET (gst_sink->widget)); if (!gtk_widget_is_toplevel (toplevel)) { - GtkWidget *window; - /* sanity check */ g_assert (klass->window_title); /* 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), klass->window_title); - gtk_container_add (GTK_CONTAINER (window), toplevel); - gtk_widget_show_all (window); + gst_sink->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (gst_sink->window), 640, 480); + gtk_window_set_title (GTK_WINDOW (gst_sink->window), klass->window_title); + gtk_container_add (GTK_CONTAINER (gst_sink->window), toplevel); + gtk_widget_show_all (gst_sink->window); + } + + return TRUE; +} + +static gboolean +gst_gtk_base_sink_stop (GstBaseSink * bsink) +{ + GstGtkBaseSink *gst_sink = GST_GTK_BASE_SINK (bsink); + + if (gst_sink->window) { + gtk_widget_destroy (gst_sink->window); + gst_sink->window = NULL; + gst_sink->widget = NULL; } return TRUE; diff --git a/ext/gtk/gstgtkbasesink.h b/ext/gtk/gstgtkbasesink.h index 6158d81ed0..7260cd5a7e 100644 --- a/ext/gtk/gstgtkbasesink.h +++ b/ext/gtk/gstgtkbasesink.h @@ -67,6 +67,8 @@ struct _GstGtkBaseSink gboolean ignore_alpha; GBinding *bind_ignore_alpha; + + GtkWidget *window; }; /** diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index d59880c53f..ceba7bda1d 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -212,7 +212,7 @@ gst_gtk_gl_sink_stop (GstBaseSink * bsink) gtk_sink->gtk_context = NULL; } - return TRUE; + return GST_BASE_SINK_CLASS (parent_class)->stop (bsink); } static gboolean From 04cf80aa0445bdd912e2d5f0ed0ab4fab449a313 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 21 Sep 2015 10:47:15 +0200 Subject: [PATCH 091/128] gtksink: Do not re destroy the GtkWindow if destroyed by the user Otherwise we will get an ASSERT. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=755249 --- ext/gtk/gstgtkbasesink.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index 42f74261a7..0aeed1f35b 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -150,7 +150,12 @@ static void widget_destroy_cb (GtkWidget * widget, GstGtkBaseSink * gtk_sink) { GST_OBJECT_LOCK (gtk_sink); - g_clear_object (>k_sink->widget); + if (widget == GTK_WIDGET (gtk_sink->widget)) + g_clear_object (>k_sink->widget); + else if (widget == gtk_sink->window) + gtk_sink->window = NULL; + else + g_assert_not_reached (); GST_OBJECT_UNLOCK (gtk_sink); } @@ -290,6 +295,8 @@ gst_gtk_base_sink_start (GstBaseSink * bsink) gtk_window_set_default_size (GTK_WINDOW (gst_sink->window), 640, 480); gtk_window_set_title (GTK_WINDOW (gst_sink->window), klass->window_title); gtk_container_add (GTK_CONTAINER (gst_sink->window), toplevel); + g_signal_connect (gst_sink->window, "destroy", + G_CALLBACK (widget_destroy_cb), gst_sink); gtk_widget_show_all (gst_sink->window); } From afdea505a087d6b4a75835e1936fb13cc386c28c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Sep 2015 11:42:51 +0200 Subject: [PATCH 092/128] gtksink: Do not show window until we reach the PAUSED state https://bugzilla.gnome.org/show_bug.cgi?id=755459 --- ext/gtk/gstgtkbasesink.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index 0aeed1f35b..6321bdaae3 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -297,7 +297,6 @@ gst_gtk_base_sink_start (GstBaseSink * bsink) gtk_container_add (GTK_CONTAINER (gst_sink->window), toplevel); g_signal_connect (gst_sink->window, "destroy", G_CALLBACK (widget_destroy_cb), gst_sink); - gtk_widget_show_all (gst_sink->window); } return TRUE; @@ -317,6 +316,14 @@ gst_gtk_base_sink_stop (GstBaseSink * bsink) return TRUE; } +static gboolean +_show_window_cb (GstGtkBaseSink * gtk_sink) +{ + gtk_widget_show_all (gtk_sink->window); + + return FALSE; +} + static GstStateChangeReturn gst_gtk_base_sink_change_state (GstElement * element, GstStateChange transition) { @@ -332,6 +339,12 @@ gst_gtk_base_sink_change_state (GstElement * element, GstStateChange transition) return ret; switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + GST_OBJECT_LOCK (gtk_sink); + if (gtk_sink->window) + g_idle_add ((GSourceFunc) _show_window_cb, gtk_sink); + GST_OBJECT_UNLOCK (gtk_sink); + break; case GST_STATE_CHANGE_PAUSED_TO_READY: GST_OBJECT_LOCK (gtk_sink); if (gtk_sink->widget) From c3f72729298e1c38bd6432f4f7d4a769dcdc2b7b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 24 Sep 2015 10:51:31 +0200 Subject: [PATCH 093/128] gtk: Marshall state changes in the main thread Gtk is not MT safe thus we need to make sure that everything is done in the main thread when working with it. https://bugzilla.gnome.org/show_bug.cgi?id=755251 --- ext/gtk/gstgtkbasesink.c | 97 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 90 insertions(+), 7 deletions(-) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index 6321bdaae3..41bb7f23ca 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -77,6 +77,54 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstGtkBaseSink, gst_gtk_base_sink, GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_sink, "gtkbasesink", 0, "Gtk Video Sink base class")); +struct invoke_context +{ + GThreadFunc func; + gpointer data; + GMutex lock; + GCond cond; + gboolean fired; + + gpointer res; +}; + +static gboolean +_invoke_func (struct invoke_context *info) +{ + g_mutex_lock (&info->lock); + info->res = info->func (info->data); + info->fired = TRUE; + g_cond_signal (&info->cond); + g_mutex_unlock (&info->lock); + + return G_SOURCE_REMOVE; +} + +static gpointer +_invoke_on_main (GThreadFunc func, gpointer data) +{ + GMainContext *main_context = g_main_context_default (); + struct invoke_context info; + + g_mutex_init (&info.lock); + g_cond_init (&info.cond); + info.fired = FALSE; + info.func = func; + info.data = data; + + g_main_context_invoke (main_context, (GSourceFunc) _invoke_func, &info); + + g_mutex_lock (&info.lock); + while (!info.fired) + g_cond_wait (&info.cond, &info.lock); + g_mutex_unlock (&info.lock); + + g_mutex_clear (&info.lock); + g_cond_clear (&info.cond); + + return info.res; +} + static void gst_gtk_base_sink_class_init (GstGtkBaseSinkClass * klass) { @@ -207,8 +255,21 @@ gst_gtk_base_sink_get_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_WIDGET: - g_value_set_object (value, gst_gtk_base_sink_get_widget (gtk_sink)); + { + GObject *widget = NULL; + + GST_OBJECT_LOCK (gtk_sink); + if (gtk_sink->widget != NULL) + widget = G_OBJECT (gtk_sink->widget); + GST_OBJECT_UNLOCK (gtk_sink); + + if (!widget) + widget = _invoke_on_main ((GThreadFunc) gst_gtk_base_sink_get_widget, + gtk_sink); + + g_value_set_object (value, widget); break; + } case PROP_FORCE_ASPECT_RATIO: g_value_set_boolean (value, gtk_sink->force_aspect_ratio); break; @@ -273,7 +334,7 @@ gst_gtk_base_sink_navigation_interface_init (GstNavigationInterface * iface) } static gboolean -gst_gtk_base_sink_start (GstBaseSink * bsink) +gst_gtk_base_sink_start_on_main (GstBaseSink * bsink) { GstGtkBaseSink *gst_sink = GST_GTK_BASE_SINK (bsink); GstGtkBaseSinkClass *klass = GST_GTK_BASE_SINK_GET_CLASS (bsink); @@ -303,7 +364,14 @@ gst_gtk_base_sink_start (GstBaseSink * bsink) } static gboolean -gst_gtk_base_sink_stop (GstBaseSink * bsink) +gst_gtk_base_sink_start (GstBaseSink * bsink) +{ + return ! !_invoke_on_main ((GThreadFunc) gst_gtk_base_sink_start_on_main, + bsink); +} + +static gboolean +gst_gtk_base_sink_stop_on_main (GstBaseSink * bsink) { GstGtkBaseSink *gst_sink = GST_GTK_BASE_SINK (bsink); @@ -317,11 +385,17 @@ gst_gtk_base_sink_stop (GstBaseSink * bsink) } static gboolean -_show_window_cb (GstGtkBaseSink * gtk_sink) +gst_gtk_base_sink_stop (GstBaseSink * bsink) { - gtk_widget_show_all (gtk_sink->window); + return ! !_invoke_on_main ((GThreadFunc) gst_gtk_base_sink_stop_on_main, + bsink); +} - return FALSE; +static void +gst_gtk_widget_show_all_and_unref (GtkWidget * widget) +{ + gtk_widget_show_all (widget); + g_object_unref (widget); } static GstStateChangeReturn @@ -340,11 +414,20 @@ gst_gtk_base_sink_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: + { + GtkWindow *window = NULL; + GST_OBJECT_LOCK (gtk_sink); if (gtk_sink->window) - g_idle_add ((GSourceFunc) _show_window_cb, gtk_sink); + window = g_object_ref (gtk_sink->window); GST_OBJECT_UNLOCK (gtk_sink); + + if (window) + _invoke_on_main ((GThreadFunc) gst_gtk_widget_show_all_and_unref, + window); + break; + } case GST_STATE_CHANGE_PAUSED_TO_READY: GST_OBJECT_LOCK (gtk_sink); if (gtk_sink->widget) From edebbb709f860d5b3e729bc6623a629828adf99f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 24 Sep 2015 11:37:04 +0200 Subject: [PATCH 094/128] gtk: Factor out a function to run a function on main thread https://bugzilla.gnome.org/show_bug.cgi?id=755251 --- ext/gtk/Makefile.am | 2 ++ ext/gtk/gstgtkbasesink.c | 64 +++++------------------------------- ext/gtk/gstgtkutils.c | 71 ++++++++++++++++++++++++++++++++++++++++ ext/gtk/gstgtkutils.h | 29 ++++++++++++++++ ext/gtk/gtkgstglwidget.c | 51 ++--------------------------- 5 files changed, 114 insertions(+), 103 deletions(-) create mode 100644 ext/gtk/gstgtkutils.c create mode 100644 ext/gtk/gstgtkutils.h diff --git a/ext/gtk/Makefile.am b/ext/gtk/Makefile.am index f2e8c55184..84846774eb 100644 --- a/ext/gtk/Makefile.am +++ b/ext/gtk/Makefile.am @@ -16,6 +16,8 @@ sources = \ gstgtkbasesink.h \ gstgtksink.c \ gstgtksink.h \ + gstgtkutils.c \ + gstgtkutils.h \ gstplugin.c \ $(NULL) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index 41bb7f23ca..9ce6f7cc00 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -28,6 +28,7 @@ #endif #include "gstgtkbasesink.h" +#include "gstgtkutils.h" GST_DEBUG_CATEGORY (gst_debug_gtk_base_sink); #define GST_CAT_DEFAULT gst_debug_gtk_base_sink @@ -77,53 +78,6 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstGtkBaseSink, gst_gtk_base_sink, GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_sink, "gtkbasesink", 0, "Gtk Video Sink base class")); -struct invoke_context -{ - GThreadFunc func; - gpointer data; - GMutex lock; - GCond cond; - gboolean fired; - - gpointer res; -}; - -static gboolean -_invoke_func (struct invoke_context *info) -{ - g_mutex_lock (&info->lock); - info->res = info->func (info->data); - info->fired = TRUE; - g_cond_signal (&info->cond); - g_mutex_unlock (&info->lock); - - return G_SOURCE_REMOVE; -} - -static gpointer -_invoke_on_main (GThreadFunc func, gpointer data) -{ - GMainContext *main_context = g_main_context_default (); - struct invoke_context info; - - g_mutex_init (&info.lock); - g_cond_init (&info.cond); - info.fired = FALSE; - info.func = func; - info.data = data; - - g_main_context_invoke (main_context, (GSourceFunc) _invoke_func, &info); - - g_mutex_lock (&info.lock); - while (!info.fired) - g_cond_wait (&info.cond, &info.lock); - g_mutex_unlock (&info.lock); - - g_mutex_clear (&info.lock); - g_cond_clear (&info.cond); - - return info.res; -} static void gst_gtk_base_sink_class_init (GstGtkBaseSinkClass * klass) @@ -264,7 +218,8 @@ gst_gtk_base_sink_get_property (GObject * object, guint prop_id, GST_OBJECT_UNLOCK (gtk_sink); if (!widget) - widget = _invoke_on_main ((GThreadFunc) gst_gtk_base_sink_get_widget, + widget = + gst_gtk_invoke_on_main ((GThreadFunc) gst_gtk_base_sink_get_widget, gtk_sink); g_value_set_object (value, widget); @@ -366,8 +321,8 @@ gst_gtk_base_sink_start_on_main (GstBaseSink * bsink) static gboolean gst_gtk_base_sink_start (GstBaseSink * bsink) { - return ! !_invoke_on_main ((GThreadFunc) gst_gtk_base_sink_start_on_main, - bsink); + return ! !gst_gtk_invoke_on_main ((GThreadFunc) + gst_gtk_base_sink_start_on_main, bsink); } static gboolean @@ -387,12 +342,12 @@ gst_gtk_base_sink_stop_on_main (GstBaseSink * bsink) static gboolean gst_gtk_base_sink_stop (GstBaseSink * bsink) { - return ! !_invoke_on_main ((GThreadFunc) gst_gtk_base_sink_stop_on_main, - bsink); + return ! !gst_gtk_invoke_on_main ((GThreadFunc) + gst_gtk_base_sink_stop_on_main, bsink); } static void -gst_gtk_widget_show_all_and_unref (GtkWidget * widget) +gst_gtk_widget_show_all_and_unref (GtkWidget *widget) { gtk_widget_show_all (widget); g_object_unref (widget); @@ -423,8 +378,7 @@ gst_gtk_base_sink_change_state (GstElement * element, GstStateChange transition) GST_OBJECT_UNLOCK (gtk_sink); if (window) - _invoke_on_main ((GThreadFunc) gst_gtk_widget_show_all_and_unref, - window); + gst_gtk_invoke_on_main ((GThreadFunc) gst_gtk_widget_show_all_and_unref, window); break; } diff --git a/ext/gtk/gstgtkutils.c b/ext/gtk/gstgtkutils.c new file mode 100644 index 0000000000..c730f0188f --- /dev/null +++ b/ext/gtk/gstgtkutils.c @@ -0,0 +1,71 @@ +/* + * GStreamer + * Copyright (C) 2015 Matthew Waters + * Copyright (C) 2015 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gstgtkutils.h" + +struct invoke_context +{ + GThreadFunc func; + gpointer data; + GMutex lock; + GCond cond; + gboolean fired; + + gpointer res; +}; + +static gboolean +gst_gtk_invoke_func (struct invoke_context *info) +{ + g_mutex_lock (&info->lock); + info->res = info->func (info->data); + info->fired = TRUE; + g_cond_signal (&info->cond); + g_mutex_unlock (&info->lock); + + return G_SOURCE_REMOVE; +} + +gpointer +gst_gtk_invoke_on_main (GThreadFunc func, gpointer data) +{ + GMainContext *main_context = g_main_context_default (); + struct invoke_context info; + + g_mutex_init (&info.lock); + g_cond_init (&info.cond); + info.fired = FALSE; + info.func = func; + info.data = data; + + g_main_context_invoke (main_context, (GSourceFunc) gst_gtk_invoke_func, + &info); + + g_mutex_lock (&info.lock); + while (!info.fired) + g_cond_wait (&info.cond, &info.lock); + g_mutex_unlock (&info.lock); + + g_mutex_clear (&info.lock); + g_cond_clear (&info.cond); + + return info.res; +} diff --git a/ext/gtk/gstgtkutils.h b/ext/gtk/gstgtkutils.h new file mode 100644 index 0000000000..7584ae2c66 --- /dev/null +++ b/ext/gtk/gstgtkutils.h @@ -0,0 +1,29 @@ +/* + * GStreamer + * Copyright (C) 2015 Matthew Waters + * Copyright (C) 2015 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_GTK_UTILS_H__ +#define __GST_GTK_UTILS_H__ + +#include + +gpointer gst_gtk_invoke_on_main (GThreadFunc func, gpointer data); + +#endif /* __GST_GTK_UTILS_H__ */ diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index b16725fc96..7b3f37f61a 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -25,6 +25,7 @@ #include #include "gtkgstglwidget.h" +#include "gstgtkutils.h" #include #if GST_GL_HAVE_WINDOW_X11 && GST_GL_HAVE_PLATFORM_GLX && defined (GDK_WINDOWING_X11) @@ -278,52 +279,6 @@ done: return FALSE; } -typedef void (*ThreadFunc) (gpointer data); - -struct invoke_context -{ - ThreadFunc func; - gpointer data; - GMutex lock; - GCond cond; - gboolean fired; -}; - -static gboolean -_invoke_func (struct invoke_context *info) -{ - g_mutex_lock (&info->lock); - info->func (info->data); - info->fired = TRUE; - g_cond_signal (&info->cond); - g_mutex_unlock (&info->lock); - - return G_SOURCE_REMOVE; -} - -static void -_invoke_on_main (ThreadFunc func, gpointer data) -{ - GMainContext *main_context = g_main_context_default (); - struct invoke_context info; - - g_mutex_init (&info.lock); - g_cond_init (&info.cond); - info.fired = FALSE; - info.func = func; - info.data = data; - - g_main_context_invoke (main_context, (GSourceFunc) _invoke_func, &info); - - g_mutex_lock (&info.lock); - while (!info.fired) - g_cond_wait (&info.cond, &info.lock); - g_mutex_unlock (&info.lock); - - g_mutex_clear (&info.lock); - g_cond_clear (&info.cond); -} - static void _reset_gl (GtkGstGLWidget * gst_widget) { @@ -380,7 +335,7 @@ gtk_gst_gl_widget_finalize (GObject * object) GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (object); if (priv->other_context) - _invoke_on_main ((ThreadFunc) _reset_gl, base_widget); + gst_gtk_invoke_on_main ((GThreadFunc) _reset_gl, base_widget); if (priv->context) gst_object_unref (priv->context); @@ -534,7 +489,7 @@ gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * gst_widget) if (!priv->other_context) { GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); - _invoke_on_main ((ThreadFunc) _get_gl_context, gst_widget); + gst_gtk_invoke_on_main ((GThreadFunc) _get_gl_context, gst_widget); GTK_GST_BASE_WIDGET_LOCK (gst_widget); } From f08f8d77f8dd14daf9d2a3cb79ef35d53546c993 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 24 Sep 2015 15:51:28 +0200 Subject: [PATCH 095/128] gtk: Do not forget to release OBJECT_LOCK on error path https://bugzilla.gnome.org/show_bug.cgi?id=755542 --- ext/gtk/gstgtkbasesink.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index 9ce6f7cc00..57c5a060af 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -347,7 +347,7 @@ gst_gtk_base_sink_stop (GstBaseSink * bsink) } static void -gst_gtk_widget_show_all_and_unref (GtkWidget *widget) +gst_gtk_widget_show_all_and_unref (GtkWidget * widget) { gtk_widget_show_all (widget); g_object_unref (widget); @@ -378,7 +378,8 @@ gst_gtk_base_sink_change_state (GstElement * element, GstStateChange transition) GST_OBJECT_UNLOCK (gtk_sink); if (window) - gst_gtk_invoke_on_main ((GThreadFunc) gst_gtk_widget_show_all_and_unref, window); + gst_gtk_invoke_on_main ((GThreadFunc) gst_gtk_widget_show_all_and_unref, + window); break; } @@ -437,9 +438,10 @@ gst_gtk_base_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) return FALSE; } - if (!gtk_gst_base_widget_set_format (gtk_sink->widget, >k_sink->v_info)) + if (!gtk_gst_base_widget_set_format (gtk_sink->widget, >k_sink->v_info)) { + GST_OBJECT_UNLOCK (gtk_sink); return FALSE; - + } GST_OBJECT_UNLOCK (gtk_sink); return TRUE; From e80765c9285a600bda364d1c3c8134804ca855b5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 24 Sep 2015 15:52:40 +0200 Subject: [PATCH 096/128] gtk: When setting format check if pending format changed In case the format changed fast and the pending format is different than the currently set but the currently set is equal to the pending one we could end up having mismatch between the finally set format and the data stream format. https://bugzilla.gnome.org/show_bug.cgi?id=755542 --- ext/gtk/gtkgstbasewidget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/gtk/gtkgstbasewidget.c b/ext/gtk/gtkgstbasewidget.c index 390ac246b7..aa02c7e2b1 100644 --- a/ext/gtk/gtkgstbasewidget.c +++ b/ext/gtk/gtkgstbasewidget.c @@ -454,7 +454,7 @@ gtk_gst_base_widget_set_format (GtkGstBaseWidget * widget, { GTK_GST_BASE_WIDGET_LOCK (widget); - if (gst_video_info_is_equal (&widget->v_info, v_info)) { + if (gst_video_info_is_equal (&widget->pending_v_info, v_info)) { GTK_GST_BASE_WIDGET_UNLOCK (widget); return TRUE; } From 16fe5f43c08faef02de42a5da5691adb8630ff98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Sep 2015 18:51:39 +0200 Subject: [PATCH 097/128] gtk: Only run from the main thread in stop() if we created the window We're not doing anything at all from the main thread in other cases. --- ext/gtk/gstgtkbasesink.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index 57c5a060af..e11627b5b8 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -342,8 +342,13 @@ gst_gtk_base_sink_stop_on_main (GstBaseSink * bsink) static gboolean gst_gtk_base_sink_stop (GstBaseSink * bsink) { - return ! !gst_gtk_invoke_on_main ((GThreadFunc) - gst_gtk_base_sink_stop_on_main, bsink); + GstGtkBaseSink *gst_sink = GST_GTK_BASE_SINK (bsink); + + if (gst_sink->window) + return ! !gst_gtk_invoke_on_main ((GThreadFunc) + gst_gtk_base_sink_stop_on_main, bsink); + + return TRUE; } static void From 38e30dc631d76c2cd074d449b584ea2c695bb08e Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 29 Sep 2015 00:25:00 +1000 Subject: [PATCH 098/128] gtk: fix assertion when the element has no peer When proxying keyboard/navigation/mouse events, only unref a successfully retreived peer pad. https://bugzilla.gnome.org/show_bug.cgi?id=755738 --- ext/gtk/gstgtkbasesink.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index e11627b5b8..dd3af91016 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -276,10 +276,12 @@ gst_gtk_base_sink_navigation_send_event (GstNavigation * navigation, GST_TRACE_OBJECT (sink, "navigation event %" GST_PTR_FORMAT, structure); - if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) - gst_pad_send_event (pad, event); + if (GST_IS_PAD (pad)) { + if (GST_IS_EVENT (event)) + gst_pad_send_event (pad, event); - gst_object_unref (pad); + gst_object_unref (pad); + } } static void From ab5f9c551f8af745892d9c74f68a80c63d026379 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 29 Sep 2015 22:57:52 +1000 Subject: [PATCH 099/128] gtk: add some GL debug statements to show up in GL traces --- ext/gtk/gtkgstglwidget.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 7b3f37f61a..3020f1919f 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -52,8 +52,7 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); G_DEFINE_TYPE_WITH_CODE (GtkGstGLWidget, gtk_gst_gl_widget, GTK_TYPE_GL_AREA, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gtkgstglwidget", 0, - "Gtk Gst GL Widget"); - ); + "Gtk Gst GL Widget");); #define GTK_GST_GL_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ GTK_TYPE_GST_GL_WIDGET, GtkGstGLWidgetPrivate)) @@ -121,6 +120,7 @@ gtk_gst_gl_widget_init_redisplay (GtkGstGLWidget * gst_widget) const GstGLFuncs *gl = priv->context->gl_vtable; priv->shader = gst_gl_shader_new (priv->context); + gst_gl_insert_debug_marker (priv->other_context, "initializing redisplay"); gst_gl_shader_compile_with_default_vf_and_check (priv->shader, &priv->attr_position, &priv->attr_texture); @@ -207,6 +207,7 @@ _draw_black (GstGLContext * context) { const GstGLFuncs *gl = context->gl_vtable; + gst_gl_insert_debug_marker (context, "no buffer. rendering black"); gl->ClearColor (0.0, 0.0, 0.0, 0.0); gl->Clear (GL_COLOR_BUFFER_BIT); } @@ -244,6 +245,10 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) goto done; } + priv->current_tex = *(guint *) gl_frame.data[0]; + gst_gl_insert_debug_marker (priv->other_context, "redrawing texture %u", + priv->current_tex); + gst_gl_overlay_compositor_upload_overlays (priv->overlay_compositor, buffer); @@ -253,8 +258,6 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) gst_gl_sync_meta_wait (sync_meta, priv->other_context); } - priv->current_tex = *(guint *) gl_frame.data[0]; - gst_video_frame_unmap (&gl_frame); if (base_widget->buffer) @@ -271,6 +274,9 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) _redraw_texture (GTK_GST_GL_WIDGET (widget), priv->current_tex); gst_gl_overlay_compositor_draw_overlays (priv->overlay_compositor); + gst_gl_insert_debug_marker (priv->other_context, "texture %u redrawn", + priv->current_tex); + done: if (priv->other_context) gst_gl_context_activate (priv->other_context, FALSE); From 136f375f010cd3047d3aa17ecab19ba15ce5ef29 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Fri, 4 Sep 2015 16:02:32 +1000 Subject: [PATCH 100/128] glshader: port to using GstGLSLStage objects for string management A GstGLShader is now simply a collection of stages that are compiled and linked together into a program. The uniform/attribute interface has remained the same. --- ext/gtk/gtkgstglwidget.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 3020f1919f..3e427a8d35 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -118,12 +118,18 @@ gtk_gst_gl_widget_init_redisplay (GtkGstGLWidget * gst_widget) { GtkGstGLWidgetPrivate *priv = gst_widget->priv; const GstGLFuncs *gl = priv->context->gl_vtable; + GError *error = NULL; - priv->shader = gst_gl_shader_new (priv->context); gst_gl_insert_debug_marker (priv->other_context, "initializing redisplay"); + if (!(priv->shader = gst_gl_shader_new_default (priv->context, &error))) { + GST_ERROR ("Failed to initialize shader: %s", error->message); + return; + } - gst_gl_shader_compile_with_default_vf_and_check (priv->shader, - &priv->attr_position, &priv->attr_texture); + priv->attr_position = + gst_gl_shader_get_attribute_location (priv->shader, "a_position"); + priv->attr_texture = + gst_gl_shader_get_attribute_location (priv->shader, "a_texcoord"); if (gl->GenVertexArrays) { gl->GenVertexArrays (1, &priv->vao); From b8b9c78599fdfbfba507c440196a7b3b3a88450e Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Sat, 17 Oct 2015 01:08:29 +1100 Subject: [PATCH 101/128] gl/examples: add a live shader demo using the new GstGLSLStage Implemented with videotestsrc ! glshader ! glupload ! gtkglsink Errors on an invalid shader compilation are ignored however any error provided by the glsl compiler is printed to stdout. --- tests/examples/gtk/Makefile.am | 15 +- tests/examples/gtk/glliveshader.c | 353 ++++++++++++++++++++++++++++++ 2 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 tests/examples/gtk/glliveshader.c diff --git a/tests/examples/gtk/Makefile.am b/tests/examples/gtk/Makefile.am index 945331d5f6..71441b453f 100644 --- a/tests/examples/gtk/Makefile.am +++ b/tests/examples/gtk/Makefile.am @@ -9,7 +9,7 @@ gtksink_LDADD = $(GTK3_LIBS) \ if USE_GTK3_GL if USE_GL -noinst_PROGRAMS += gtkglsink +noinst_PROGRAMS += gtkglsink glliveshader gtkglsink_SOURCES = gtkglsink.c gtkglsink_CFLAGS = $(GTK3_CFLAGS) \ @@ -20,5 +20,18 @@ gtkglsink_CFLAGS = $(GTK3_CFLAGS) \ gtkglsink_LDADD = $(GTK3_LIBS) \ $(GST_LIBS) \ $(GL_LIBS) + +glliveshader_SOURCES = glliveshader.c +glliveshader_CFLAGS = $(GTK3_CFLAGS) \ + -I$(top_srcdir)/gst-libs \ + -I$(top_builddir)/gst-libs \ + $(GST_PLUGINS_BAD_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_CFLAGS) \ + $(GL_CFLAGS) +glliveshader_LDADD = $(GTK3_LIBS) \ + $(GST_LIBS) \ + $(GL_LIBS) \ + $(top_builddir)/gst-libs/gst/gl/libgstgl-$(GST_API_VERSION).la endif endif diff --git a/tests/examples/gtk/glliveshader.c b/tests/examples/gtk/glliveshader.c new file mode 100644 index 0000000000..a8d128a4fe --- /dev/null +++ b/tests/examples/gtk/glliveshader.c @@ -0,0 +1,353 @@ +/* + * GStreamer + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#if GST_GL_HAVE_WINDOW_X11 +#include +#endif + +static GMainLoop *loop; + +static const gchar *vert = "#version 330\n\ +in vec4 a_position;\n\ +in vec2 a_texcoord;\n\ +out vec2 v_texcoord;\n\ +uniform float time;\n\ +uniform float width;\n\ +uniform float height;\n\ +void main()\n\ +{\n\ + gl_Position = a_position;\n\ + v_texcoord = a_texcoord;\n\ +}\n"; + +static const gchar *geom = "#version 330\n\ +\n\ +layout(triangles) in;\n\ +layout(triangle_strip, max_vertices = 3) out;\n\ +in vec2 v_texcoord[];\n\ +out vec2 g_texcoord;\n\ +\n\ +void main() {\n\ + for(int i = 0; i < 3; i++) {\n\ + gl_Position = gl_in[i].gl_Position;\n\ + g_texcoord = v_texcoord[i];\n\ + EmitVertex();\n\ + }\n\ + EndPrimitive();\n\ +}\n"; + +static const gchar *frag = "#version 330\n\ +in vec2 g_texcoord;\n\ +uniform sampler2D tex;\n\ +uniform float time;\n\ +uniform float width;\n\ +uniform float height;\n\ +void main()\n\ +{\n\ + gl_FragColor = texture2D(tex, g_texcoord);\n\ +}\n"; + +#define MAX_SHADER_STAGES 8 +struct shader_state; + +struct text_view_state +{ + struct shader_state *state; + + GLenum type; + gchar *str; +}; + +struct shader_state +{ + GstGLContext *context; + GstElement *shader; + gboolean shader_linked; + GtkWidget *label; + struct text_view_state text_states[MAX_SHADER_STAGES]; + gint n_stages; +}; + +static gboolean +bus_call (GstBus * bus, GstMessage * msg, gpointer data) +{ + switch (GST_MESSAGE_TYPE (msg)) { + case GST_MESSAGE_EOS: + g_print ("End of stream\n"); + g_main_loop_quit (loop); + break; + case GST_MESSAGE_ERROR:{ + gchar *debug; + GError *error; + + gst_message_parse_error (msg, &error, &debug); + g_free (debug); + + g_printerr ("Error: %s\n", error->message); + g_error_free (error); + + g_main_loop_quit (loop); + break; + } + default: + break; + } + + return TRUE; +} + +static gchar * +_find_source_for_shader_type (struct shader_state *state, GLenum type) +{ + int i = 0; + + for (i = 0; i < state->n_stages; i++) { + if (state->text_states[i].type == type) + return state->text_states[i].str; + } + + return NULL; +} + +static gboolean +_add_stage_to_shader (GstGLShader * shader, struct shader_state *state, + GLenum type, const gchar * default_src) +{ + GError *error = NULL; + GstGLSLVersion version; + GstGLSLProfile profile; + GstGLSLStage *stage; + const gchar *src; + + src = _find_source_for_shader_type (state, type); + if (!src) + src = default_src; + if (!src) + /* FIXME: assume this stage is not needed */ + return TRUE; + + if (!gst_glsl_string_get_version_profile (src, &version, &profile)) { + g_print ("Warning: failed to retreive GLSL version and profile for " + "shader type 0x%x\nsrc:\n%s\n", type, src); + } + + if (!(stage = gst_glsl_stage_new_with_string (shader->context, type, + version, profile, src))) { + g_print ("Error: Failed to create GLSL Stage from src:\n%s\n", src); + return FALSE; + } + + if (!gst_gl_shader_compile_attach_stage (shader, stage, &error)) { + /* ignore failed shader compilations */ + g_print ("%s", error->message); + return FALSE; + } + + return TRUE; +} + +static GstGLShader * +_new_shader (GstGLContext * context, struct shader_state *state) +{ + GstGLShader *shader = gst_gl_shader_new (context); + GError *error = NULL; + + if (!_add_stage_to_shader (shader, state, GL_VERTEX_SHADER, vert)) { + gst_object_unref (shader); + return NULL; + } + if (!_add_stage_to_shader (shader, state, GL_GEOMETRY_SHADER, geom)) { + gst_object_unref (shader); + return NULL; + } + if (!_add_stage_to_shader (shader, state, GL_FRAGMENT_SHADER, frag)) { + gst_object_unref (shader); + return NULL; + } + + if (!gst_gl_shader_link (shader, &error)) { + /* ignore failed shader compilations */ + g_print ("%s", error->message); + gst_object_unref (shader); + return NULL; + } + + return shader; +} + +static GstGLShader * +_create_shader (GstElement * element, struct shader_state *state) +{ + GstGLContext *context; + GstGLShader *shader; + + g_object_get (G_OBJECT (element), "context", &context, NULL); + + shader = _new_shader (context, state); + state->shader_linked = TRUE; + + if (state->context) + gst_object_unref (state->context); + state->context = context; + + return shader; +} + +static void +_modify_shader (GstGLContext * context, struct shader_state *state) +{ + GstGLShader *shader; + + if (!(shader = _new_shader (context, state))) { + state->shader_linked = FALSE; + return; + } + state->shader_linked = TRUE; + + g_object_set (state->shader, "shader", shader, NULL); +} + +static void +_on_text_changed (GtkTextBuffer * text, struct text_view_state *state) +{ + GtkTextIter start, end; + + if (!state->state->context) + return; + + gtk_text_buffer_get_bounds (text, &start, &end); + if (state->str) + g_free (state->str); + state->str = gtk_text_buffer_get_text (text, &start, &end, FALSE); + gst_gl_context_thread_add (state->state->context, + (GstGLContextThreadFunc) _modify_shader, state->state); + + gtk_label_set_text (GTK_LABEL (state->state->label), + state->state->shader_linked ? "Success" : "Failure"); +} + +static GtkWidget * +_new_source_view (struct shader_state *state, GLenum type, const gchar * templ) +{ + static int i = 0; + GtkWidget *scroll, *text_view; + GtkTextBuffer *text; + + g_return_val_if_fail (i < MAX_SHADER_STAGES, NULL); + + state->text_states[i].state = state; + state->text_states[i].type = type; + state->text_states[i].str = g_strdup (templ); + + scroll = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_set_size_request (scroll, 20, 20); + text_view = gtk_text_view_new (); + gtk_container_add (GTK_CONTAINER (scroll), text_view); + text = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)); + if (state->text_states[i].str) + gtk_text_buffer_set_text (text, state->text_states[i].str, -1); + g_signal_connect (text, "changed", G_CALLBACK (_on_text_changed), + &state->text_states[i]); + state->n_stages++; + i++; + + return scroll; +} + +int +main (int argc, char *argv[]) +{ + GstElement *pipeline, *src, *upload, *shader, *sink; + GtkWidget *window, *paned, *video, *right_box, *book; + struct shader_state state = { 0, }; + GstBus *bus; + +#if GST_GL_HAVE_WINDOW_X11 + XInitThreads (); +#endif + + gst_init (&argc, &argv); + gtk_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + pipeline = gst_pipeline_new (NULL); + src = gst_element_factory_make ("videotestsrc", NULL); + upload = gst_element_factory_make ("glupload", NULL); + shader = gst_element_factory_make ("glshader", NULL); + sink = gst_element_factory_make ("gtkglsink", NULL); + g_object_get (sink, "widget", &video, NULL); + + g_assert (src && shader && sink); + gst_bin_add_many (GST_BIN (pipeline), src, upload, shader, sink, NULL); + g_assert (gst_element_link_many (src, upload, shader, sink, NULL)); + + bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); + gst_bus_add_watch (bus, bus_call, loop); + gst_object_unref (bus); + + state.shader = gst_object_ref (shader); + g_signal_connect (shader, "create-shader", G_CALLBACK (_create_shader), + &state); + + book = gtk_notebook_new (); + /* text view inside a scroll view */ + gtk_notebook_append_page (GTK_NOTEBOOK (book), _new_source_view (&state, + GL_VERTEX_SHADER, vert), gtk_label_new ("Vertex")); + gtk_notebook_append_page (GTK_NOTEBOOK (book), _new_source_view (&state, + GL_GEOMETRY_SHADER, geom), gtk_label_new ("Geometry")); + gtk_notebook_append_page (GTK_NOTEBOOK (book), _new_source_view (&state, + GL_FRAGMENT_SHADER, frag), gtk_label_new ("Fragment")); + /* status label */ + state.label = gtk_label_new ("Success"); + + /* right side source code editor */ + right_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_box_pack_start (GTK_BOX (right_box), book, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (right_box), state.label, FALSE, TRUE, 0); + + paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); + gtk_paned_pack1 (GTK_PANED (paned), video, TRUE, FALSE); + gtk_widget_set_size_request (video, 20, 20); + gtk_paned_pack2 (GTK_PANED (paned), right_box, TRUE, FALSE); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (window), 640, 480); + gtk_container_add (GTK_CONTAINER (window), paned); + + gtk_widget_show_all (window); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + g_main_loop_run (loop); + + gst_element_set_state (pipeline, GST_STATE_NULL); + + /*shader strings leaked here */ + /*g_free (state.str); */ + gst_object_unref (state.shader); + + gst_object_unref (pipeline); + + return 0; +} From 2882f6b90bf786aac8a0a997fa6cba2ec29e1ea8 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Sat, 17 Oct 2015 02:40:50 +1100 Subject: [PATCH 102/128] gtk: separate out the widget/window destroy callbacks Fixes assertion due to the sink_finalize() being run before the widget destroy callback. https://bugzilla.gnome.org/show_bug.cgi?id=755969 --- ext/gtk/gstgtkbasesink.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index dd3af91016..e192940658 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -152,12 +152,15 @@ static void widget_destroy_cb (GtkWidget * widget, GstGtkBaseSink * gtk_sink) { GST_OBJECT_LOCK (gtk_sink); - if (widget == GTK_WIDGET (gtk_sink->widget)) - g_clear_object (>k_sink->widget); - else if (widget == gtk_sink->window) - gtk_sink->window = NULL; - else - g_assert_not_reached (); + g_clear_object (>k_sink->widget); + GST_OBJECT_UNLOCK (gtk_sink); +} + +static void +window_destroy_cb (GtkWidget * widget, GstGtkBaseSink * gtk_sink) +{ + GST_OBJECT_LOCK (gtk_sink); + gtk_sink->window = NULL; GST_OBJECT_UNLOCK (gtk_sink); } @@ -314,7 +317,7 @@ gst_gtk_base_sink_start_on_main (GstBaseSink * bsink) gtk_window_set_title (GTK_WINDOW (gst_sink->window), klass->window_title); gtk_container_add (GTK_CONTAINER (gst_sink->window), toplevel); g_signal_connect (gst_sink->window, "destroy", - G_CALLBACK (widget_destroy_cb), gst_sink); + G_CALLBACK (window_destroy_cb), gst_sink); } return TRUE; From 608cf31a253ac29e94d3d64dad4b533a1fbe3b73 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Sat, 17 Oct 2015 15:26:46 +1100 Subject: [PATCH 103/128] glshaderelement: implement on-demand create-shader signalling One may not have an GstGLContext available or current in the thread where one would need to update the shader. Support this by signalling create-shader whenever the one-shot 'update-shader' is set to TRUE. --- tests/examples/gtk/glliveshader.c | 51 +++++++++++++------------------ 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/tests/examples/gtk/glliveshader.c b/tests/examples/gtk/glliveshader.c index a8d128a4fe..6f820a63a9 100644 --- a/tests/examples/gtk/glliveshader.c +++ b/tests/examples/gtk/glliveshader.c @@ -195,36 +195,36 @@ _new_shader (GstGLContext * context, struct shader_state *state) return shader; } +static gboolean +_set_compilation_state (struct shader_state *state) +{ + gtk_label_set_text (GTK_LABEL (state->label), + state->shader_linked ? "Success" : "Failure"); + + return G_SOURCE_REMOVE; +} + static GstGLShader * _create_shader (GstElement * element, struct shader_state *state) { GstGLContext *context; - GstGLShader *shader; + GstGLShader *shader, *new_shader; - g_object_get (G_OBJECT (element), "context", &context, NULL); + g_object_get (G_OBJECT (element), "context", &context, "shader", &shader, + NULL); - shader = _new_shader (context, state); - state->shader_linked = TRUE; + new_shader = _new_shader (context, state); + if (!shader && !new_shader) + g_warning ("Failed to create a shader!"); + state->shader_linked = new_shader != NULL; - if (state->context) - gst_object_unref (state->context); - state->context = context; + if (shader) + gst_object_unref (shader); + gst_object_unref (context); - return shader; -} + g_main_context_invoke (NULL, (GSourceFunc) _set_compilation_state, state); -static void -_modify_shader (GstGLContext * context, struct shader_state *state) -{ - GstGLShader *shader; - - if (!(shader = _new_shader (context, state))) { - state->shader_linked = FALSE; - return; - } - state->shader_linked = TRUE; - - g_object_set (state->shader, "shader", shader, NULL); + return new_shader; } static void @@ -232,18 +232,11 @@ _on_text_changed (GtkTextBuffer * text, struct text_view_state *state) { GtkTextIter start, end; - if (!state->state->context) - return; - gtk_text_buffer_get_bounds (text, &start, &end); if (state->str) g_free (state->str); state->str = gtk_text_buffer_get_text (text, &start, &end, FALSE); - gst_gl_context_thread_add (state->state->context, - (GstGLContextThreadFunc) _modify_shader, state->state); - - gtk_label_set_text (GTK_LABEL (state->state->label), - state->state->shader_linked ? "Success" : "Failure"); + g_object_set (state->state->shader, "update-shader", TRUE, NULL); } static GtkWidget * From 5f94356ce1b6b8a77f17ed084230023fccaf395b Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 19 Oct 2015 15:15:30 +1100 Subject: [PATCH 104/128] gl: be consistent in gobject boilerpate GST_GL_IS_* vs GST_IS_GL_* git grep -l 'GST_GL_IS_' | xargs sed -i 's/GST_GL_IS_/GST_IS_GL_/g' --- ext/gtk/gtkgstglwidget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 3e427a8d35..c4d53a2b09 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -505,7 +505,7 @@ gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * gst_widget) GTK_GST_BASE_WIDGET_LOCK (gst_widget); } - if (!GST_GL_IS_CONTEXT (priv->other_context)) { + if (!GST_IS_GL_CONTEXT (priv->other_context)) { GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); return FALSE; } From 4a52b58b78c0ea1eea71ae00cefce3bcf0ef92b9 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 10 Nov 2015 12:32:39 +1100 Subject: [PATCH 105/128] gtk: add the overlaycomposition feature to the template caps There is a possibility that the _get_caps impl will be called with the feature in the filter caps which when interecting with the template, will return EMPTY and therefore fail negotiation. https://bugzilla.gnome.org/show_bug.cgi?id=757854 --- ext/gtk/gstgtkglsink.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index ceba7bda1d..4d41f1a20f 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -42,11 +42,14 @@ static GstCaps *gst_gtk_gl_sink_get_caps (GstBaseSink * bsink, GstCaps * filter); static GstStaticPadTemplate gst_gtk_gl_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"))); + (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, "RGBA") "; " + GST_VIDEO_CAPS_MAKE_WITH_FEATURES + (GST_CAPS_FEATURE_MEMORY_GL_MEMORY ", " + GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, "RGBA"))); #define gst_gtk_gl_sink_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstGtkGLSink, gst_gtk_gl_sink, From d55cc79310da19966744479e1cabf153c1a3d493 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Tue, 17 Nov 2015 15:23:17 -0800 Subject: [PATCH 106/128] Remove unnecessary NULL checks before g_free() g_free() is NULL-safe --- tests/examples/gtk/glliveshader.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/examples/gtk/glliveshader.c b/tests/examples/gtk/glliveshader.c index 6f820a63a9..d8c8d35063 100644 --- a/tests/examples/gtk/glliveshader.c +++ b/tests/examples/gtk/glliveshader.c @@ -233,8 +233,7 @@ _on_text_changed (GtkTextBuffer * text, struct text_view_state *state) GtkTextIter start, end; gtk_text_buffer_get_bounds (text, &start, &end); - if (state->str) - g_free (state->str); + g_free (state->str); state->str = gtk_text_buffer_get_text (text, &start, &end, FALSE); g_object_set (state->state->shader, "update-shader", TRUE, NULL); } From caafdd8ca2a34bcbd3ea80b208f691d74a2b38a5 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 9 Feb 2016 12:14:04 +1100 Subject: [PATCH 107/128] glsyncmeta: separate out gpu/cpu waits. CPU waits are more expensive and are only required if the CPU is ever going to access the data. GPU waits perform inter-context synchronisation and are cheaper as they don't require CPU intervention. --- ext/gtk/gtkgstglwidget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index c4d53a2b09..c9ad0b63fb 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -260,6 +260,7 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) sync_meta = gst_buffer_get_gl_sync_meta (buffer); if (sync_meta) { + /* XXX: the set_sync() seems to be needed for resizing */ gst_gl_sync_meta_set_sync_point (sync_meta, priv->context); gst_gl_sync_meta_wait (sync_meta, priv->other_context); } From aaacc9fe54ec644803f402d5ad48e19aab41aad9 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 16 Feb 2016 19:59:13 +1100 Subject: [PATCH 108/128] gtk(gl)sink: remove the signal handlers on finalize It's possible that the sink element will be freed before the widget is destroyed. When the widget was eventually destroyed, it was attempting to access member variables of the freed sink struct which resulted in undefined behaviour. Fix by disconnecting our signal on finalize. https://bugzilla.gnome.org/show_bug.cgi?id=762098 --- ext/gtk/gstgtkbasesink.c | 13 ++++++++++--- ext/gtk/gstgtkbasesink.h | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index e192940658..f0019bf264 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -141,9 +141,16 @@ gst_gtk_base_sink_init (GstGtkBaseSink * gtk_sink) static void gst_gtk_base_sink_finalize (GObject * object) { - GstGtkBaseSink *gtk_sink = GST_GTK_BASE_SINK (object);; + GstGtkBaseSink *gtk_sink = GST_GTK_BASE_SINK (object); + + GST_OBJECT_LOCK (gtk_sink); + if (gtk_sink->window && gtk_sink->window_destroy_id) + g_signal_handler_disconnect (gtk_sink->window, gtk_sink->window_destroy_id); + if (gtk_sink->widget && gtk_sink->widget_destroy_id) + g_signal_handler_disconnect (gtk_sink->widget, gtk_sink->widget_destroy_id); g_clear_object (>k_sink->widget); + GST_OBJECT_UNLOCK (gtk_sink); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -194,7 +201,7 @@ gst_gtk_base_sink_get_widget (GstGtkBaseSink * gtk_sink) /* Take the floating ref, other wise 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", + gtk_sink->widget_destroy_id = g_signal_connect (gtk_sink->widget, "destroy", G_CALLBACK (widget_destroy_cb), gtk_sink); /* back pointer */ @@ -316,7 +323,7 @@ gst_gtk_base_sink_start_on_main (GstBaseSink * bsink) gtk_window_set_default_size (GTK_WINDOW (gst_sink->window), 640, 480); gtk_window_set_title (GTK_WINDOW (gst_sink->window), klass->window_title); gtk_container_add (GTK_CONTAINER (gst_sink->window), toplevel); - g_signal_connect (gst_sink->window, "destroy", + gst_sink->window_destroy_id = g_signal_connect (gst_sink->window, "destroy", G_CALLBACK (window_destroy_cb), gst_sink); } diff --git a/ext/gtk/gstgtkbasesink.h b/ext/gtk/gstgtkbasesink.h index 7260cd5a7e..ef8c28495b 100644 --- a/ext/gtk/gstgtkbasesink.h +++ b/ext/gtk/gstgtkbasesink.h @@ -69,6 +69,8 @@ struct _GstGtkBaseSink GBinding *bind_ignore_alpha; GtkWidget *window; + gulong widget_destroy_id; + gulong window_destroy_id; }; /** From d37822173d6de981698ebe42753ca34f6eb9ab21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 5 Mar 2016 11:38:46 +0200 Subject: [PATCH 109/128] gtk: examples: #define GST_USE_UNSTABLE_API and link with X11_LIBS X11_LIBS is needed for XInitThreads() and without the #define we get warnings about the GL API being still unstable. --- tests/examples/gtk/Makefile.am | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/examples/gtk/Makefile.am b/tests/examples/gtk/Makefile.am index 71441b453f..adf5e3178a 100644 --- a/tests/examples/gtk/Makefile.am +++ b/tests/examples/gtk/Makefile.am @@ -16,10 +16,12 @@ gtkglsink_CFLAGS = $(GTK3_CFLAGS) \ $(GST_PLUGINS_BAD_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_CFLAGS) \ - $(GL_CFLAGS) + $(GL_CFLAGS) \ + -DGST_USE_UNSTABLE_API gtkglsink_LDADD = $(GTK3_LIBS) \ $(GST_LIBS) \ - $(GL_LIBS) + $(GL_LIBS) \ + $(X11_LIBS) glliveshader_SOURCES = glliveshader.c glliveshader_CFLAGS = $(GTK3_CFLAGS) \ @@ -28,10 +30,12 @@ glliveshader_CFLAGS = $(GTK3_CFLAGS) \ $(GST_PLUGINS_BAD_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_CFLAGS) \ - $(GL_CFLAGS) + $(GL_CFLAGS) \ + -DGST_USE_UNSTABLE_API glliveshader_LDADD = $(GTK3_LIBS) \ $(GST_LIBS) \ $(GL_LIBS) \ - $(top_builddir)/gst-libs/gst/gl/libgstgl-$(GST_API_VERSION).la + $(top_builddir)/gst-libs/gst/gl/libgstgl-$(GST_API_VERSION).la \ + $(X11_LIBS) endif endif From 32e346da06620d3fa6547eacf9779e0a699811f0 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Fri, 4 Mar 2016 15:50:26 +0900 Subject: [PATCH 110/128] bad: use new gst_element_class_add_static_pad_template() https://bugzilla.gnome.org/show_bug.cgi?id=763081 --- ext/gtk/gstgtkglsink.c | 4 ++-- ext/gtk/gstgtksink.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 4d41f1a20f..f17a88e37c 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -80,8 +80,8 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) "Sink/Video", "A video sink that renders to a GtkWidget", "Matthew Waters "); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&gst_gtk_gl_sink_template)); + gst_element_class_add_static_pad_template (gstelement_class, + &gst_gtk_gl_sink_template); } static void diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index 4659221640..083c28dc0c 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -62,8 +62,8 @@ gst_gtk_sink_class_init (GstGtkSinkClass * klass) "Sink/Video", "A video sink that renders to a GtkWidget", "Matthew Waters "); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&gst_gtk_sink_template)); + gst_element_class_add_static_pad_template (gstelement_class, + &gst_gtk_sink_template); } static void From c7dae7d057c62e6f48dedfcd81944967f0f9aa6d Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Thu, 10 Mar 2016 08:44:57 +0900 Subject: [PATCH 111/128] gtkbasesink: post message to application for unhandled keyboard/mouse events https://bugzilla.gnome.org/show_bug.cgi?id=763403 --- ext/gtk/gstgtkbasesink.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index f0019bf264..44c8cbd46e 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -286,10 +286,14 @@ gst_gtk_base_sink_navigation_send_event (GstNavigation * navigation, GST_TRACE_OBJECT (sink, "navigation event %" GST_PTR_FORMAT, structure); - if (GST_IS_PAD (pad)) { - if (GST_IS_EVENT (event)) - gst_pad_send_event (pad, event); - + if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) { + if (!gst_pad_send_event (pad, gst_event_ref (event))) { + /* If upstream didn't handle the event we'll post a message with it + * for the application in case it wants to do something with it */ + gst_element_post_message (GST_ELEMENT_CAST (sink), + gst_navigation_message_new_event (GST_OBJECT_CAST (sink), event)); + } + gst_event_unref (event); gst_object_unref (pad); } } From 3faf049250a66b8c716b234b92831e805adb8643 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Fri, 25 Mar 2016 17:49:14 +1100 Subject: [PATCH 112/128] gtk/gl: don't assert when gdk doesn't provide a GL context Allows the application to check whether gtkglsink is supported by setting the element to READY. https://bugzilla.gnome.org/show_bug.cgi?id=764148 --- ext/gtk/gtkgstglwidget.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index c9ad0b63fb..e3d08ab3ba 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -420,8 +420,13 @@ _get_gl_context (GtkGstGLWidget * gst_widget) gtk_widget_realize (GTK_WIDGET (gst_widget)); + if (priv->other_context) + gst_object_unref (priv->other_context); + priv->other_context = NULL; + if (priv->gdk_context) g_object_unref (priv->gdk_context); + priv->gdk_context = gtk_gl_area_get_context (GTK_GL_AREA (gst_widget)); if (priv->gdk_context == NULL) { GError *error = gtk_gl_area_get_error (GTK_GL_AREA (gst_widget)); @@ -429,7 +434,6 @@ _get_gl_context (GtkGstGLWidget * gst_widget) GST_ERROR_OBJECT (gst_widget, "Error creating GdkGLContext : %s", error ? error->message : "No error set by Gdk"); g_clear_error (&error); - g_assert_not_reached (); return; } From 570ce4f7c87c74a5f66bf41d8fb31969f5fcafb0 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Sun, 27 Mar 2016 14:29:58 +0530 Subject: [PATCH 113/128] gtk: Fix logging in base widget and fix desc of GL sink Set a default category for gtkgstbasewidget lest the logging go to the 'default' category where it can't be found easily --- ext/gtk/gstgtkglsink.c | 6 +++--- ext/gtk/gstgtksink.c | 7 ++++++- ext/gtk/gtkgstbasewidget.c | 6 ++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index f17a88e37c..4081754673 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -54,7 +54,7 @@ static GstStaticPadTemplate gst_gtk_gl_sink_template = #define gst_gtk_gl_sink_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstGtkGLSink, gst_gtk_gl_sink, GST_TYPE_GTK_BASE_SINK, GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_gl_sink, - "gtkglsink", 0, "Gtk Video Sink")); + "gtkglsink", 0, "Gtk GL Video Sink")); static void gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) @@ -76,8 +76,8 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) 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", + gst_element_class_set_metadata (gstelement_class, "Gtk GL Video Sink", + "Sink/Video", "A video sink that renders to a GtkWidget using OpenGL", "Matthew Waters "); gst_element_class_add_static_pad_template (gstelement_class, diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index 083c28dc0c..e9f9d0cc72 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -30,6 +30,9 @@ #include "gtkgstwidget.h" #include "gstgtksink.h" +GST_DEBUG_CATEGORY (gst_debug_gtk_sink); +#define GST_CAT_DEFAULT gst_debug_gtk_sink + #if G_BYTE_ORDER == G_LITTLE_ENDIAN #define FORMATS "{ BGRx, BGRA }" #else @@ -44,7 +47,9 @@ GST_STATIC_PAD_TEMPLATE ("sink", ); #define gst_gtk_sink_parent_class parent_class -G_DEFINE_TYPE (GstGtkSink, gst_gtk_sink, GST_TYPE_GTK_BASE_SINK); +G_DEFINE_TYPE_WITH_CODE (GstGtkSink, gst_gtk_sink, GST_TYPE_GTK_BASE_SINK, + GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_sink, "gtksink", 0, + "Gtk Video Sink")); static void gst_gtk_sink_class_init (GstGtkSinkClass * klass) diff --git a/ext/gtk/gtkgstbasewidget.c b/ext/gtk/gtkgstbasewidget.c index aa02c7e2b1..4858f2764a 100644 --- a/ext/gtk/gtkgstbasewidget.c +++ b/ext/gtk/gtkgstbasewidget.c @@ -26,6 +26,9 @@ #include "gtkgstbasewidget.h" +GST_DEBUG_CATEGORY (gst_debug_gtk_base_widget); +#define GST_CAT_DEFAULT gst_debug_gtk_base_widget + #define DEFAULT_FORCE_ASPECT_RATIO TRUE #define DEFAULT_PAR_N 0 #define DEFAULT_PAR_D 1 @@ -399,6 +402,9 @@ gtk_gst_base_widget_class_init (GtkGstBaseWidgetClass * klass) widget_klass->button_press_event = gtk_gst_base_widget_button_event; widget_klass->button_release_event = gtk_gst_base_widget_button_event; widget_klass->motion_notify_event = gtk_gst_base_widget_motion_event; + + GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_widget, "gtkbasewidget", 0, + "Gtk Video Base Widget"); } void From eb4c674e9dabd9c9dac3ca15132997a85593232d Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Fri, 9 Sep 2016 16:36:03 +1000 Subject: [PATCH 114/128] meson: add build files for the gtk plugin --- ext/gtk/meson.build | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 ext/gtk/meson.build diff --git a/ext/gtk/meson.build b/ext/gtk/meson.build new file mode 100644 index 0000000000..d041fbd213 --- /dev/null +++ b/ext/gtk/meson.build @@ -0,0 +1,54 @@ +gtk_sources = [ + 'gstgtkbasesink.c', + 'gstgtksink.c', + 'gstgtkutils.c', + 'gstplugin.c', + 'gtkgstbasewidget.c', + 'gtkgstwidget.c', +] + +gtk_defines = [] +optional_deps = [] + +gtk_dep = dependency('gtk+-3.0', required : false) +if gtk_dep.found() + if build_gstgl and gstgl_dep.found() and gtk_dep.version().version_compare('>=3.15.0') + have_gtk3_gl_windowing = false + + if x11_dep.found() and gl_dep.found() + gtk_x11_dep = dependency('gtk+-x11-3.0', required : false) + if gtk_x11_dep.found() + optional_deps += gtk_x11_dep + have_gtk3_gl_windowing = true + endif + endif + + if wayland_egl_dep.found() and egl_dep.found() + gtk_wayland_dep = dependency('gtk+-wayland-3.0', required : false) + if gtk_wayland_dep.found() + optional_deps += gtk_wayland_dep + have_gtk3_gl_windowing = true + endif + endif + + if have_gtk3_gl_windowing + gtk_sources += [ + 'gstgtkglsink.c', + 'gtkgstglwidget.c', + ] + optional_deps += gstgl_dep + gtk_defines += ['-DGST_USE_UNSTABLE_API', '-DHAVE_GTK3_GL'] + endif + endif + + gstgtk = library('gstgtk', + gtk_sources, + c_args : gst_plugins_bad_args + gtk_defines, + link_args : noseh_link_args, + include_directories : [configinc], + dependencies : [gtk_dep, gstvideo_dep, gstbase_dep, libm] + optional_deps, + install : true, + install_dir : plugins_install_dir, + ) +endif + From c51210f2a81b0fe318e9526980475bc5bc5a6ca6 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Wed, 5 Oct 2016 12:19:12 +1100 Subject: [PATCH 115/128] gl: GST_GL_TYPE -> GST_TYPE_GL Some deprecated symbols are kept for backwards compatibility --- ext/gtk/gstgtkglsink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 4081754673..6843451046 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -120,7 +120,7 @@ gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query) context = gst_context_new ("gst.gl.local_context", FALSE); s = gst_context_writable_structure (context); - gst_structure_set (s, "context", GST_GL_TYPE_CONTEXT, gtk_sink->context, + gst_structure_set (s, "context", GST_TYPE_GL_CONTEXT, gtk_sink->context, NULL); gst_query_set_context (query, context); gst_context_unref (context); From 64394fc29635328a8827954cc5e5f998aa06cc07 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Thu, 12 Jan 2017 21:35:25 +1100 Subject: [PATCH 116/128] gl/utils: also take care of the local GL context in query functions Simplifies a deduplicates a lot of code in elements retrieving/setting the local OpenGL context. --- ext/gtk/gstgtkglsink.c | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 6843451046..2bdd331c65 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -98,37 +98,9 @@ gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query) switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CONTEXT: { - const gchar *context_type; - GstContext *context, *old_context; - - res = gst_gl_handle_context_query ((GstElement *) gtk_sink, query, - >k_sink->display, >k_sink->gtk_context); - - if (gtk_sink->display) - gst_gl_display_filter_gl_api (gtk_sink->display, GST_GL_API_OPENGL3); - - 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_TYPE_GL_CONTEXT, gtk_sink->context, - NULL); - gst_query_set_context (query, context); - gst_context_unref (context); - - res = gtk_sink->context != NULL; - } - GST_LOG_OBJECT (gtk_sink, "context query of type %s %i", context_type, - res); + if (gst_gl_handle_context_query ((GstElement *) gtk_sink, query, + gtk_sink->display, gtk_sink->context, gtk_sink->gtk_context)) + return TRUE; break; } default: From efa2ed59c7e58dfd158255b84126ba50287c8a85 Mon Sep 17 00:00:00 2001 From: Juan Pablo Ugarte Date: Wed, 11 Jan 2017 10:32:23 -0300 Subject: [PATCH 117/128] gl/examples/gtk: fixed compilation on systems without GL_GEOMETRY_SHADER https://bugzilla.gnome.org/show_bug.cgi?id=777143 --- tests/examples/gtk/glliveshader.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/examples/gtk/glliveshader.c b/tests/examples/gtk/glliveshader.c index d8c8d35063..5a71bc3fcb 100644 --- a/tests/examples/gtk/glliveshader.c +++ b/tests/examples/gtk/glliveshader.c @@ -25,6 +25,10 @@ #include #endif +#ifndef GL_GEOMETRY_SHADER +#define GL_GEOMETRY_SHADER 0x8DD9 +#endif + static GMainLoop *loop; static const gchar *vert = "#version 330\n\ From b7d332022cf1f89c5700126eea1cc2a63913b710 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Sat, 4 Mar 2017 11:03:53 -0500 Subject: [PATCH 118/128] Rename plugin filesnames to match plugin names - libgstgtksink.so -> libgstgtk.so - libgstteletextdec.so -> libgstteletex.so - libgstcamerabin2.so -> libgstcamerabin.so - libgstonvif.so -> libgstrtponvif.so (meson only) - sdp -> sdpelem (avoid clash with libgstsdp) - gstsiren -> siren - libgstkmssink.so -> libgstkms.so https://bugzilla.gnome.org/show_bug.cgi?id=779344 --- ext/gtk/Makefile.am | 16 ++++++++-------- ext/gtk/gstplugin.c | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ext/gtk/Makefile.am b/ext/gtk/Makefile.am index 84846774eb..fdf860f67b 100644 --- a/ext/gtk/Makefile.am +++ b/ext/gtk/Makefile.am @@ -21,29 +21,29 @@ sources = \ gstplugin.c \ $(NULL) -libgstgtksink_la_CFLAGS = \ +libgstgtk_la_CFLAGS = \ -I$(top_srcdir)/gst-libs \ -I$(top_builddir)/gst-libs \ $(GTK3_CFLAGS) \ $(GST_CFLAGS) \ $(GST_BASE_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) -libgstgtksink_la_LIBADD = \ +libgstgtk_la_LIBADD = \ $(GTK3_LIBS) \ $(GST_BASE_LIBS) \ $(GST_PLUGINS_BASE_LIBS) \ -lgstvideo-$(GST_API_VERSION) -libgstgtksink_la_SOURCES = $(sources) -libgstgtksink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstgtksink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) +libgstgtk_la_SOURCES = $(sources) +libgstgtk_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstgtk_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) if USE_GTK3_GL if USE_GL -libgstgtksink_la_SOURCES += gstgtkglsink.c gstgtkglsink.h gtkgstglwidget.c gtkgstglwidget.h -libgstgtksink_la_LIBADD += \ +libgstgtk_la_SOURCES += gstgtkglsink.c gstgtkglsink.h gtkgstglwidget.c gtkgstglwidget.h +libgstgtk_la_LIBADD += \ $(top_builddir)/gst-libs/gst/gl/libgstgl-$(GST_API_VERSION).la endif endif -plugin_LTLIBRARIES = libgstgtksink.la +plugin_LTLIBRARIES = libgstgtk.la diff --git a/ext/gtk/gstplugin.c b/ext/gtk/gstplugin.c index 4c5d26b54e..ed275785be 100644 --- a/ext/gtk/gstplugin.c +++ b/ext/gtk/gstplugin.c @@ -46,7 +46,7 @@ plugin_init (GstPlugin * plugin) GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, - gstgtk, + gtk, "Gtk+ sink", plugin_init, PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) From f451d9be8d919103796625acb4c4f211ae8db675 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 14 Mar 2017 14:15:00 +1100 Subject: [PATCH 119/128] gl: GL_ARRAY_BUFFER is not a part of VAO state As a result we need to bind it on every draw in order to have the correct state in the GL state machine. --- ext/gtk/gtkgstglwidget.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index e3d08ab3ba..e780ebd386 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -191,8 +191,7 @@ _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) if (gl->BindVertexArray) gl->BindVertexArray (priv->vao); - else - gtk_gst_gl_widget_bind_buffer (gst_widget); + gtk_gst_gl_widget_bind_buffer (gst_widget); gl->ActiveTexture (GL_TEXTURE0); gl->BindTexture (GL_TEXTURE_2D, tex); @@ -202,8 +201,7 @@ _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) if (gl->BindVertexArray) gl->BindVertexArray (0); - else - gtk_gst_gl_widget_unbind_buffer (gst_widget); + gtk_gst_gl_widget_unbind_buffer (gst_widget); gl->BindTexture (GL_TEXTURE_2D, 0); } From 1ee15d67b063bf9d18761921d705941e8e767678 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 8 Mar 2017 15:01:13 -0300 Subject: [PATCH 120/128] docs: Port all docstring to gtk-doc markdown --- ext/gtk/gstgtkbasesink.c | 1 + ext/gtk/gstgtkglsink.c | 4 ++-- ext/gtk/gstgtksink.c | 3 ++- ext/gtk/gtkgstglwidget.c | 1 + ext/gtk/gtkgstwidget.c | 1 + 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index 44c8cbd46e..843c97f1b6 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -20,6 +20,7 @@ /** * SECTION:gtkgstsink + * @title: GstGtkBaseSink * */ diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 2bdd331c65..56326882a9 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -19,8 +19,8 @@ */ /** - * SECTION:gstgtkglsink - * + * SECTION:element-gtkglsink + * @title: gtkglsink */ #ifdef HAVE_CONFIG_H diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index e9f9d0cc72..ba8ea33ca0 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -19,7 +19,8 @@ */ /** - * SECTION:gtkgstsink + * SECTION:element-gtkgstsink + * @title: gtkgstsink * */ diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index e780ebd386..ea0fe2f8ab 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -41,6 +41,7 @@ /** * SECTION:gtkgstglwidget + * @title: GtkGstGlWidget * @short_description: a #GtkGLArea that renders GStreamer video #GstBuffers * @see_also: #GtkGLArea, #GstBuffer * diff --git a/ext/gtk/gtkgstwidget.c b/ext/gtk/gtkgstwidget.c index 5fe238a545..a936210ba1 100644 --- a/ext/gtk/gtkgstwidget.c +++ b/ext/gtk/gtkgstwidget.c @@ -29,6 +29,7 @@ /** * SECTION:gtkgstwidget + * @title: GtkGstWidget * @short_description: a #GtkWidget that renders GStreamer video #GstBuffers * @see_also: #GtkDrawingArea, #GstBuffer * From 5c8d4271d670cd3cb681af530670b3cc4e1fad45 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 16 May 2017 14:05:52 -0400 Subject: [PATCH 121/128] Remove plugin specific static build option Static and dynamic plugins now have the same interface. The standard --enable-static/--enable-shared toggle are sufficient. --- ext/gtk/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/gtk/Makefile.am b/ext/gtk/Makefile.am index fdf860f67b..7736b24ef2 100644 --- a/ext/gtk/Makefile.am +++ b/ext/gtk/Makefile.am @@ -36,7 +36,6 @@ libgstgtk_la_LIBADD = \ libgstgtk_la_SOURCES = $(sources) libgstgtk_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstgtk_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) if USE_GTK3_GL if USE_GL From a4d74fda9a1a279fdf27534a53634095cc094c09 Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Fri, 7 Jul 2017 16:15:12 +0100 Subject: [PATCH 122/128] gl: do not include GL headers in public gstgl headers Except for gst/gl/gstglfuncs.h It is up to the client app to include these headers. It is coherent with the fact that gstreamer-gl.pc does not require any egl.pc/gles.pc. I.e. it is the responsability of the app to search these headers within its build setup. For example gstreamer-vaapi includes explicitly EGL/egl.h and search for it in its configure.ac. For example with this patch, if an app includes the headers gst/gl/egl/gstglcontext_egl.h gst/gl/egl/gstgldisplay_egl.h gst/gl/egl/gstglmemoryegl.h it will *no longer* automatically include EGL/egl.h and GLES2/gl2.h. Which is good because the app might want to use the gstgl api only without the need to bother about gl headers. Also added a test: cd tests/check && make libs/gstglheaders.check https://bugzilla.gnome.org/show_bug.cgi?id=784779 --- ext/gtk/Makefile.am | 3 ++- ext/gtk/gstgtkglsink.c | 2 ++ ext/gtk/gtkgstglwidget.c | 1 + tests/examples/gtk/glliveshader.c | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ext/gtk/Makefile.am b/ext/gtk/Makefile.am index 7736b24ef2..34906257f4 100644 --- a/ext/gtk/Makefile.am +++ b/ext/gtk/Makefile.am @@ -27,7 +27,8 @@ libgstgtk_la_CFLAGS = \ $(GTK3_CFLAGS) \ $(GST_CFLAGS) \ $(GST_BASE_CFLAGS) \ - $(GST_PLUGINS_BASE_CFLAGS) + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GL_CFLAGS) libgstgtk_la_LIBADD = \ $(GTK3_LIBS) \ $(GST_BASE_LIBS) \ diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 56326882a9..39b54faf86 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -27,6 +27,8 @@ #include "config.h" #endif +#include + #include "gstgtkglsink.h" #include "gtkgstglwidget.h" diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index ea0fe2f8ab..2423afca00 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -26,6 +26,7 @@ #include "gtkgstglwidget.h" #include "gstgtkutils.h" +#include #include #if GST_GL_HAVE_WINDOW_X11 && GST_GL_HAVE_PLATFORM_GLX && defined (GDK_WINDOWING_X11) diff --git a/tests/examples/gtk/glliveshader.c b/tests/examples/gtk/glliveshader.c index 5a71bc3fcb..03e745ee36 100644 --- a/tests/examples/gtk/glliveshader.c +++ b/tests/examples/gtk/glliveshader.c @@ -20,6 +20,7 @@ #include #include +#include #include #if GST_GL_HAVE_WINDOW_X11 #include From 38b5a9bf3396720c615d63d8ec420e206a70964d Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Fri, 1 Sep 2017 15:00:12 +1000 Subject: [PATCH 123/128] gtkglsink: expose the created display and context correctly 1. Propagate the GstGLDisplay we create 2. Add the created GstGLContext to the propagated GstGLDisplay Otherwise with multi-branch GL pipelines involving gtkglsink, things will fall apart and errors will be genarated somewhere. --- ext/gtk/gstgtkglsink.c | 3 +++ ext/gtk/gtkgstglwidget.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index 39b54faf86..d9d389b36d 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -166,6 +166,9 @@ gst_gtk_gl_sink_start (GstBaseSink * bsink) if (!gtk_sink->display || !gtk_sink->context || !gtk_sink->gtk_context) return FALSE; + gst_gl_element_propagate_display_context (GST_ELEMENT (bsink), + gtk_sink->display); + return TRUE; } diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 2423afca00..cfad4f1759 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -515,12 +515,16 @@ gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * gst_widget) return FALSE; } + GST_OBJECT_LOCK (priv->display); if (!gst_gl_display_create_context (priv->display, priv->other_context, &priv->context, &error)) { g_clear_error (&error); + GST_OBJECT_UNLOCK (priv->display); GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); return FALSE; } + gst_gl_display_add_context (priv->display, priv->context); + GST_OBJECT_UNLOCK (priv->display); GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); return TRUE; From 6669ccdae5a56c52bf505ddfff49bb3b24b0bda4 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 5 Sep 2017 16:20:44 -0400 Subject: [PATCH 124/128] Request minimum buffer even if need_pool is FALSE When tee is used, it will not request a pool, but still it wants to know how many buffers are required. https://bugzilla.gnome.org/show_bug.cgi?id=730758 --- ext/gtk/gstgtkglsink.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index d9d389b36d..4439e85fbf 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -202,6 +202,7 @@ gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) GstBufferPool *pool = NULL; GstStructure *config; GstCaps *caps; + GstVideoInfo info; guint size; gboolean need_pool; GstStructure *allocation_meta = NULL; @@ -215,18 +216,16 @@ gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) if (caps == NULL) goto no_caps; + if (!gst_video_info_from_caps (&info, caps)) + goto invalid_caps; + + /* the normal size of a frame */ + size = info.size; + if (need_pool) { - GstVideoInfo info; - - if (!gst_video_info_from_caps (&info, caps)) - goto invalid_caps; - GST_DEBUG_OBJECT (gtk_sink, "create new pool"); pool = gst_gl_buffer_pool_new (gtk_sink->context); - /* the normal size of a frame */ - size = info.size; - config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, caps, size, 0, 0); gst_buffer_pool_config_add_option (config, @@ -234,12 +233,13 @@ gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) 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 */ - gst_query_add_allocation_pool (query, pool, size, 2, 0); - gst_object_unref (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); + if (pool) + gst_object_unref (pool); + GST_OBJECT_LOCK (gtk_sink); display_width = gtk_sink->display_width; display_height = gtk_sink->display_height; From 63398b852551dba78fea7e709eca838f1d1cae89 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 24 Nov 2017 08:00:21 +0100 Subject: [PATCH 125/128] gtk: Fix possibility of NULL variable It's quite unlikely since it's initialized in instance initialization. CID #1417721 --- ext/gtk/gtkgstglwidget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index cfad4f1759..fdece48e8a 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -496,6 +496,7 @@ gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * gst_widget) GError *error = NULL; g_return_val_if_fail (GTK_IS_GST_GL_WIDGET (gst_widget), FALSE); + g_return_val_if_fail (priv->display != NULL, FALSE); GTK_GST_BASE_WIDGET_LOCK (gst_widget); From 2106bf01515d02c9314888b8545c445dcc83eb30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 17 Dec 2017 20:54:06 +0000 Subject: [PATCH 126/128] gl: update plugins to use GstGL from -base --- ext/gtk/Makefile.am | 19 ++++++++----------- ext/gtk/meson.build | 4 ++-- tests/examples/gtk/Makefile.am | 23 +++++++++++------------ 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/ext/gtk/Makefile.am b/ext/gtk/Makefile.am index 34906257f4..057ff3f184 100644 --- a/ext/gtk/Makefile.am +++ b/ext/gtk/Makefile.am @@ -22,18 +22,16 @@ sources = \ $(NULL) libgstgtk_la_CFLAGS = \ - -I$(top_srcdir)/gst-libs \ - -I$(top_builddir)/gst-libs \ - $(GTK3_CFLAGS) \ - $(GST_CFLAGS) \ - $(GST_BASE_CFLAGS) \ + $(GST_PLUGINS_BAD_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) \ - $(GL_CFLAGS) + $(GST_GL_CFLAGS) \ + $(GST_CFLAGS) \ + $(GTK3_CFLAGS) libgstgtk_la_LIBADD = \ - $(GTK3_LIBS) \ - $(GST_BASE_LIBS) \ $(GST_PLUGINS_BASE_LIBS) \ - -lgstvideo-$(GST_API_VERSION) + -lgstvideo-$(GST_API_VERSION) \ + $(GST_BASE_LIBS) \ + $(GTK3_LIBS) libgstgtk_la_SOURCES = $(sources) libgstgtk_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) @@ -41,8 +39,7 @@ libgstgtk_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) if USE_GTK3_GL if USE_GL libgstgtk_la_SOURCES += gstgtkglsink.c gstgtkglsink.h gtkgstglwidget.c gtkgstglwidget.h -libgstgtk_la_LIBADD += \ - $(top_builddir)/gst-libs/gst/gl/libgstgl-$(GST_API_VERSION).la +libgstgtk_la_LIBADD += $(GST_GL_LIBS) endif endif diff --git a/ext/gtk/meson.build b/ext/gtk/meson.build index d041fbd213..324bfba89e 100644 --- a/ext/gtk/meson.build +++ b/ext/gtk/meson.build @@ -15,7 +15,7 @@ if gtk_dep.found() if build_gstgl and gstgl_dep.found() and gtk_dep.version().version_compare('>=3.15.0') have_gtk3_gl_windowing = false - if x11_dep.found() and gl_dep.found() + if gst_gl_have_window_x11 and gst_gl_have_platform_glx gtk_x11_dep = dependency('gtk+-x11-3.0', required : false) if gtk_x11_dep.found() optional_deps += gtk_x11_dep @@ -23,7 +23,7 @@ if gtk_dep.found() endif endif - if wayland_egl_dep.found() and egl_dep.found() + if gst_gl_have_window_wayland and gst_gl_have_platform_egl gtk_wayland_dep = dependency('gtk+-wayland-3.0', required : false) if gtk_wayland_dep.found() optional_deps += gtk_wayland_dep diff --git a/tests/examples/gtk/Makefile.am b/tests/examples/gtk/Makefile.am index adf5e3178a..15636d9f20 100644 --- a/tests/examples/gtk/Makefile.am +++ b/tests/examples/gtk/Makefile.am @@ -12,30 +12,29 @@ if USE_GL noinst_PROGRAMS += gtkglsink glliveshader gtkglsink_SOURCES = gtkglsink.c -gtkglsink_CFLAGS = $(GTK3_CFLAGS) \ +gtkglsink_CFLAGS = \ $(GST_PLUGINS_BAD_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_CFLAGS) \ $(GL_CFLAGS) \ - -DGST_USE_UNSTABLE_API -gtkglsink_LDADD = $(GTK3_LIBS) \ + $(GTK3_CFLAGS) +gtkglsink_LDADD = \ + $(GST_GL_LIBS) \ $(GST_LIBS) \ - $(GL_LIBS) \ + $(GTK3_LIBS) \ $(X11_LIBS) glliveshader_SOURCES = glliveshader.c -glliveshader_CFLAGS = $(GTK3_CFLAGS) \ - -I$(top_srcdir)/gst-libs \ - -I$(top_builddir)/gst-libs \ +glliveshader_CFLAGS = \ $(GST_PLUGINS_BAD_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_GL_CFLAGS) \ $(GST_CFLAGS) \ - $(GL_CFLAGS) \ - -DGST_USE_UNSTABLE_API -glliveshader_LDADD = $(GTK3_LIBS) \ + $(GTK3_CFLAGS) +glliveshader_LDADD = \ + $(GST_GL_LIBS) \ $(GST_LIBS) \ - $(GL_LIBS) \ - $(top_builddir)/gst-libs/gst/gl/libgstgl-$(GST_API_VERSION).la \ + $(GTK3_LIBS) \ $(X11_LIBS) endif endif From 33e2fadc3adb8b959baeeafb3ba6681eda287b7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 19 Dec 2017 13:03:28 +0000 Subject: [PATCH 127/128] gtk: don't include uninstalled header --- ext/gtk/gtkgstglwidget.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index fdece48e8a..76c46c9c8c 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -32,7 +32,6 @@ #if GST_GL_HAVE_WINDOW_X11 && GST_GL_HAVE_PLATFORM_GLX && defined (GDK_WINDOWING_X11) #include #include -#include #endif #if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (GDK_WINDOWING_WAYLAND) From 3bdb3a89c25ff009064ab75bde91a985147f3404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 19 Dec 2017 16:22:52 -0500 Subject: [PATCH 128/128] gtk example: Fix cflags in Makefile.am --- tests/examples/gtk/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/examples/gtk/Makefile.am b/tests/examples/gtk/Makefile.am index 15636d9f20..cd7962d525 100644 --- a/tests/examples/gtk/Makefile.am +++ b/tests/examples/gtk/Makefile.am @@ -15,6 +15,7 @@ gtkglsink_SOURCES = gtkglsink.c gtkglsink_CFLAGS = \ $(GST_PLUGINS_BAD_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_GL_CFLAGS) \ $(GST_CFLAGS) \ $(GL_CFLAGS) \ $(GTK3_CFLAGS)