diff options
31 files changed, 5 insertions, 3822 deletions
diff --git a/.gitignore b/.gitignore index 7a0aef604..26e2eebc3 100644 --- a/.gitignore +++ b/.gitignore @@ -61,9 +61,6 @@ gst*orc.h /tests/examples/ipcpipeline/ipcpipeline1 /tests/examples/codecparsers/parse-jpeg /tests/examples/codecparsers/parse-vp8 -/tests/examples/gtk/gtkglsink -/tests/examples/gtk/gtksink -/tests/examples/gtk/glliveshader /tests/examples/shapewipe/shapewipe-example /tests/examples/jack/jack_client /tests/examples/opencv/gstmotioncells_dynamic_test diff --git a/Makefile.am b/Makefile.am index 732dc4b85..62b902a7d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -52,6 +52,7 @@ CRUFT_FILES = \ $(top_builddir)/docs/plugins/xml/plugin-sdp.xml \ $(top_builddir)/ext/alsaspdif/.libs/*.{so,dll,DLL,dylib} \ $(top_builddir)/ext/gtk/.libs/libgstgtksink.so \ + $(top_builddir)/ext/gtk/.libs/libgstgtk.so \ $(top_builddir)/ext/hls/.libs/libgstfragmented* \ $(top_builddir)/ext/ivorbis/.libs/*.{so,dll,DLL,dylib} \ $(top_builddir)/ext/jack/.libs/*.{so,dll,DLL,dylib} \ @@ -126,6 +127,7 @@ CRUFT_DIRS = \ $(top_srcdir)/gst-libs/gst/signalprocessor \ $(top_srcdir)/tests/examples/gl \ $(top_srcdir)/tests/examples/scaletempo \ + $(top_srcdir)/tests/examples/gtk \ $(top_srcdir)/tests/examples/shapewipe \ $(top_srcdir)/tests/examples/switch \ $(top_srcdir)/tests/examples/jack \ @@ -134,6 +136,7 @@ CRUFT_DIRS = \ $(top_srcdir)/ext/cog \ $(top_srcdir)/ext/eglgles \ $(top_srcdir)/ext/gsettings \ + $(top_srcdir)/ext/gtk \ $(top_srcdir)/ext/ivorbis \ $(top_srcdir)/ext/jack \ $(top_srcdir)/ext/metadata \ diff --git a/configure.ac b/configure.ac index 1516f66b3..f3faaab12 100644 --- a/configure.ac +++ b/configure.ac @@ -1943,42 +1943,6 @@ AG_GST_CHECK_FEATURE(GL, [gl elements], gl, [ AM_CONDITIONAL(USE_GL, test "x$HAVE_GL" = "xyes") AM_CONDITIONAL(USE_OPENGL, test "x$GST_GL_HAVE_API_GL" = "x1") -dnl *** gtk+ *** -HAVE_GTK3_GL="no" -translit(dnm, m, l) AM_CONDITIONAL(USE_GTK3, true) -AG_GST_CHECK_FEATURE(GTK3, [Gtk+ elements], gtk, [ - PKG_CHECK_MODULES(GTK3, gtk+-3.0, [ - AC_DEFINE([HAVE_GTK3], 1, [Define if Gtk+ 3.0 is installed]) - HAVE_GTK3="yes" - ], [ - HAVE_GTK3="no" - ]) - PKG_CHECK_MODULES(GTK3_GL, gtk+-3.0 >= 3.15.0, [ - GDK_WINDOWING="no" - if test "x$GST_GL_HAVE_WINDOW_X11" = "x1" -a "x$GST_GL_HAVE_PLATFORM_GLX" = "x1"; then - PKG_CHECK_MODULES(GTK3_X11, gtk+-x11-3.0, [ - GTK3_CFLAGS="$GTK3_CFLAGS $GTK3_X11_CFLAGS" - GTK3_LIBS="$GTK3_LIBS $GTK3_X11_LIBS" - GDK_WINDOWING="yes" - ], [AC_MSG_NOTICE([Could not find Gtk X11 integration])]) - fi - if test "x$GST_GL_HAVE_WINDOW_WAYLAND" = "x1" -a "x$GST_GL_HAVE_PLATFORM_EGL" = "x1"; then - PKG_CHECK_MODULES(GTK3_WAYLAND, gtk+-wayland-3.0, [ - GTK3_CFLAGS="$GTK3_CFLAGS $GTK3_WAYLAND_CFLAGS" - GTK3_LIBS="$GTK3_LIBS $GTK3_WAYLAND_LIBS" - GDK_WINDOWING="yes" - ], [AC_MSG_NOTICE([Could not find Gtk Wayland integration])]) - fi - if test "x$GDK_WINDOWING" = "xyes"; then - AC_DEFINE([HAVE_GTK3_GL], 1, [Define if Gtk+ 3.0 GL is installed]) - HAVE_GTK3_GL="yes" - fi - ], [ - HAVE_GTK3_GL="no" - ]) -]) -AM_CONDITIONAL(USE_GTK3_GL, test "x$HAVE_GTK3_GL" = "xyes") - dnl *** Qt *** translit(dnm, m, l) AM_CONDITIONAL(USE_QT, true) AG_GST_CHECK_FEATURE(QT, [Qt elements], qt, [ @@ -2735,7 +2699,6 @@ tests/examples/camerabin2/Makefile tests/examples/codecparsers/Makefile tests/examples/directfb/Makefile tests/examples/audiomixmatrix/Makefile -tests/examples/gtk/Makefile tests/examples/ipcpipeline/Makefile tests/examples/mpegts/Makefile tests/examples/mxf/Makefile @@ -2759,7 +2722,6 @@ ext/directfb/Makefile ext/wayland/Makefile ext/daala/Makefile ext/dts/Makefile -ext/gtk/Makefile ext/faac/Makefile ext/faad/Makefile ext/fdkaac/Makefile diff --git a/docs/plugins/gst-plugins-bad-plugins-sections.txt b/docs/plugins/gst-plugins-bad-plugins-sections.txt index 324e17db6..89d9b33b9 100644 --- a/docs/plugins/gst-plugins-bad-plugins-sections.txt +++ b/docs/plugins/gst-plugins-bad-plugins-sections.txt @@ -1602,38 +1602,6 @@ gst_grabcut_get_type </SECTION> <SECTION> -<FILE>element-gtkglsink</FILE> -<TITLE>gtkglsink</TITLE> -GstGtkGLSink -<SUBSECTION Standard> -GstGtkGLSinkClass -GST_GTK_GL_SINK -GST_GTK_GL_SINK_CAST -GST_IS_GTK_GL_SINK -GST_GTK_GL_SINK_CLASS -GST_IS_GTK_GL_SINK_CLASS -GST_TYPE_GTK_GL_SINK -<SUBSECTION Private> -gst_gtk_gl_sink_get_type -</SECTION> - -<SECTION> -<FILE>element-gtksink</FILE> -<TITLE>gtksink</TITLE> -GstGtkSink -<SUBSECTION Standard> -GstGtkSinkClass -GST_GTK_SINK -GST_GTK_SINK_CAST -GST_IS_GTK_SINK -GST_GTK_SINK_CLASS -GST_IS_GTK_SINK_CLASS -GST_TYPE_GTK_SINK -<SUBSECTION Private> -gst_gtk_sink_get_type -</SECTION> - -<SECTION> <FILE>element-h263parse</FILE> <TITLE>h263parse</TITLE> GstH263Parse diff --git a/docs/plugins/inspect/plugin-gstgtk.xml b/docs/plugins/inspect/plugin-gstgtk.xml deleted file mode 100644 index bf2222038..000000000 --- a/docs/plugins/inspect/plugin-gstgtk.xml +++ /dev/null @@ -1,43 +0,0 @@ -<plugin> - <name>gstgtk</name> - <description>Gtk+ sink</description> - <filename>../../ext/gtk/.libs/libgstgtksink.so</filename> - <basename>libgstgtksink.so</basename> - <version>1.11.2</version> - <license>LGPL</license> - <source>gst-plugins-bad</source> - <package>GStreamer Bad Plug-ins source release</package> - <origin>Unknown package origin</origin> - <elements> - <element> - <name>gtkglsink</name> - <longname>Gtk GL Video Sink</longname> - <class>Sink/Video</class> - <description>A video sink that renders to a GtkWidget using OpenGL</description> - <author>Matthew Waters <matthew@centricular.com></author> - <pads> - <caps> - <name>sink</name> - <direction>sink</direction> - <presence>always</presence> - <details>video/x-raw(memory:GLMemory), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(memory:GLMemory, meta:GstVideoOverlayComposition), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> - </caps> - </pads> - </element> - <element> - <name>gtksink</name> - <longname>Gtk Video Sink</longname> - <class>Sink/Video</class> - <description>A video sink that renders to a GtkWidget</description> - <author>Matthew Waters <matthew@centricular.com></author> - <pads> - <caps> - <name>sink</name> - <direction>sink</direction> - <presence>always</presence> - <details>video/x-raw, format=(string){ BGRx, BGRA }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> - </caps> - </pads> - </element> - </elements> -</plugin>
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-gtk.xml b/docs/plugins/inspect/plugin-gtk.xml deleted file mode 100644 index cf939b250..000000000 --- a/docs/plugins/inspect/plugin-gtk.xml +++ /dev/null @@ -1,43 +0,0 @@ -<plugin> - <name>gtk</name> - <description>Gtk+ sink</description> - <filename>../../ext/gtk/.libs/libgstgtk.so</filename> - <basename>libgstgtk.so</basename> - <version>1.13.0.1</version> - <license>LGPL</license> - <source>gst-plugins-bad</source> - <package>GStreamer Bad Plug-ins git</package> - <origin>Unknown package origin</origin> - <elements> - <element> - <name>gtkglsink</name> - <longname>Gtk GL Video Sink</longname> - <class>Sink/Video</class> - <description>A video sink that renders to a GtkWidget using OpenGL</description> - <author>Matthew Waters <matthew@centricular.com></author> - <pads> - <caps> - <name>sink</name> - <direction>sink</direction> - <presence>always</presence> - <details>video/x-raw(memory:GLMemory), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(memory:GLMemory, meta:GstVideoOverlayComposition), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> - </caps> - </pads> - </element> - <element> - <name>gtksink</name> - <longname>Gtk Video Sink</longname> - <class>Sink/Video</class> - <description>A video sink that renders to a GtkWidget</description> - <author>Matthew Waters <matthew@centricular.com></author> - <pads> - <caps> - <name>sink</name> - <direction>sink</direction> - <presence>always</presence> - <details>video/x-raw, format=(string){ BGRx, BGRA }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> - </caps> - </pads> - </element> - </elements> -</plugin>
\ No newline at end of file diff --git a/ext/Makefile.am b/ext/Makefile.am index cbea2e0bd..eeea9fc11 100644 --- a/ext/Makefile.am +++ b/ext/Makefile.am @@ -88,12 +88,6 @@ else GL_DIR= endif -if USE_GTK3 -GTK3_DIR=gtk -else -GTK3_DIR= -endif - if USE_QT QT_DIR=qt else @@ -437,7 +431,6 @@ SUBDIRS=\ $(DTS_DIR) \ $(RESINDVD_DIR) \ $(GL_DIR) \ - $(GTK3_DIR) \ $(QT_DIR) \ $(FAAC_DIR) \ $(FAAD_DIR) \ @@ -519,7 +512,6 @@ DIST_SUBDIRS = \ daala \ dts \ gl \ - gtk \ qt \ modplug \ mpeg2enc \ diff --git a/ext/gtk/Makefile.am b/ext/gtk/Makefile.am deleted file mode 100644 index 057ff3f18..000000000 --- a/ext/gtk/Makefile.am +++ /dev/null @@ -1,46 +0,0 @@ -# preamble -NULL = -BUILT_SOURCES = -CLEANFILES = -EXTRA_DIST = -DISTCLEANFILES = -lib_LTLIBRARIES = - -# source -sources = \ - gtkgstbasewidget.c \ - gtkgstbasewidget.h \ - gtkgstwidget.c \ - gtkgstwidget.h \ - gstgtkbasesink.c \ - gstgtkbasesink.h \ - gstgtksink.c \ - gstgtksink.h \ - gstgtkutils.c \ - gstgtkutils.h \ - gstplugin.c \ - $(NULL) - -libgstgtk_la_CFLAGS = \ - $(GST_PLUGINS_BAD_CFLAGS) \ - $(GST_PLUGINS_BASE_CFLAGS) \ - $(GST_GL_CFLAGS) \ - $(GST_CFLAGS) \ - $(GTK3_CFLAGS) -libgstgtk_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) \ - -lgstvideo-$(GST_API_VERSION) \ - $(GST_BASE_LIBS) \ - $(GTK3_LIBS) - -libgstgtk_la_SOURCES = $(sources) -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 += $(GST_GL_LIBS) -endif -endif - -plugin_LTLIBRARIES = libgstgtk.la diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c deleted file mode 100644 index 843c97f1b..000000000 --- a/ext/gtk/gstgtkbasesink.c +++ /dev/null @@ -1,495 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 - * @title: GstGtkBaseSink - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstgtkbasesink.h" -#include "gstgtkutils.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 gboolean gst_gtk_base_sink_stop (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); - -static void -gst_gtk_base_sink_navigation_interface_init (GstNavigationInterface * iface); - -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, - 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 -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 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, - 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; - gstbasesink_class->stop = gst_gtk_base_sink_stop; - - 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); - - 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); -} - -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 void -window_destroy_cb (GtkWidget * widget, GstGtkBaseSink * gtk_sink) -{ - GST_OBJECT_LOCK (gtk_sink); - gtk_sink->window = NULL; - 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); - gtk_sink->widget_destroy_id = 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; -} - -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: - { - 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 = - gst_gtk_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; - 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 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)) { - 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); - } -} - -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_on_main (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)) { - /* 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. */ - 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); - gst_sink->window_destroy_id = g_signal_connect (gst_sink->window, "destroy", - G_CALLBACK (window_destroy_cb), gst_sink); - } - - return TRUE; -} - -static gboolean -gst_gtk_base_sink_start (GstBaseSink * bsink) -{ - return ! !gst_gtk_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); - - if (gst_sink->window) { - gtk_widget_destroy (gst_sink->window); - gst_sink->window = NULL; - gst_sink->widget = NULL; - } - - return TRUE; -} - -static gboolean -gst_gtk_base_sink_stop (GstBaseSink * 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 -gst_gtk_widget_show_all_and_unref (GtkWidget * widget) -{ - gtk_widget_show_all (widget); - g_object_unref (widget); -} - -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_READY_TO_PAUSED: - { - GtkWindow *window = NULL; - - GST_OBJECT_LOCK (gtk_sink); - if (gtk_sink->window) - window = g_object_ref (gtk_sink->window); - GST_OBJECT_UNLOCK (gtk_sink); - - if (window) - gst_gtk_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) - 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_format (gtk_sink->widget, >k_sink->v_info)) { - GST_OBJECT_UNLOCK (gtk_sink); - 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 deleted file mode 100644 index ef8c28495..000000000 --- a/ext/gtk/gstgtkbasesink.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 <gtk/gtk.h> -#include <gst/gst.h> -#include <gst/video/gstvideosink.h> -#include <gst/video/video.h> - -#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 -{ - /* <private> */ - 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; - - GtkWidget *window; - gulong widget_destroy_id; - gulong window_destroy_id; -}; - -/** - * 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__ */ diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c deleted file mode 100644 index 4439e85fb..000000000 --- a/ext/gtk/gstgtkglsink.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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:element-gtkglsink - * @title: gtkglsink - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gst/gl/gstglfuncs.h> - -#include "gstgtkglsink.h" -#include "gtkgstglwidget.h" - -GST_DEBUG_CATEGORY (gst_debug_gtk_gl_sink); -#define GST_CAT_DEFAULT gst_debug_gtk_gl_sink - -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 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", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES - (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, - GST_TYPE_GTK_BASE_SINK, GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_gl_sink, - "gtkglsink", 0, "Gtk GL Video Sink")); - -static void -gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) -{ - GstElementClass *gstelement_class; - GstBaseSinkClass *gstbasesink_class; - GstGtkBaseSinkClass *gstgtkbasesink_class; - - gstelement_class = (GstElementClass *) klass; - gstbasesink_class = (GstBaseSinkClass *) klass; - gstgtkbasesink_class = (GstGtkBaseSinkClass *) klass; - - 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; - 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"; - - 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 <matthew@centricular.com>"); - - gst_element_class_add_static_pad_template (gstelement_class, - &gst_gtk_gl_sink_template); -} - -static void -gst_gtk_gl_sink_init (GstGtkGLSink * gtk_sink) -{ -} - -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: - { - if (gst_gl_handle_context_query ((GstElement *) gtk_sink, query, - gtk_sink->display, gtk_sink->context, gtk_sink->gtk_context)) - return TRUE; - break; - } - default: - res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); - break; - } - - 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) -{ - 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); - - /* 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; - - 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; - - gst_gl_element_propagate_display_context (GST_ELEMENT (bsink), - gtk_sink->display); - - return TRUE; -} - -static gboolean -gst_gtk_gl_sink_stop (GstBaseSink * bsink) -{ - GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (bsink); - - 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; - } - - return GST_BASE_SINK_CLASS (parent_class)->stop (bsink); -} - -static gboolean -gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) -{ - GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (bsink); - GstBufferPool *pool = NULL; - GstStructure *config; - GstCaps *caps; - GstVideoInfo info; - guint size; - gboolean need_pool; - GstStructure *allocation_meta = NULL; - gint display_width, display_height; - - if (!gtk_sink->display || !gtk_sink->context) - return FALSE; - - gst_query_parse_allocation (query, &caps, &need_pool); - - 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) { - GST_DEBUG_OBJECT (gtk_sink, "create new pool"); - pool = gst_gl_buffer_pool_new (gtk_sink->context); - - 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; - } - - /* 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; - 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); - - 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; - } -} - -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 deleted file mode 100644 index 789cf33f6..000000000 --- a/ext/gtk/gstgtkglsink.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 <gtk/gtk.h> -#include <gst/gst.h> -#include <gst/video/gstvideosink.h> -#include <gst/video/video.h> -#include <gst/gl/gl.h> - -#include "gstgtkbasesink.h" - - -#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)) - -G_BEGIN_DECLS - -typedef struct _GstGtkGLSink GstGtkGLSink; -typedef struct _GstGtkGLSinkClass GstGtkGLSinkClass; - -GType gst_gtk_gl_sink_get_type (void); - -/** - * GstGtkGLSink: - * - * Opaque #GstGtkGLSink object - */ -struct _GstGtkGLSink -{ - /* <private> */ - GstGtkBaseSink parent; - - GstGLDisplay *display; - GstGLContext *context; - GstGLContext *gtk_context; - - GstGLUpload *upload; - GstBuffer *uploaded_buffer; - - /* read/write with object lock */ - gint display_width; - gint display_height; -}; - -/** - * GstGtkGLSinkClass: - * - * The #GstGtkGLSinkClass struct only contains private data - */ -struct _GstGtkGLSinkClass -{ - /* <private> */ - GstGtkBaseSinkClass object_class; -}; - -G_END_DECLS - -#endif /* __GST_GTK_GL_SINK_H__ */ diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c deleted file mode 100644 index ba8ea33ca..000000000 --- a/ext/gtk/gstgtksink.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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:element-gtkgstsink - * @title: gtkgstsink - * - */ - -#ifdef HAVE_CONFIG_H -#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 - -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -#define FORMATS "{ BGRx, BGRA }" -#else -#define FORMATS "{ xRGB, 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 (FORMATS)) - ); - -#define gst_gtk_sink_parent_class parent_class -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) -{ - GstElementClass *gstelement_class; - GstGtkBaseSinkClass *base_class; - - gstelement_class = (GstElementClass *) klass; - base_class = (GstGtkBaseSinkClass *) klass; - - 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 <matthew@centricular.com>"); - - gst_element_class_add_static_pad_template (gstelement_class, - &gst_gtk_sink_template); -} - -static void -gst_gtk_sink_init (GstGtkSink * gtk_sink) -{ -} diff --git a/ext/gtk/gstgtksink.h b/ext/gtk/gstgtksink.h deleted file mode 100644 index 7dad3b053..000000000 --- a/ext/gtk/gstgtksink.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 <gtk/gtk.h> -#include <gst/gst.h> -#include <gst/video/gstvideosink.h> -#include <gst/video/video.h> - -#include "gstgtkbasesink.h" - -#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)) - -G_BEGIN_DECLS - -typedef struct _GstGtkSink GstGtkSink; -typedef struct _GstGtkSinkClass GstGtkSinkClass; - -GType gst_gtk_sink_get_type (void); - -/** - * GstGtkSink: - * - * Opaque #GstGtkSink object - */ -struct _GstGtkSink -{ - /* <private> */ - GstGtkBaseSink parent; -}; - -/** - * GstGtkSinkClass: - * - * The #GstGtkSinkClass struct only contains private data - */ -struct _GstGtkSinkClass -{ - /* <private> */ - GstGtkBaseSinkClass object_class; -}; - -G_END_DECLS - -#endif /* __GST_GTK_SINK_H__ */ diff --git a/ext/gtk/gstgtkutils.c b/ext/gtk/gstgtkutils.c deleted file mode 100644 index c730f0188..000000000 --- a/ext/gtk/gstgtkutils.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * Copyright (C) 2015 Thibault Saunier <tsaunier@gnome.org> - * - * 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 deleted file mode 100644 index 7584ae2c6..000000000 --- a/ext/gtk/gstgtkutils.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * Copyright (C) 2015 Thibault Saunier <tsaunier@gnome.org> - * - * 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 <glib.h> - -gpointer gst_gtk_invoke_on_main (GThreadFunc func, gpointer data); - -#endif /* __GST_GTK_UTILS_H__ */ diff --git a/ext/gtk/gstplugin.c b/ext/gtk/gstplugin.c deleted file mode 100644 index ed275785b..000000000 --- a/ext/gtk/gstplugin.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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, - gtk, - "Gtk+ sink", - plugin_init, PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, - GST_PACKAGE_ORIGIN) diff --git a/ext/gtk/gtkgstbasewidget.c b/ext/gtk/gtkgstbasewidget.c deleted file mode 100644 index 4858f2764..000000000 --- a/ext/gtk/gtkgstbasewidget.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 <stdio.h> - -#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 -#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 -_calculate_par (GtkGstBaseWidget * widget, GstVideoInfo * info) -{ - gboolean ok; - gint width, height; - gint par_n, par_d; - gint display_par_n, display_par_d; - - 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 (&widget->display_ratio_num, - &widget->display_ratio_den, width, height, par_n, par_d, display_par_n, - display_par_d); - - if (ok) { - GST_LOG ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n, - display_par_d); - return TRUE; - } - - 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"); - 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); -} - -static gboolean -_queue_draw (GtkGstBaseWidget * widget) -{ - GTK_GST_BASE_WIDGET_LOCK (widget); - widget->draw_id = 0; - - if (widget->pending_resize) { - widget->pending_resize = FALSE; - - widget->v_info = widget->pending_v_info; - widget->negotiated = 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; -} - -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 FALSE; -} - -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) -{ - 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"; - 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, x, y); - } - g_object_unref (element); - } - - return FALSE; -} - -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)) { - gdouble x, y; - - _display_size_to_stream_size (base_widget, event->x, event->y, &x, &y); - - gst_navigation_send_mouse_event (GST_NAVIGATION (element), "mouse-move", - 0, x, y); - } - g_object_unref (element); - } - - return FALSE; -} - -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; - 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; - - GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_widget, "gtkbasewidget", 0, - "Gtk Video Base Widget"); -} - -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; - widget->ignore_alpha = DEFAULT_IGNORE_ALPHA; - - 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 -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); - - 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) -{ - GTK_GST_BASE_WIDGET_LOCK (widget); - - if (gst_video_info_is_equal (&widget->pending_v_info, v_info)) { - GTK_GST_BASE_WIDGET_UNLOCK (widget); - return TRUE; - } - - if (!_calculate_par (widget, v_info)) { - GTK_GST_BASE_WIDGET_UNLOCK (widget); - return FALSE; - } - - widget->pending_resize = TRUE; - widget->pending_v_info = *v_info; - - 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)); - - GTK_GST_BASE_WIDGET_LOCK (widget); - - gst_buffer_replace (&widget->pending_buffer, buffer); - - 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 deleted file mode 100644 index 13737c632..000000000 --- a/ext/gtk/gtkgstbasewidget.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 <gtk/gtk.h> -#include <gst/gst.h> -#include <gst/video/video.h> - -#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 *pending_buffer; - GstBuffer *buffer; - GstVideoInfo v_info; - - /* resize */ - gboolean pending_resize; - GstVideoInfo pending_v_info; - guint display_ratio_num; - guint display_ratio_den; - - /*< private >*/ - GMutex lock; - GWeakRef element; - - /* Pending draw idles callback */ - guint draw_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_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 - -#endif /* __GTK_GST_BASE_WIDGET_H__ */ diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c deleted file mode 100644 index 76c46c9c8..000000000 --- a/ext/gtk/gtkgstglwidget.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 <stdio.h> - -#include "gtkgstglwidget.h" -#include "gstgtkutils.h" -#include <gst/gl/gstglfuncs.h> -#include <gst/video/video.h> - -#if GST_GL_HAVE_WINDOW_X11 && GST_GL_HAVE_PLATFORM_GLX && defined (GDK_WINDOWING_X11) -#include <gdk/gdkx.h> -#include <gst/gl/x11/gstgldisplay_x11.h> -#endif - -#if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (GDK_WINDOWING_WAYLAND) -#include <gdk/gdkwayland.h> -#include <gst/gl/wayland/gstgldisplay_wayland.h> -#endif - -/** - * SECTION:gtkgstglwidget - * @title: 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 -{ - 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; - GstGLOverlayCompositor *overlay_compositor; -}; - -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) -{ - GtkGstGLWidgetPrivate *priv = gst_widget->priv; - const GstGLFuncs *gl = priv->context->gl_vtable; - - gl->BindBuffer (GL_ARRAY_BUFFER, priv->vertex_buffer); - - /* Load the vertex position */ - gl->VertexAttribPointer (priv->attr_position, 3, GL_FLOAT, GL_FALSE, - 5 * sizeof (GLfloat), (void *) 0); - - /* Load the texture coordinate */ - gl->VertexAttribPointer (priv->attr_texture, 2, GL_FLOAT, GL_FALSE, - 5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat))); - - gl->EnableVertexAttribArray (priv->attr_position); - gl->EnableVertexAttribArray (priv->attr_texture); -} - -static void -gtk_gst_gl_widget_unbind_buffer (GtkGstGLWidget * gst_widget) -{ - GtkGstGLWidgetPrivate *priv = gst_widget->priv; - const GstGLFuncs *gl = priv->context->gl_vtable; - - gl->BindBuffer (GL_ARRAY_BUFFER, 0); - - gl->DisableVertexAttribArray (priv->attr_position); - gl->DisableVertexAttribArray (priv->attr_texture); -} - -static void -gtk_gst_gl_widget_init_redisplay (GtkGstGLWidget * gst_widget) -{ - GtkGstGLWidgetPrivate *priv = gst_widget->priv; - const GstGLFuncs *gl = priv->context->gl_vtable; - GError *error = NULL; - - 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; - } - - 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); - gl->BindVertexArray (priv->vao); - } - - 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); - - if (gl->GenVertexArrays) { - gtk_gst_gl_widget_bind_buffer (gst_widget); - gl->BindVertexArray (0); - } - - gl->BindBuffer (GL_ARRAY_BUFFER, 0); - - priv->overlay_compositor = - gst_gl_overlay_compositor_new (priv->other_context); - - priv->initted = TRUE; -} - -static void -_redraw_texture (GtkGstGLWidget * gst_widget, guint tex) -{ - GtkGstGLWidgetPrivate *priv = gst_widget->priv; - const GstGLFuncs *gl = priv->context->gl_vtable; - const GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; - - if (gst_widget->base.force_aspect_ratio) { - GstVideoRectangle src, dst, result; - gint widget_width, widget_height, widget_scale; - - gl->ClearColor (0.0, 0.0, 0.0, 0.0); - gl->Clear (GL_COLOR_BUFFER_BIT); - - 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->base.display_width; - src.h = gst_widget->base.display_height; - - 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); - - gl->Viewport (result.x, result.y, result.w, result.h); - } - - gst_gl_shader_use (priv->shader); - - if (gl->BindVertexArray) - gl->BindVertexArray (priv->vao); - gtk_gst_gl_widget_bind_buffer (gst_widget); - - gl->ActiveTexture (GL_TEXTURE0); - gl->BindTexture (GL_TEXTURE_2D, tex); - gst_gl_shader_set_uniform_1i (priv->shader, "tex", 0); - - gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); - - if (gl->BindVertexArray) - gl->BindVertexArray (0); - gtk_gst_gl_widget_unbind_buffer (gst_widget); - - gl->BindTexture (GL_TEXTURE_2D, 0); -} - -static inline void -_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); -} - -static gboolean -gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) -{ - GtkGstGLWidgetPrivate *priv = GTK_GST_GL_WIDGET (widget)->priv; - GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget); - - GTK_GST_BASE_WIDGET_LOCK (widget); - - 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) { - _draw_black (priv->other_context); - 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 (priv->other_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); - - 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); - } - - 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); - 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); - - GTK_GST_BASE_WIDGET_UNLOCK (widget); - return FALSE; -} - -static void -_reset_gl (GtkGstGLWidget * gst_widget) -{ - GtkGstGLWidgetPrivate *priv = gst_widget->priv; - const GstGLFuncs *gl = priv->other_context->gl_vtable; - - 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 (priv->gdk_context); - gst_gl_context_activate (priv->other_context, TRUE); - - 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; - } - - if (priv->upload) { - gst_object_unref (priv->upload); - priv->upload = NULL; - } - - if (priv->shader) { - gst_object_unref (priv->shader); - 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); - priv->other_context = NULL; - - gdk_gl_context_clear_current (); - - g_object_unref (priv->gdk_context); - priv->gdk_context = NULL; -} - -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); - - if (priv->other_context) - gst_gtk_invoke_on_main ((GThreadFunc) _reset_gl, base_widget); - - if (priv->context) - gst_object_unref (priv->context); - - 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_class_init (GtkGstGLWidgetClass * klass) -{ - GObjectClass *gobject_klass = (GObjectClass *) klass; - GtkGLAreaClass *gl_widget_klass = (GtkGLAreaClass *) 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; -} - -static void -gtk_gst_gl_widget_init (GtkGstGLWidget * gst_widget) -{ - GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (gst_widget); - GdkDisplay *display; - GtkGstGLWidgetPrivate *priv; - - gtk_gst_base_widget_init (base_widget); - - gst_widget->priv = priv = GTK_GST_GL_WIDGET_GET_PRIVATE (gst_widget); - - display = gdk_display_get_default (); - -#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 && 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); - priv->display = (GstGLDisplay *) - gst_gl_display_wayland_new_with_display (wayland_display); - } -#endif - - (void) display; - - if (!priv->display) - priv->display = gst_gl_display_new (); - - gtk_gl_area_set_has_alpha (GTK_GL_AREA (gst_widget), - !base_widget->ignore_alpha); -} - -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 (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)); - - GST_ERROR_OBJECT (gst_widget, "Error creating GdkGLContext : %s", - error ? error->message : "No error set by Gdk"); - g_clear_error (&error); - return; - } - - g_object_ref (priv->gdk_context); - - gdk_gl_context_make_current (priv->gdk_context); - -#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); - gl_handle = gst_gl_context_get_current_gl_context (platform); - if (gl_handle) - priv->other_context = - gst_gl_context_new_wrapped (priv->display, gl_handle, - platform, gl_api); - } -#endif -#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); - gl_handle = gst_gl_context_get_current_gl_context (platform); - if (gl_handle) - priv->other_context = - gst_gl_context_new_wrapped (priv->display, gl_handle, - platform, gl_api); - } -#endif - - (void) platform; - (void) gl_api; - (void) gl_handle; - - if (priv->other_context) { - GError *error = NULL; - - 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 { - gst_gl_context_activate (priv->other_context, FALSE); - } - } -} - -GtkWidget * -gtk_gst_gl_widget_new (void) -{ - return (GtkWidget *) g_object_new (GTK_TYPE_GST_GL_WIDGET, NULL); -} - -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); - g_return_val_if_fail (priv->display != NULL, FALSE); - - 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 (!priv->other_context) { - GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); - gst_gtk_invoke_on_main ((GThreadFunc) _get_gl_context, gst_widget); - GTK_GST_BASE_WIDGET_LOCK (gst_widget); - } - - if (!GST_IS_GL_CONTEXT (priv->other_context)) { - GTK_GST_BASE_WIDGET_UNLOCK (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; -} - -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 deleted file mode 100644 index 7f055c481..000000000 --- a/ext/gtk/gtkgstglwidget.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 <gtk/gtk.h> -#include <gst/gst.h> -#include <gst/gl/gl.h> - -#include "gtkgstbasewidget.h" - -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 -{ - /* <private> */ - GtkGstBaseWidget base; - - GtkGstGLWidgetPrivate *priv; -}; - -/** - * GtkGstGLWidgetClass: - * - * The #GtkGstGLWidgetClass struct only contains private data - */ -struct _GtkGstGLWidgetClass -{ - /* <private> */ - GtkGstBaseWidgetClass base_class; -}; - -GtkWidget * gtk_gst_gl_widget_new (void); - -gboolean gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * widget); -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 deleted file mode 100644 index a936210ba..000000000 --- a/ext/gtk/gtkgstwidget.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 <stdio.h> - -#include "gtkgstwidget.h" -#include <gst/video/video.h> - -/** - * SECTION:gtkgstwidget - * @title: 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); - -static gboolean -gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) -{ - GtkGstBaseWidget *gst_widget = (GtkGstBaseWidget *) 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); - - 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, - 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->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], - format, frame.info.width, frame.info.height, frame.info.stride[0]); - - if (gst_widget->force_aspect_ratio) { - GstVideoRectangle src, dst; - - src.x = 0; - src.y = 0; - src.w = gst_widget->display_width; - src.h = gst_widget->display_height; - - 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; - } - - if (gst_widget->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->display_width / (gdouble) frame.info.width; - scale_y *= - (gdouble) gst_widget->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); - cairo_set_source_surface (cr, surface, 0, 0); - cairo_paint (cr); - - cairo_surface_destroy (surface); - - gst_video_frame_unmap (&frame); - } else { - GdkRGBA color; - - if (gst_widget->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); - } - - GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); - return FALSE; -} - -static void -gtk_gst_widget_finalize (GObject * object) -{ - gtk_gst_base_widget_finalize (object); - - G_OBJECT_CLASS (gtk_gst_widget_parent_class)->finalize (object); -} - -static void -gtk_gst_widget_class_init (GtkGstWidgetClass * klass) -{ - GObjectClass *gobject_klass = (GObjectClass *) klass; - GtkWidgetClass *widget_klass = (GtkWidgetClass *) klass; - - gtk_gst_base_widget_class_init (GTK_GST_BASE_WIDGET_CLASS (klass)); - gobject_klass->finalize = gtk_gst_widget_finalize; - widget_klass->draw = gtk_gst_widget_draw; -} - -static void -gtk_gst_widget_init (GtkGstWidget * widget) -{ - gtk_gst_base_widget_init (GTK_GST_BASE_WIDGET (widget)); -} - -GtkWidget * -gtk_gst_widget_new (void) -{ - return (GtkWidget *) g_object_new (GTK_TYPE_GST_WIDGET, NULL); -} diff --git a/ext/gtk/gtkgstwidget.h b/ext/gtk/gtkgstwidget.h deleted file mode 100644 index 427eebac4..000000000 --- a/ext/gtk/gtkgstwidget.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 <gtk/gtk.h> -#include <gst/gst.h> - -#include "gtkgstbasewidget.h" - -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; - -/** - * GtkGstWidget: - * - * Opaque #GtkGstWidget object - */ -struct _GtkGstWidget -{ - /* <private> */ - GtkGstBaseWidget base; -}; - -/** - * GtkGstWidgetClass: - * - * The #GtkGstWidgetClass struct only contains private data - */ -struct _GtkGstWidgetClass -{ - /* <private> */ - GtkGstBaseWidgetClass base_class; -}; - -GtkWidget * gtk_gst_widget_new (void); - -G_END_DECLS - -#endif /* __GTK_GST_WIDGET_H__ */ diff --git a/ext/gtk/meson.build b/ext/gtk/meson.build deleted file mode 100644 index 324bfba89..000000000 --- a/ext/gtk/meson.build +++ /dev/null @@ -1,54 +0,0 @@ -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 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 - have_gtk3_gl_windowing = true - endif - endif - - 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 - 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 - diff --git a/ext/meson.build b/ext/meson.build index a2960b8ee..b9c243f0b 100644 --- a/ext/meson.build +++ b/ext/meson.build @@ -18,7 +18,6 @@ subdir('fluidsynth') subdir('gl') #subdir('gme') subdir('gsm') -subdir('gtk') subdir('hls') subdir('iqa') subdir('kate') diff --git a/tests/examples/Makefile.am b/tests/examples/Makefile.am index b14b0232f..d11331e0f 100644 --- a/tests/examples/Makefile.am +++ b/tests/examples/Makefile.am @@ -30,12 +30,6 @@ else AVSAMPLE_DIR= endif -if USE_GTK3 -GTK3_DIR=gtk -else -GTK3_DIR= -endif - if USE_WAYLAND if HAVE_GTK3 WAYLAND_DIR=waylandsink @@ -65,9 +59,9 @@ 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) \ - $(GTK3_DIR) $(AVSAMPLE_DIR) $(WAYLAND_DIR) $(MATRIXMIX_DIR) \ + $(AVSAMPLE_DIR) $(WAYLAND_DIR) $(MATRIXMIX_DIR) \ $(IPCPIPELINE_DIR) $(WEBRTC_DIR) -DIST_SUBDIRS= codecparsers mpegts camerabin2 directfb mxf opencv uvch264 gtk \ +DIST_SUBDIRS= codecparsers mpegts camerabin2 directfb mxf opencv uvch264 \ avsamplesink waylandsink audiomixmatrix ipcpipeline webrtc include $(top_srcdir)/common/parallel-subdirs.mak diff --git a/tests/examples/gtk/Makefile.am b/tests/examples/gtk/Makefile.am deleted file mode 100644 index cd7962d52..000000000 --- a/tests/examples/gtk/Makefile.am +++ /dev/null @@ -1,41 +0,0 @@ - -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 glliveshader - -gtkglsink_SOURCES = gtkglsink.c -gtkglsink_CFLAGS = \ - $(GST_PLUGINS_BAD_CFLAGS) \ - $(GST_PLUGINS_BASE_CFLAGS) \ - $(GST_GL_CFLAGS) \ - $(GST_CFLAGS) \ - $(GL_CFLAGS) \ - $(GTK3_CFLAGS) -gtkglsink_LDADD = \ - $(GST_GL_LIBS) \ - $(GST_LIBS) \ - $(GTK3_LIBS) \ - $(X11_LIBS) - -glliveshader_SOURCES = glliveshader.c -glliveshader_CFLAGS = \ - $(GST_PLUGINS_BAD_CFLAGS) \ - $(GST_PLUGINS_BASE_CFLAGS) \ - $(GST_GL_CFLAGS) \ - $(GST_CFLAGS) \ - $(GTK3_CFLAGS) -glliveshader_LDADD = \ - $(GST_GL_LIBS) \ - $(GST_LIBS) \ - $(GTK3_LIBS) \ - $(X11_LIBS) -endif -endif diff --git a/tests/examples/gtk/glliveshader.c b/tests/examples/gtk/glliveshader.c deleted file mode 100644 index 03e745ee3..000000000 --- a/tests/examples/gtk/glliveshader.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 <gst/gl/gl.h> -#include <gst/gl/gstglfuncs.h> -#include <gtk/gtk.h> -#if GST_GL_HAVE_WINDOW_X11 -#include <X11/Xlib.h> -#endif - -#ifndef GL_GEOMETRY_SHADER -#define GL_GEOMETRY_SHADER 0x8DD9 -#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 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, *new_shader; - - g_object_get (G_OBJECT (element), "context", &context, "shader", &shader, - NULL); - - new_shader = _new_shader (context, state); - if (!shader && !new_shader) - g_warning ("Failed to create a shader!"); - state->shader_linked = new_shader != NULL; - - if (shader) - gst_object_unref (shader); - gst_object_unref (context); - - g_main_context_invoke (NULL, (GSourceFunc) _set_compilation_state, state); - - return new_shader; -} - -static void -_on_text_changed (GtkTextBuffer * text, struct text_view_state *state) -{ - GtkTextIter start, end; - - gtk_text_buffer_get_bounds (text, &start, &end); - 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); -} - -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; -} diff --git a/tests/examples/gtk/gtkglsink.c b/tests/examples/gtk/gtkglsink.c deleted file mode 100644 index 4b71985b0..000000000 --- a/tests/examples/gtk/gtkglsink.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2014 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 <gtk/gtk.h> -#include <gst/gst.h> - -#include <gst/gl/gl.h> - -#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11) -#include <gst/gl/x11/gstgldisplay_x11.h> -#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); - 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", - "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 deleted file mode 100644 index d86fd090e..000000000 --- a/tests/examples/gtk/gtksink.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2014 Matthew Waters <matthew@centricular.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 <gtk/gtk.h> -#include <gst/gst.h> - -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); - g_object_unref (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; -} diff --git a/tests/examples/meson.build b/tests/examples/meson.build index e646d4b89..5ccd9ebb1 100644 --- a/tests/examples/meson.build +++ b/tests/examples/meson.build @@ -5,7 +5,6 @@ #subdir('codecparsers') subdir('compositor') #subdir('directfb') -#subdir('gtk') #subdir('ipcpipeline') subdir('mpegts') #subdir('mxf') |