summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Kiagiadakis <george.kiagiadakis@collabora.com>2015-10-26 16:24:40 +0100
committerGeorge Kiagiadakis <george.kiagiadakis@collabora.com>2015-11-18 13:10:45 +0100
commit3eeec2836a8f1ddb5525633f4ae1c360ddc9d3ba (patch)
tree19daca6c4a48c145fcde9c4049fd220bb2f4201e
parentc51fe83d4228262f297382f49676c76cd2f8147e (diff)
downloadgstreamer-plugins-bad-3eeec2836a8f1ddb5525633f4ae1c360ddc9d3ba.tar.gz
tests/examples: add a waylandsink example
https://bugzilla.gnome.org/show_bug.cgi?id=748322
-rw-r--r--.gitignore1
-rw-r--r--configure.ac1
-rw-r--r--tests/examples/Makefile.am15
-rw-r--r--tests/examples/waylandsink/Makefile.am9
-rw-r--r--tests/examples/waylandsink/main.c279
-rw-r--r--tests/examples/waylandsink/window.ui99
6 files changed, 402 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 508357b40..3cef8b503 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,6 +65,7 @@ gst*orc.h
/tests/examples/opencv/gsthanddetect_test
/tests/examples/opencv/gstfacedetect_test
/tests/examples/playout
+/tests/examples/waylandsink/gtkwaylandsink
Build
*.user
diff --git a/configure.ac b/configure.ac
index e71f9dd25..2ecc868e9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3559,6 +3559,7 @@ tests/examples/mpegts/Makefile
tests/examples/mxf/Makefile
tests/examples/opencv/Makefile
tests/examples/uvch264/Makefile
+tests/examples/waylandsink/Makefile
tests/icles/Makefile
ext/voamrwbenc/Makefile
ext/voaacenc/Makefile
diff --git a/tests/examples/Makefile.am b/tests/examples/Makefile.am
index c26d3d9fd..57ed6ddc3 100644
--- a/tests/examples/Makefile.am
+++ b/tests/examples/Makefile.am
@@ -40,6 +40,16 @@ else
GTK3_DIR=
endif
+if USE_WAYLAND
+if HAVE_GTK3
+WAYLAND_DIR=waylandsink
+else
+WAYLAND_DIR=
+endif
+else
+WAYLAND_DIR=
+endif
+
noinst_PROGRAMS = playout
playout_SOURCES = playout.c
@@ -47,7 +57,8 @@ playout_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
playout_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) $(GST_LIBS)
SUBDIRS= codecparsers mpegts $(DIRECTFB_DIR) $(GTK_EXAMPLES) $(OPENCV_EXAMPLES) \
- $(GL_DIR) $(GTK3_DIR) $(AVSAMPLE_DIR)
-DIST_SUBDIRS= codecparsers mpegts camerabin2 directfb mxf opencv uvch264 gl gtk avsamplesink
+ $(GL_DIR) $(GTK3_DIR) $(AVSAMPLE_DIR) $(WAYLAND_DIR)
+DIST_SUBDIRS= codecparsers mpegts camerabin2 directfb mxf opencv uvch264 gl gtk \
+ avsamplesink waylandsink
include $(top_srcdir)/common/parallel-subdirs.mak
diff --git a/tests/examples/waylandsink/Makefile.am b/tests/examples/waylandsink/Makefile.am
new file mode 100644
index 000000000..4a6649e21
--- /dev/null
+++ b/tests/examples/waylandsink/Makefile.am
@@ -0,0 +1,9 @@
+noinst_PROGRAMS = gtkwaylandsink
+
+gtkwaylandsink_SOURCES = main.c
+
+gtkwaylandsink_CFLAGS=-I$(top_srcdir)/gst-libs -I$(top_builddir)/gst-libs \
+ $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GTK3_CFLAGS)
+gtkwaylandsink_LDADD=$(GTK3_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_LIBS) \
+ -lgstvideo-$(GST_API_VERSION) \
+ -L$(top_srcdir)/gst-libs/gst/wayland -lgstwayland-$(GST_API_VERSION)
diff --git a/tests/examples/waylandsink/main.c b/tests/examples/waylandsink/main.c
new file mode 100644
index 000000000..2f9bf8954
--- /dev/null
+++ b/tests/examples/waylandsink/main.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2014-2015 Collabora Ltd.
+ * @author George Kiagiadakis <george.kiagiadakis@collabora.com>
+ *
+ * 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 <gst/gst.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#ifdef GDK_WINDOWING_WAYLAND
+#include <gdk/gdkwayland.h>
+#else
+#error "Wayland is not supported in GTK+"
+#endif
+
+#include <gst/video/videooverlay.h>
+#include <gst/wayland/wayland.h>
+
+
+static gboolean live = FALSE;
+
+static GOptionEntry entries[] = {
+ {"live", 'l', 0, G_OPTION_ARG_NONE, &live, "Use a live source", NULL},
+ {NULL}
+};
+
+typedef struct
+{
+ GtkWidget *app_widget;
+ GtkWidget *video_widget;
+
+ GstElement *pipeline;
+ GstVideoOverlay *overlay;
+
+ gchar **argv;
+ gint current_uri; /* index for argv */
+} DemoApp;
+
+static void
+on_about_to_finish (GstElement * playbin, DemoApp * d)
+{
+ if (d->argv[++d->current_uri] == NULL)
+ d->current_uri = 1;
+
+ g_print ("Now playing %s\n", d->argv[d->current_uri]);
+ g_object_set (playbin, "uri", d->argv[d->current_uri], NULL);
+}
+
+static void
+error_cb (GstBus * bus, GstMessage * msg, gpointer user_data)
+{
+ DemoApp *d = user_data;
+ gchar *debug = NULL;
+ GError *err = NULL;
+
+ gst_message_parse_error (msg, &err, &debug);
+
+ g_print ("Error: %s\n", err->message);
+ g_error_free (err);
+
+ if (debug) {
+ g_print ("Debug details: %s\n", debug);
+ g_free (debug);
+ }
+
+ gst_element_set_state (d->pipeline, GST_STATE_NULL);
+}
+
+static GstBusSyncReply
+bus_sync_handler (GstBus * bus, GstMessage * message, gpointer user_data)
+{
+ DemoApp *d = user_data;
+
+ if (gst_is_wayland_display_handle_need_context_message (message)) {
+ GstContext *context;
+ GdkDisplay *display;
+ struct wl_display *display_handle;
+
+ display = gtk_widget_get_display (d->video_widget);
+ display_handle = gdk_wayland_display_get_wl_display (display);
+ context = gst_wayland_display_handle_context_new (display_handle);
+ gst_element_set_context (GST_ELEMENT (GST_MESSAGE_SRC (message)), context);
+
+ goto drop;
+ } else if (gst_is_video_overlay_prepare_window_handle_message (message)) {
+ GtkAllocation allocation;
+ GdkWindow *window;
+ struct wl_surface *window_handle;
+
+ /* GST_MESSAGE_SRC (message) will be the overlay object that we have to
+ * use. This may be waylandsink, but it may also be playbin. In the latter
+ * case, we must make sure to use playbin instead of waylandsink, because
+ * playbin resets the window handle and render_rectangle after restarting
+ * playback and the actual window size is lost */
+ d->overlay = GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (message));
+
+ gtk_widget_get_allocation (d->video_widget, &allocation);
+ window = gtk_widget_get_window (d->video_widget);
+ window_handle = gdk_wayland_window_get_wl_surface (window);
+
+ g_print ("setting window handle and size (%d x %d)\n",
+ allocation.width, allocation.height);
+
+ gst_video_overlay_set_window_handle (d->overlay, (guintptr) window_handle);
+ gst_video_overlay_set_render_rectangle (d->overlay, allocation.x,
+ allocation.y, allocation.width, allocation.height);
+
+ goto drop;
+ }
+
+ return GST_BUS_PASS;
+
+drop:
+ gst_message_unref (message);
+ return GST_BUS_DROP;
+}
+
+/* We use the "draw" callback to change the size of the sink
+ * because the "configure-event" is only sent to top-level widgets. */
+static gboolean
+video_widget_draw_cb (GtkWidget * widget, cairo_t * cr, gpointer user_data)
+{
+ DemoApp *d = user_data;
+ GtkAllocation allocation;
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ g_print ("draw_cb x %d, y %d, w %d, h %d\n",
+ allocation.x, allocation.y, allocation.width, allocation.height);
+
+ if (d->overlay) {
+ gst_video_overlay_set_render_rectangle (d->overlay, allocation.x,
+ allocation.y, allocation.width, allocation.height);
+ }
+
+ /* There is no need to call gst_video_overlay_expose().
+ * The wayland compositor can always re-draw the window
+ * based on its last contents if necessary */
+
+ return FALSE;
+}
+
+static void
+playing_clicked_cb (GtkButton * button, DemoApp * d)
+{
+ gst_element_set_state (d->pipeline, GST_STATE_PLAYING);
+}
+
+static void
+paused_clicked_cb (GtkButton * button, DemoApp * d)
+{
+ gst_element_set_state (d->pipeline, GST_STATE_PAUSED);
+}
+
+static void
+ready_clicked_cb (GtkButton * button, DemoApp * d)
+{
+ gst_element_set_state (d->pipeline, GST_STATE_READY);
+}
+
+static void
+null_clicked_cb (GtkButton * button, DemoApp * d)
+{
+ gst_element_set_state (d->pipeline, GST_STATE_NULL);
+}
+
+static void
+build_window (DemoApp * d)
+{
+ GtkBuilder *builder;
+ GtkWidget *button;
+ GError *error = NULL;
+
+ builder = gtk_builder_new ();
+ if (!gtk_builder_add_from_file (builder, "window.ui", &error)) {
+ g_error ("Failed to load window.ui: %s", error->message);
+ g_error_free (error);
+ goto exit;
+ }
+
+ d->app_widget = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
+ g_object_ref (d->app_widget);
+ g_signal_connect (d->app_widget, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+ d->video_widget = GTK_WIDGET (gtk_builder_get_object (builder, "videoarea"));
+ g_signal_connect (d->video_widget, "draw",
+ G_CALLBACK (video_widget_draw_cb), d);
+
+ button = GTK_WIDGET (gtk_builder_get_object (builder, "button_playing"));
+ g_signal_connect (button, "clicked", G_CALLBACK (playing_clicked_cb), d);
+
+ button = GTK_WIDGET (gtk_builder_get_object (builder, "button_paused"));
+ g_signal_connect (button, "clicked", G_CALLBACK (paused_clicked_cb), d);
+
+ button = GTK_WIDGET (gtk_builder_get_object (builder, "button_ready"));
+ g_signal_connect (button, "clicked", G_CALLBACK (ready_clicked_cb), d);
+
+ button = GTK_WIDGET (gtk_builder_get_object (builder, "button_null"));
+ g_signal_connect (button, "clicked", G_CALLBACK (null_clicked_cb), d);
+
+ gtk_widget_show_all (d->app_widget);
+
+exit:
+ g_object_unref (builder);
+}
+
+int
+main (int argc, char **argv)
+{
+ DemoApp *d;
+ GOptionContext *context;
+ GstBus *bus;
+ GError *error = NULL;
+
+ gtk_init (&argc, &argv);
+ gst_init (&argc, &argv);
+
+ context = g_option_context_new ("- waylandsink gtk demo");
+ g_option_context_add_main_entries (context, entries, NULL);
+ if (!g_option_context_parse (context, &argc, &argv, &error)) {
+ g_printerr ("option parsing failed: %s\n", error->message);
+ return 1;
+ }
+
+ d = g_slice_new0 (DemoApp);
+ build_window (d);
+
+ if (argc > 1) {
+ d->argv = argv;
+ d->current_uri = 1;
+
+ d->pipeline = gst_parse_launch ("playbin video-sink=waylandsink", NULL);
+ g_object_set (d->pipeline, "uri", argv[d->current_uri], NULL);
+
+ /* enable looping */
+ g_signal_connect (d->pipeline, "about-to-finish",
+ G_CALLBACK (on_about_to_finish), d);
+ } else {
+ if (live) {
+ d->pipeline = gst_parse_launch ("videotestsrc pattern=18 "
+ "background-color=0x000062FF is-live=true ! waylandsink", NULL);
+ } else {
+ d->pipeline = gst_parse_launch ("videotestsrc pattern=18 "
+ "background-color=0x000062FF ! waylandsink", NULL);
+ }
+ }
+
+ bus = gst_pipeline_get_bus (GST_PIPELINE (d->pipeline));
+ gst_bus_add_signal_watch (bus);
+ g_signal_connect (bus, "message::error", G_CALLBACK (error_cb), d);
+ gst_bus_set_sync_handler (bus, bus_sync_handler, d, NULL);
+ gst_object_unref (bus);
+
+ gst_element_set_state (d->pipeline, GST_STATE_PLAYING);
+
+ gtk_main ();
+
+ gst_element_set_state (d->pipeline, GST_STATE_NULL);
+ gst_object_unref (d->pipeline);
+ g_object_unref (d->app_widget);
+ g_slice_free (DemoApp, d);
+
+ return 0;
+}
diff --git a/tests/examples/waylandsink/window.ui b/tests/examples/waylandsink/window.ui
new file mode 100644
index 000000000..ce6cf823c
--- /dev/null
+++ b/tests/examples/waylandsink/window.ui
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.2 -->
+<interface>
+ <requires lib="gtk+" version="3.0"/>
+ <object class="GtkWindow" id="window">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes">GStreamer Wayland GTK Demo</property>
+ <child>
+ <object class="GtkBox" id="box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkEventBox" id="videoarea">
+ <property name="width_request">400</property>
+ <property name="height_request">300</property>
+ <property name="visible">True</property>
+ <property name="app_paintable">True</property>
+ <property name="can_focus">False</property>
+ <property name="double_buffered">False</property>
+ <property name="vexpand">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButtonBox" id="buttonbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="layout_style">center</property>
+ <child>
+ <object class="GtkButton" id="button_playing">
+ <property name="label" translatable="yes">PLAYING</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_paused">
+ <property name="label" translatable="yes">PAUSED</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_ready">
+ <property name="label" translatable="yes">READY</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_null">
+ <property name="label" translatable="yes">NULL</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>