unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* GStreamer xwidget
       [not found] <87ee7cq2mu.fsf.ref@yahoo.com>
@ 2021-11-19  2:51 ` Po Lu
  2021-11-19  4:01   ` T.V Raman
                     ` (3 more replies)
  0 siblings, 4 replies; 70+ messages in thread
From: Po Lu @ 2021-11-19  2:51 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 506 bytes --]

I would like to install the following change that introduces a
GStreamer-based media widget.

It depends on GStreamer, gst-plugins-base, and gst-plugins-good and is
thus a compile-time option.

Right now, it can only display a test pattern, but getting that to work
and perform decently was a challenge (for instance, offscreen rendering
is not an option, instead the pipeline is dynamically built based on
available xwidget views, utilizing hardware acceleration and video
decoding if available).

WDYT?


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Implement-a-media-xwidget-based-on-GStreamer.patch --]
[-- Type: text/x-patch, Size: 31895 bytes --]

From 39a034aff24b2b64b028345aeae66c7aae6f8820 Mon Sep 17 00:00:00 2001
From: Po Lu <luangruo@yahoo.com>
Date: Thu, 18 Nov 2021 18:10:45 +0800
Subject: [PATCH] Implement a media xwidget based on GStreamer

* configure.ac: Add option to use GStreamer for media playback.
* doc/lispref/display.texi (Xwidgets): Document new functions
and xwidget type.

* src/Makefile.in (EMACS_CFLAGS): Add GStreamer cflags.
(LIBES): Add GStreamer linker options.

* etc/NEWS: Announce `media' xwidget.
* etc/xterm.c (x_scroll_run): Don't resize cairo surface
if not a GTK xwidget.
(x_term_init): Initialize GStreamer.

* src/xwidget.c (gst_create_window)
(gst_message_cb, unlink_gst_xwidget_view)
(check_gstreamer_dependencies): New functions.

(Fmake_xwidget): Add support for media xwidgets.
(Fxwidget_perform_lispy_event): Return nil if it doesn't make
sense to perform an event.
(Fxwidget_resize): Add support for media widgets.
(xwidget_button, xwidget_motion_or_crossing): Handle non-GTK
xwidgets.
(xwidget_expose): Handle media xwidgets.
(x_draw_xwidget_glyph_string): Set up GStreamer widgets if
appropriate.
(Fxwidget_size_request): Return nil on widgets that can't
have a size request.
(Fdelete_xwidget_view): Clean up after GStreamer.
(Fxwidget_media_pause, Fxwidget_media_play): New functions.

(syms_of_xwidget): New symbols and subrs.
(kill_xwidget): Clean up after GStreamer.

* src/xwidget.h (struct xwidget, struct xwidget_view): Add
GStreamer specific fields for media xwidgets.
(XWIDGET_VIEW_GTK_P): New macro.
---
 configure.ac             |  13 +
 doc/lispref/display.texi |  12 +
 etc/NEWS                 |   7 +
 src/Makefile.in          |   7 +-
 src/xterm.c              |  16 +-
 src/xwidget.c            | 536 +++++++++++++++++++++++++++++++--------
 src/xwidget.h            |  25 ++
 7 files changed, 508 insertions(+), 108 deletions(-)

diff --git a/configure.ac b/configure.ac
index c231c2ceae..ae3f28f8db 100644
--- a/configure.ac
+++ b/configure.ac
@@ -485,6 +485,7 @@ AC_DEFUN
 OPTION_DEFAULT_ON([zlib],[don't compile with zlib decompression support])
 OPTION_DEFAULT_ON([modules],[don't compile with dynamic modules support])
 OPTION_DEFAULT_ON([threads],[don't compile with elisp threading support])
+OPTION_DEFAULT_OFF([gstreamer],[compile with xwidget video playback support using GStreamer])
 OPTION_DEFAULT_OFF([native-compilation],[compile with Emacs Lisp native compiler support])
 OPTION_DEFAULT_OFF([cygwin32-native-compilation],[use native compilation on 32-bit Cygwin])
 
@@ -2834,6 +2835,18 @@ AC_DEFUN
 fi
 AC_SUBST(XWIDGETS_OBJ)
 
+HAVE_GSTREAMER=no
+if test "$with_gstreamer" != "no" && test "${HAVE_X_WINDOWS}" = "yes" \
+   && test "${HAVE_XWIDGETS}" = "yes"; then
+  EMACS_CHECK_MODULES([GSTREAMER], "gstreamer-1.0 gstreamer-video-1.0")
+  if test "$HAVE_GSTREAMER" = "yes"; then
+    AC_DEFINE(HAVE_GSTREAMER, 1, [Define to 1 if using GStreamer for video support in xwidgets.])
+  fi
+fi
+
+AC_SUBST(GSTREAMER_CFLAGS)
+AC_SUBST(GSTREAMER_LIBS)
+
 CFLAGS=$OLD_CFLAGS
 LIBS=$OLD_LIBS
 
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index dd2c6e003f..1b4a3d9a22 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -6797,6 +6797,8 @@ Xwidgets
 @table @code
 @item webkit
 The WebKit component.
+@item media
+A media widget that allows to display videos inside Emacs buffers.
 @end table
 
 The @var{width} and @var{height} arguments specify the widget size in
@@ -7004,6 +7006,16 @@ Xwidgets
 be passed as an index to @code{xwidget-webkit-goto-history}.
 @end defun
 
+@defun xwidget-media-pause xwidget
+Suspend playback of @var{xwidget}, a media xwidget.  You can later
+resume playback using @code{xwidget-media-play}.
+@end defun
+
+@defun xwidget-media-pause xwidget
+Start or resume playback of @var{xwidget}, a media xwidget.  You can
+later pause playback using @code{xwidget-media-pause}.
+@end defun
+
 @node Buttons
 @section Buttons
 @cindex buttons in buffers
diff --git a/etc/NEWS b/etc/NEWS
index cee2844be3..8cb5495b4e 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -488,6 +488,13 @@ This is a convenience function to extract the field data from
 
 ** Xwidgets
 
++++
+*** New xwidget type 'media'.
+This xwidget type allows to display video content inside Emacs buffers.
+You must have the GStreamer library installed, along with the plugins
+"xvimagesink", "queue", "videotestsrc" and "tee", and Emacs must be
+built with '--with-gstreamer'.
+
 ---
 *** New user option 'xwidget-webkit-buffer-name-format'.
 Using this option you can control how the xwidget-webkit buffers are
diff --git a/src/Makefile.in b/src/Makefile.in
index 4c5535f8ad..646392c051 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -333,6 +333,9 @@ LIBGMP =
 LIBGCCJIT_LIBS = @LIBGCCJIT_LIBS@
 LIBGCCJIT_CFLAGS = @LIBGCCJIT_CFLAGS@
 
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+
 ## dynlib.o if necessary, else empty
 DYNLIB_OBJ = @DYNLIB_OBJ@
 
@@ -377,7 +380,7 @@ EMACS_CFLAGS=
   $(WEBKIT_CFLAGS) $(WEBP_CFLAGS) $(LCMS2_CFLAGS) \
   $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
   $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
-  $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \
+  $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) $(GSTREAMER_CFLAGS) \
   $(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \
   $(WERROR_CFLAGS)
 ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS)
@@ -524,7 +527,7 @@ LIBES =
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
    $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \
    $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \
-   $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS)
+   $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS) $(GSTREAMER_LIBS)
 
 ## FORCE it so that admin/unidata can decide whether this file is
 ## up-to-date.  Although since charprop depends on bootstrap-emacs,
diff --git a/src/xterm.c b/src/xterm.c
index 816b6dc5a8..a7116d9d95 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -4471,9 +4471,11 @@ x_scroll_run (struct window *w, struct run *run)
 					 view->y + view->clip_top,
 					 view->clip_right - view->clip_left,
 					 view->clip_bottom - view->clip_top);
-		      cairo_xlib_surface_set_size (view->cr_surface,
-						   view->clip_right - view->clip_left,
-						   view->clip_bottom - view->clip_top);
+
+		      if (XWIDGET_VIEW_GTK_P (view))
+			cairo_xlib_surface_set_size (view->cr_surface,
+						     view->clip_right - view->clip_left,
+						     view->clip_bottom - view->clip_top);
 		    }
 		  xwidget_expose (view);
 		  XFlush (dpy);
@@ -12940,6 +12942,14 @@ #define NUM_ARGV 10
         gtk_init (&argc, &argv2);
         request_sigio ();
 
+#ifdef HAVE_GSTREAMER
+	unrequest_sigio ();
+	/* gst_init might call XOpenDisplay, which fails if a signal
+	   is received.  */
+	gst_init (&argc, &argv2);
+	request_sigio ();
+#endif
+
         g_log_remove_handler ("GLib", id);
 
         xg_initialize ();
diff --git a/src/xwidget.c b/src/xwidget.c
index e1bf40ea43..ffed743412 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -40,6 +40,10 @@ Copyright (C) 2011-2021 Free Software Foundation, Inc.
 #include <JavaScriptCore/JavaScript.h>
 #include <cairo.h>
 #include <X11/Xlib.h>
+#ifdef HAVE_GSTREAMER
+#include <gst/video/videooverlay.h>
+#define XG_WINDOW_HANDLE "xg-window-handle"
+#endif
 #elif defined NS_IMPL_COCOA
 #include "nsxwidget.h"
 #endif
@@ -111,6 +115,12 @@ webkit_decide_policy_cb (WebKitWebView *,
 static void find_widget (GtkWidget *t, struct widget_search_data *);
 static void mouse_target_changed (WebKitWebView *, WebKitHitTestResult *, guint,
 				  gpointer);
+#ifdef HAVE_GSTREAMER
+static GstBusSyncReply gst_create_window (GstBus *, GstMessage *, gpointer);
+static gboolean gst_message_cb (GstBus *, GstMessage *, gpointer);
+static bool check_gstreamer_dependencies (void);
+static void unlink_gst_xwidget_view (struct xwidget_view *);
+#endif
 #endif
 
 
@@ -123,6 +133,7 @@ DEFUN ("make-xwidget",
 TYPE is a symbol which can take one of the following values:
 
 - webkit
+- media
 
 RELATED is nil, or an xwidget.  When constructing a WebKit widget, it
 will share the same settings and internal subprocess as RELATED.
@@ -140,9 +151,18 @@ DEFUN ("make-xwidget",
   CHECK_FIXNAT (width);
   CHECK_FIXNAT (height);
 
-  if (!EQ (type, Qwebkit))
+  if (!EQ (type, Qwebkit) && !EQ (type, Qmedia))
     error ("Bad xwidget type");
 
+#ifdef HAVE_GSTREAMER
+  if (EQ (type, Qmedia)
+      && !check_gstreamer_dependencies ())
+    error ("Your Emacs is missing run-time dependencies required for GStreamer support");
+#else
+  if (EQ (type, Qmedia))
+    error ("Your Emacs was not built with GStreamer support");
+#endif
+
   struct xwidget *xw = allocate_xwidget ();
   Lisp_Object val;
   xw->type = type;
@@ -180,103 +200,142 @@ DEFUN ("make-xwidget",
       gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
                          xw->height);
 
-      if (EQ (xw->type, Qwebkit))
-        {
-	  WebKitWebView *related_view;
+      xw->xg_p = true;
+      WebKitWebView *related_view;
+
+      if (NILP (related)
+	  || !XWIDGETP (related)
+	  || !EQ (XXWIDGET (related)->type, Qwebkit))
+	{
+	  xw->widget_osr = webkit_web_view_new ();
+
+	  webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr),
+				    "about:blank");
+	  /* webkitgtk uses GSubprocess which sets sigaction causing
+	     Emacs to not catch SIGCHLD with its usual handle setup in
+	     'catch_child_signal'.  This resets the SIGCHLD sigaction.  */
+	  catch_child_signal ();
+	}
+      else
+	{
+	  related_view = WEBKIT_WEB_VIEW (XXWIDGET (related)->widget_osr);
+	  xw->widget_osr = webkit_web_view_new_with_related_view (related_view);
+	}
+
+      /* Enable the developer extras.  */
+      settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr));
+      g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL);
+
+      if (xw->xg_p)
+	{
+	  gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
+				       xw->height);
 
-	  if (NILP (related)
-	      || !XWIDGETP (related)
-	      || !EQ (XXWIDGET (related)->type, Qwebkit))
+	  if (EQ (xw->type, Qwebkit))
 	    {
-	      xw->widget_osr = webkit_web_view_new ();
-
-	      webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr),
-					"about:blank");
-	      /* webkitgtk uses GSubprocess which sets sigaction causing
-		 Emacs to not catch SIGCHLD with its usual handle setup in
-		 'catch_child_signal'.  This resets the SIGCHLD sigaction.  */
-	      catch_child_signal ();
+	      gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
+				 GTK_WIDGET (WEBKIT_WEB_VIEW (xw->widget_osr)));
 	    }
 	  else
 	    {
-	      related_view = WEBKIT_WEB_VIEW (XXWIDGET (related)->widget_osr);
-	      xw->widget_osr = webkit_web_view_new_with_related_view (related_view);
+	      gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
+				 xw->widget_osr);
 	    }
 
-	  /* Enable the developer extras.  */
-	  settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr));
-	  g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL);
+	  gtk_widget_show (xw->widget_osr);
+	  gtk_widget_show (xw->widgetwindow_osr);
+	  synthesize_focus_in_event (xw->widgetwindow_osr);
+
+
+	  g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
+			    "from-embedder", G_CALLBACK (from_embedder), NULL);
+	  g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
+			    "to-embedder", G_CALLBACK (to_embedder), NULL);
+
+	  /* Store some xwidget data in the gtk widgets for convenient
+	     retrieval in the event handlers.  */
+	  g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET, xw);
+	  g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET, xw);
+
+	  /* signals */
+	  if (EQ (xw->type, Qwebkit))
+	    {
+	      g_signal_connect (G_OBJECT (xw->widget_osr),
+				"load-changed",
+				G_CALLBACK (webkit_view_load_changed_cb), xw);
+
+	      g_signal_connect (G_OBJECT (webkit_context),
+				"download-started",
+				G_CALLBACK (webkit_download_cb), xw);
+
+	      g_signal_connect (G_OBJECT (xw->widget_osr),
+				"decide-policy",
+				G_CALLBACK
+				(webkit_decide_policy_cb),
+				xw);
+
+	      g_signal_connect (G_OBJECT (xw->widget_osr),
+				"mouse-target-changed",
+				G_CALLBACK (mouse_target_changed),
+				xw);
+	      g_signal_connect (G_OBJECT (xw->widget_osr),
+				"create",
+				G_CALLBACK (webkit_create_cb),
+				xw);
+	      g_signal_connect (G_OBJECT (xw->widget_osr),
+				"script-dialog",
+				G_CALLBACK (webkit_script_dialog_cb),
+				NULL);
+	      g_signal_connect (G_OBJECT (xw->widget_osr),
+				"run-file-chooser",
+			    G_CALLBACK (run_file_chooser_cb),
+				NULL);
+	    }
+
+	  g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event",
+			    G_CALLBACK (offscreen_damage_event), xw);
 	}
 
-      gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
-                                   xw->height);
+      unblock_input ();
+    }
+#ifdef HAVE_GSTREAMER
+  else
+    {
+      xw->xg_p = false;
+      xw->gst_pipeline = gst_pipeline_new (NULL);
+      xw->gst_source = gst_element_factory_make ("videotestsrc", NULL);
+      xw->gst_tee = gst_element_factory_make ("tee", NULL);
 
-      if (EQ (xw->type, Qwebkit))
-        {
-          gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
-                             GTK_WIDGET (WEBKIT_WEB_VIEW (xw->widget_osr)));
-        }
-      else
-        {
-          gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
-                             xw->widget_osr);
-        }
+      GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (xw->gst_pipeline));
+      GstElement *fakesink = gst_element_factory_make ("fakesink", NULL);
+      GstElement *queue = gst_element_factory_make ("queue", NULL);
 
-      gtk_widget_show (xw->widget_osr);
-      gtk_widget_show (xw->widgetwindow_osr);
-      synthesize_focus_in_event (xw->widgetwindow_osr);
+      g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
 
+      gst_bus_set_sync_handler (bus, gst_create_window, xw->gst_pipeline, NULL);
+      gst_bus_add_signal_watch (bus);
+      g_signal_connect (G_OBJECT (bus), "message",
+			G_CALLBACK (gst_message_cb), xw->gst_pipeline);
 
-      g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
-			"from-embedder", G_CALLBACK (from_embedder), NULL);
-      g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
-			"to-embedder", G_CALLBACK (to_embedder), NULL);
+      xw->gst_fakesink = fakesink;
 
-      /* Store some xwidget data in the gtk widgets for convenient
-         retrieval in the event handlers.  */
-      g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET, xw);
-      g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET, xw);
+      gst_object_ref (xw->gst_pipeline);
+      gst_object_ref (xw->gst_source);
+      gst_object_ref (xw->gst_tee);
+      gst_object_ref (xw->gst_fakesink);
 
-      /* signals */
-      if (EQ (xw->type, Qwebkit))
-        {
-          g_signal_connect (G_OBJECT (xw->widget_osr),
-                            "load-changed",
-                            G_CALLBACK (webkit_view_load_changed_cb), xw);
-
-          g_signal_connect (G_OBJECT (webkit_context),
-                            "download-started",
-                            G_CALLBACK (webkit_download_cb), xw);
-
-          g_signal_connect (G_OBJECT (xw->widget_osr),
-                            "decide-policy",
-                            G_CALLBACK
-                            (webkit_decide_policy_cb),
-                            xw);
-
-	  g_signal_connect (G_OBJECT (xw->widget_osr),
-			    "mouse-target-changed",
-			    G_CALLBACK (mouse_target_changed),
-			    xw);
-	  g_signal_connect (G_OBJECT (xw->widget_osr),
-			    "create",
-			    G_CALLBACK (webkit_create_cb),
-			    xw);
-	  g_signal_connect (G_OBJECT (xw->widget_osr),
-			    "script-dialog",
-			    G_CALLBACK (webkit_script_dialog_cb),
-			    NULL);
-	  g_signal_connect (G_OBJECT (xw->widget_osr),
-			    "run-file-chooser",
-			    G_CALLBACK (run_file_chooser_cb),
-			    NULL);
-        }
+      gst_bin_add_many (GST_BIN (xw->gst_pipeline), xw->gst_source,
+			xw->gst_tee, queue, fakesink, NULL);
 
-      g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event",
-			G_CALLBACK (offscreen_damage_event), xw);
+      gst_element_link_many (xw->gst_tee, queue, fakesink, NULL);
 
-      unblock_input ();
+      if (!gst_element_link (xw->gst_source, xw->gst_tee))
+	emacs_abort ();
+
+      if (!gst_element_set_state (xw->gst_pipeline, GST_STATE_PAUSED))
+	emacs_abort ();
     }
+#endif
 #elif defined NS_IMPL_COCOA
   nsxwidget_init (xw);
 #endif
@@ -335,6 +394,9 @@ DEFUN ("xwidget-perform-lispy-event",
     f = SELECTED_FRAME ();
 
 #ifdef USE_GTK
+  if (!xw->xg_p)
+    return Qnil;
+
   widget = gtk_window_get_focus (GTK_WINDOW (xw->widgetwindow_osr));
 
   if (!widget)
@@ -888,7 +950,8 @@ xwidget_button (struct xwidget_view *view,
 		bool down_p, int x, int y, int button,
 		int modifier_state, Time time)
 {
-  if (NILP (XXWIDGET (view->model)->buffer))
+  if (NILP (XXWIDGET (view->model)->buffer)
+      || !XWIDGET_VIEW_GTK_P (view))
     return;
 
   record_osr_embedder (view);
@@ -947,7 +1010,7 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
   int y;
   GtkWidget *target;
 
-  if (NILP (model->buffer))
+  if (NILP (model->buffer) || !model->xg_p)
     return;
 
   xg_event = gdk_event_new (event->type == MotionNotify
@@ -1117,7 +1180,17 @@ xwidget_expose (struct xwidget_view *xv)
 {
   struct xwidget *xw = XXWIDGET (xv->model);
 
-  xv_do_draw (xv, xw);
+  if (xw->xg_p)
+    xv_do_draw (xv, xw);
+#ifdef HAVE_GSTREAMER
+  else if (EQ (xw->type, Qmedia) && XWIDGET_LIVE_P (xw))
+    {
+      if (xv->wdesc != None)
+	XMoveWindow (xv->dpy, xv->internal_window,
+		     -xv->clip_left, -xv->clip_top);
+      gst_video_overlay_expose (GST_VIDEO_OVERLAY (xv->video_sink));
+    }
+#endif
 }
 #endif /* USE_GTK */
 
@@ -1690,12 +1763,81 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
 				 CopyFromParent, CWEventMask, &a);
       XLowerWindow (xv->dpy, xv->wdesc);
       XDefineCursor (xv->dpy, xv->wdesc, xv->cursor);
-      xv->cr_surface = cairo_xlib_surface_create (xv->dpy,
-						  xv->wdesc,
-						  FRAME_DISPLAY_INFO (s->f)->visual,
-						  clip_right - clip_left,
-						  clip_bottom - clip_top);
-      xv->cr_context = cairo_create (xv->cr_surface);
+
+      if (XWIDGET_VIEW_GTK_P (xv))
+	{
+	  xv->cr_surface = cairo_xlib_surface_create (xv->dpy,
+						      xv->wdesc,
+						      FRAME_DISPLAY_INFO (s->f)->visual,
+						      clip_right - clip_left,
+						      clip_bottom - clip_top);
+	  xv->cr_context = cairo_create (xv->cr_surface);
+	}
+#ifdef HAVE_GSTREAMER
+      else
+	{
+	  XFlush (xv->dpy);
+
+	  if (EQ (xww->type, Qmedia) && XWIDGET_LIVE_P (xww))
+	    {
+	      GstPadTemplate *templ;
+	      GstPad *sinkpad;
+
+	      a.event_mask = ExposureMask;
+	      a.background_pixel = FRAME_BACKGROUND_PIXEL (xv->frame);
+
+	      xv->internal_window = XCreateWindow (xv->dpy, xv->wdesc,
+						   -clip_left, -clip_top,
+						   xww->width, xww->height,
+						   0, CopyFromParent, CopyFromParent,
+						   CopyFromParent,
+						   (CWEventMask | CWBackPixel), &a);
+
+	      XMapWindow (xv->dpy, xv->internal_window);
+	      XFlush (xv->dpy);
+
+	      Fputhash (make_fixnum (xv->internal_window), xvw, x_window_to_xwv_map);
+
+	      templ = gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (xww->gst_tee),
+							  "src_%u");
+
+	      xv->teepad = gst_element_request_pad (xww->gst_tee,
+						    templ, NULL, NULL);
+	      xv->video_sink = gst_element_factory_make ("xvimagesink", NULL);
+	      xv->video_queue = gst_element_factory_make ("queue", NULL);
+
+	      gst_object_ref (xv->video_queue);
+	      gst_object_ref (xv->video_sink);
+
+	      g_object_set_data (G_OBJECT (xv->video_sink), XG_WINDOW_HANDLE,
+				 (gpointer) xv->internal_window);
+	      g_object_set (G_OBJECT (xv->video_sink), "display",
+			    FRAME_TERMINAL (xv->frame)->name, NULL);
+
+	      gst_video_overlay_handle_events (GST_VIDEO_OVERLAY (xv->video_sink),
+					       FALSE);
+
+	      gst_bin_add_many (GST_BIN (xww->gst_pipeline), xv->video_queue,
+				xv->video_sink, NULL);
+
+	      if (!gst_element_link (xv->video_queue, xv->video_sink))
+		emacs_abort ();
+
+	      gst_element_sync_state_with_parent (xv->video_queue);
+	      gst_element_sync_state_with_parent (xv->video_sink);
+
+	      sinkpad = gst_element_get_static_pad (xv->video_queue, "sink");
+	      gst_pad_link (xv->teepad, sinkpad);
+	      gst_object_unref (sinkpad);
+
+	      xv->sinkpad = sinkpad;
+
+	      gst_element_sync_state_with_parent (xww->gst_tee);
+
+	      xwidget_expose (xv);
+	    }
+	}
+#endif
       Fputhash (make_fixnum (xv->wdesc), xvw, x_window_to_xwv_map);
 
       moved = false;
@@ -1709,8 +1851,9 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
       XMoveResizeWindow (xv->dpy, xv->wdesc, x + clip_left, y + clip_top,
 			 clip_right - clip_left, clip_bottom - clip_top);
       XFlush (xv->dpy);
-      cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
-				   clip_bottom - clip_top);
+      if (XWIDGET_VIEW_GTK_P (xv))
+	cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
+				     clip_bottom - clip_top);
 #elif defined NS_IMPL_COCOA
       nsxwidget_move_view (xv, x + clip_left, y + clip_top);
 #endif
@@ -1740,8 +1883,10 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
 			     clip_bottom - clip_top);
 	    }
 	  XFlush (xv->dpy);
-	  cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
-				       clip_bottom - clip_top);
+
+	  if (xww->xg_p)
+	    cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
+					 clip_bottom - clip_top);
 	}
 #elif defined NS_IMPL_COCOA
       nsxwidget_resize_view (xv, clip_right - clip_left,
@@ -1765,7 +1910,10 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
       if (!xwidget_hidden (xv))
 	{
 #ifdef USE_GTK
-	  gtk_widget_queue_draw (xww->widget_osr);
+	  if (xww->xg_p)
+	    gtk_widget_queue_draw (xww->widget_osr);
+	  else
+	    xwidget_expose (xv);
 #elif defined NS_IMPL_COCOA
 	  nsxwidget_set_needsdisplay (xv);
 #endif
@@ -1788,6 +1936,12 @@ #define CHECK_WEBKIT_WIDGET(xw)				\
   if (NILP (xw->buffer) || !EQ (xw->type, Qwebkit))	\
     error ("Not a WebKit widget")
 
+#ifdef HAVE_GSTREAMER
+#define CHECK_MEDIA_WIDGET(xw)				\
+  if (NILP (xw->buffer) || !EQ (xw->type, Qmedia))	\
+    error ("Not a WebKit widget")
+#endif
+
 /* Macro that checks xwidget hold webkit web view first.  */
 #define WEBKIT_FN_INIT()						\
   CHECK_LIVE_XWIDGET (xwidget);						\
@@ -1989,6 +2143,14 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
 #ifdef USE_GTK
 	      xv->just_resized = true;
 	      SET_FRAME_GARBAGED (xv->frame);
+#ifdef HAVE_GSTREAMER
+	      if (EQ (xw->type, Qmedia))
+		{
+		  XResizeWindow (xv->dpy, xv->internal_window,
+				 xw->width, xw->height);
+		}
+#endif
+
 #else
 	      wset_redisplay (XWINDOW (xv->w));
 #endif
@@ -2000,7 +2162,7 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
 
   /* If there is an offscreen widget resize it first.  */
 #ifdef USE_GTK
-  if (xw->widget_osr)
+  if (xw->xg_p && xw->widget_osr)
     {
       gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
                          xw->height);
@@ -2030,9 +2192,14 @@ DEFUN ("xwidget-size-request",
 {
   CHECK_LIVE_XWIDGET (xwidget);
 #ifdef USE_GTK
-  GtkRequisition requisition;
-  gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition);
-  return list2i (requisition.width, requisition.height);
+  if (XXWIDGET (xwidget)->xg_p)
+    {
+      GtkRequisition requisition;
+      gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition);
+      return list2i (requisition.width, requisition.height);
+    }
+
+  return Qnil;
 #elif defined NS_IMPL_COCOA
   return nsxwidget_get_size (XXWIDGET (xwidget));
 #endif
@@ -2115,18 +2282,29 @@ DEFUN ("delete-xwidget-view",
 #ifdef USE_GTK
   struct xwidget *xw = XXWIDGET (xv->model);
   GdkWindow *w;
-
+#ifdef HAVE_GSTREAMER
+  block_input ();
+  if (XWIDGET_LIVE_P (xw) && EQ (xw->type, Qmedia))
+    unlink_gst_xwidget_view (xv);
+  unblock_input ();
+#endif
   if (xv->wdesc != None)
     {
       block_input ();
-      cairo_destroy (xv->cr_context);
-      cairo_surface_destroy (xv->cr_surface);
+      if (XWIDGET_VIEW_GTK_P (xv))
+	{
+	  cairo_destroy (xv->cr_context);
+	  cairo_surface_destroy (xv->cr_surface);
+	}
       XDestroyWindow (xv->dpy, xv->wdesc);
       Fremhash (make_fixnum (xv->wdesc), x_window_to_xwv_map);
+
+      if (XWIDGET_LIVE_P (xw) && EQ (xw->type, Qmedia))
+	Fremhash (make_fixnum (xv->internal_window), x_window_to_xwv_map);
       unblock_input ();
     }
 
-  if (xw->embedder_view == xv && !NILP (xw->buffer))
+  if (xw->xg_p && xw->embedder_view == xv && !NILP (xw->buffer))
     {
       w = gtk_widget_get_window (xw->widgetwindow_osr);
 
@@ -2555,6 +2733,77 @@ DEFUN ("xwidget-webkit-back-forward-list", Fxwidget_webkit_back_forward_list,
 
   return list3 (back, here, forward);
 }
+
+#ifdef HAVE_GSTREAMER
+DEFUN ("xwidget-media-pause", Fxwidget_media_pause, Sxwidget_media_pause,
+       1, 1, 0, doc: /* Pause specified media XWIDGET.
+This causes playback to stop until you resume it using
+`xwidget-media-play'.  */)
+  (Lisp_Object xwidget)
+{
+  struct xwidget *xw;
+  struct xwidget_view *xv;
+  Lisp_Object tem;
+
+  CHECK_LIVE_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+  CHECK_MEDIA_WIDGET (xw);
+
+  block_input ();
+  gst_element_set_state (xw->gst_pipeline, GST_STATE_PAUSED);
+  gst_element_sync_state_with_parent (xw->gst_tee);
+  gst_element_sync_state_with_parent (xw->gst_fakesink);
+
+  for (tem = internal_xwidget_view_list; CONSP (tem); tem = XCDR (tem))
+    {
+      xv = XXWIDGET_VIEW (XCAR (tem));
+
+      if (EQ (xv->model, xwidget))
+	{
+	  gst_element_sync_state_with_parent (xv->video_queue);
+	  gst_element_sync_state_with_parent (xv->video_sink);
+	}
+    }
+
+  unblock_input ();
+
+  return Qnil;
+}
+
+DEFUN ("xwidget-media-play", Fxwidget_media_play, Sxwidget_media_play,
+       1, 1, 0, doc: /* Resume playback of specified media XWIDGET.  */)
+  (Lisp_Object xwidget)
+{
+  struct xwidget *xw;
+  struct xwidget_view *xv;
+  Lisp_Object tem;
+
+  CHECK_LIVE_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+  CHECK_MEDIA_WIDGET (xw);
+
+  block_input ();
+  gst_element_set_state (xw->gst_pipeline, GST_STATE_PLAYING);
+  gst_element_sync_state_with_parent (xw->gst_tee);
+  gst_element_sync_state_with_parent (xw->gst_fakesink);
+
+  for (tem = internal_xwidget_view_list; CONSP (tem); tem = XCDR (tem))
+    {
+      xv = XXWIDGET_VIEW (XCAR (tem));
+
+      if (EQ (xv->model, xwidget))
+	{
+	  gst_element_sync_state_with_parent (xv->video_queue);
+	  gst_element_sync_state_with_parent (xv->video_sink);
+	}
+    }
+
+  gst_element_sync_state_with_parent (xw->gst_tee);
+  unblock_input ();
+
+  return Qnil;
+}
+#endif
 #endif
 
 void
@@ -2584,6 +2833,7 @@ syms_of_xwidget (void)
   defsubr (&Sxwidget_webkit_zoom);
   defsubr (&Sxwidget_webkit_execute_script);
   DEFSYM (Qwebkit, "webkit");
+  DEFSYM (Qmedia, "media");
 
   defsubr (&Sxwidget_size_request);
   defsubr (&Sdelete_xwidget_view);
@@ -2600,6 +2850,10 @@ syms_of_xwidget (void)
 #ifdef USE_GTK
   defsubr (&Sxwidget_webkit_load_html);
   defsubr (&Sxwidget_webkit_back_forward_list);
+#ifdef HAVE_GSTREAMER
+  defsubr (&Sxwidget_media_pause);
+  defsubr (&Sxwidget_media_play);
+#endif
 #endif
   defsubr (&Skill_xwidget);
 
@@ -2862,7 +3116,7 @@ kill_xwidget (struct xwidget *xw)
 #ifdef USE_GTK
   xw->buffer = Qnil;
 
-  if (xw->widget_osr && xw->widgetwindow_osr)
+  if (xw->xg_p && xw->widget_osr && xw->widgetwindow_osr)
     {
       gtk_widget_destroy (xw->widget_osr);
       gtk_widget_destroy (xw->widgetwindow_osr);
@@ -2882,6 +3136,26 @@ kill_xwidget (struct xwidget *xw)
 	}
     }
 
+#ifdef HAVE_GSTREAMER
+  Lisp_Object tem;
+
+  if (EQ (xw->type, Qmedia))
+    {
+      for (tem = internal_xwidget_view_list; CONSP (tem);
+	   tem = XCDR (tem))
+	{
+	  struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tem));
+
+	  if (XXWIDGET (xv->model) == xw)
+	    unlink_gst_xwidget_view (xv);
+	}
+      gst_object_unref (xw->gst_tee);
+      gst_object_unref (xw->gst_pipeline);
+      gst_object_unref (xw->gst_source);
+      gst_object_unref (xw->gst_fakesink);
+    }
+#endif
+
   xw->widget_osr = NULL;
   xw->widgetwindow_osr = NULL;
   xw->find_text = NULL;
@@ -2908,3 +3182,59 @@ kill_buffer_xwidgets (Lisp_Object buffer)
       }
     }
 }
+
+#ifdef HAVE_GSTREAMER
+static GstBusSyncReply
+gst_create_window (GstBus *bus, GstMessage *msg, gpointer user_data)
+{
+  GstObject *elm;
+  Window wdesc;
+
+  if (!gst_is_video_overlay_prepare_window_handle_message (msg))
+    return GST_BUS_PASS;
+
+  elm = GST_MESSAGE_SRC (msg);
+  wdesc = (Window) g_object_get_data (G_OBJECT (elm), XG_WINDOW_HANDLE);
+
+  gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (elm), wdesc);
+
+  return GST_BUS_DROP;
+}
+
+static gboolean
+gst_message_cb (GstBus *bus, GstMessage *message, gpointer user_data)
+{
+  return TRUE;
+}
+
+static bool
+check_gstreamer_dependencies (void)
+{
+  GstRegistry *registry = gst_registry_get ();
+
+  return (gst_registry_find_feature (registry, "xvimagesink",
+				     GST_TYPE_ELEMENT_FACTORY)
+	  && gst_registry_find_feature (registry, "queue",
+					GST_TYPE_ELEMENT_FACTORY)
+	  && gst_registry_find_feature (registry, "videotestsrc",
+					GST_TYPE_ELEMENT_FACTORY)
+	  && gst_registry_find_feature (registry, "tee",
+					GST_TYPE_ELEMENT_FACTORY));
+}
+
+static void
+unlink_gst_xwidget_view (struct xwidget_view *xv)
+{
+  struct xwidget *xw = XXWIDGET (xv->model);
+
+  gst_pad_unlink (xv->teepad, xv->sinkpad);
+  gst_element_unlink (xv->video_queue, xv->video_sink);
+
+  gst_element_set_state (xv->video_queue, GST_STATE_NULL);
+  gst_element_set_state (xv->video_sink, GST_STATE_NULL);
+  gst_bin_remove_many (GST_BIN (xw->gst_pipeline), xv->video_sink,
+		       xv->video_queue, NULL);
+  gst_object_unref (xv->video_sink);
+  gst_object_unref (xv->video_queue);
+}
+#endif
diff --git a/src/xwidget.h b/src/xwidget.h
index 78fe865dd8..66f7fb2c4c 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -39,6 +39,10 @@ #define XWIDGET_H_INCLUDED
 #import "nsxwidget.h"
 #endif
 
+#ifdef HAVE_GSTREAMER
+#include <gst/gst.h>
+#endif
+
 struct xwidget
 {
   union vectorlike_header header;
@@ -65,6 +69,16 @@ #define XWIDGET_H_INCLUDED
   char *find_text;
 
 #if defined (USE_GTK)
+  /* Whether or not the widget is used to display GTK widgets. */
+  bool xg_p;
+
+#ifdef HAVE_GSTREAMER
+  GstElement *gst_tee;
+  GstElement *gst_pipeline;
+  GstElement *gst_source;
+  GstElement *gst_fakesink;
+#endif
+
   /* For offscreen widgets, unused if not osr.  */
   GtkWidget *widget_osr;
   GtkWidget *widgetwindow_osr;
@@ -112,6 +126,14 @@ #define XWIDGET_H_INCLUDED
   Emacs_Cursor cursor;
   struct frame *frame;
 
+#ifdef HAVE_GSTREAMER
+  Window internal_window;
+  GstPad *teepad;
+  GstPad *sinkpad;
+  GstElement *video_sink;
+  GstElement *video_queue;
+#endif
+
   cairo_surface_t *cr_surface;
   cairo_t *cr_context;
   int just_resized;
@@ -159,6 +181,9 @@ #define XXWIDGET_VIEW(a) (eassert (XWIDGET_VIEW_P (a)), \
 #define CHECK_XWIDGET_VIEW(x) \
   CHECK_TYPE (XWIDGET_VIEW_P (x), Qxwidget_view_p, x)
 
+#define XWIDGET_VIEW_GTK_P(x) \
+  XXWIDGET ((x)->model)->xg_p
+
 #define XG_XWIDGET "emacs_xwidget"
 #define XG_XWIDGET_VIEW "emacs_xwidget_view"
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-19  2:51 ` GStreamer xwidget Po Lu
@ 2021-11-19  4:01   ` T.V Raman
  2021-11-19  4:21     ` Po Lu
  2021-11-19  5:38   ` Lars Ingebrigtsen
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 70+ messages in thread
From: T.V Raman @ 2021-11-19  4:01 UTC (permalink / raw)
  To: Po Lu; +Cc: emacs-devel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=gb18030, Size: 579 bytes --]


So this takes away the primary reason why one spends all one's time in
emacs; it's because all information in Emacs is manipulable as text and
more importantly as structured information with a bit of work, eg
specialized modes.

This GStreamer widget that displays text takes Emacs down the deep dark
rathole of "What You See Is All You Have" world down which many tools
have gone, never to return.

I sincerely hope Emacs doesn't go down that rathole  as well.

-- 

Thanks,

--Raman(I Search, I Find, I Misplace, I Research)
7©4 Id: kg:/m/0285kf1  •0Ü8



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-19  4:01   ` T.V Raman
@ 2021-11-19  4:21     ` Po Lu
  0 siblings, 0 replies; 70+ messages in thread
From: Po Lu @ 2021-11-19  4:21 UTC (permalink / raw)
  To: T.V Raman; +Cc: emacs-devel

"T.V Raman" <raman@google.com> writes:

> So this takes away the primary reason why one spends all one's time in
> emacs; it's because all information in Emacs is manipulable as text and
> more importantly as structured information with a bit of work, eg
> specialized modes.

The GStreamer widget doesn't display text, it only displays media.  Just
as we support displaying images and such inside buffers.

If eventually it gains support for subtitles, then they will be sent to
Lisp code as an xwidget event, and not displayed on top of the widget.

So please explain why you think this is different from an image spec,
and more specifically an animated image.

> I sincerely hope Emacs doesn't go down that rathole  as well.

It's not a rathole.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-19  2:51 ` GStreamer xwidget Po Lu
  2021-11-19  4:01   ` T.V Raman
@ 2021-11-19  5:38   ` Lars Ingebrigtsen
  2021-11-19  5:49     ` Po Lu
  2021-11-20  5:07   ` Po Lu
  2021-11-20  7:42   ` Richard Stallman
  3 siblings, 1 reply; 70+ messages in thread
From: Lars Ingebrigtsen @ 2021-11-19  5:38 UTC (permalink / raw)
  To: Po Lu; +Cc: emacs-devel

Po Lu <luangruo@yahoo.com> writes:

> Right now, it can only display a test pattern, but getting that to work
> and perform decently was a challenge (for instance, offscreen rendering
> is not an option,

Hm...  isn't the webkit rendering done offscreen?  And that's able to
play videos just fine?

> instead the pipeline is dynamically built based on
> available xwidget views, utilizing hardware acceleration and video
> decoding if available).
>
> WDYT?

Sounds good to me.

Do you have a code snippet that will display one of these widgets?  Then
I can test the patch here.

Skimming the patch, it looks good to me.  The one extremely minor nit I
have is this superfluous {}:

> +#ifdef HAVE_GSTREAMER
> +	      if (EQ (xw->type, Qmedia))
> +		{
> +		  XResizeWindow (xv->dpy, xv->internal_window,
> +				 xw->width, xw->height);
> +		}

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-19  5:38   ` Lars Ingebrigtsen
@ 2021-11-19  5:49     ` Po Lu
  2021-11-19  6:19       ` Lars Ingebrigtsen
  0 siblings, 1 reply; 70+ messages in thread
From: Po Lu @ 2021-11-19  5:49 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: emacs-devel

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Hm...  isn't the webkit rendering done offscreen?  And that's able to
> play videos just fine?

Not on macOS, which is presumably where you tested the video playback,
where a single xwidget can be displayed by only one Emacs window at a
time.  On GNU systems, the offscreen rendering causes some video
playback to consume large amounts of CPU (as it can't utilize hardware
acceleration for video decoding).

And the more immediate problem this tries to solve is video playback not
working at all in most newer versions of WebKitGTK.

> Sounds good to me.
>
> Do you have a code snippet that will display one of these widgets?  Then
> I can test the patch here.

Try this:

  (require 'xwidget)

  (setq xw (make-xwidget 'media "foo" 100 100))
  (insert (propertize "foo" 'display (list 'xwidget :xwidget xw)))
  (xwidget-media-play xw)

> Skimming the patch, it looks good to me.  The one extremely minor nit I
> have is this superfluous {}:

>> +#ifdef HAVE_GSTREAMER
>> +	      if (EQ (xw->type, Qmedia))
>> +		{
>> +		  XResizeWindow (xv->dpy, xv->internal_window,
>> +				 xw->width, xw->height);
>> +		}

It would be ugly to wrap the arguments to call there, and still rely on
implicit braces.  IMO.

But if that's really a problem, I can remove it.

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-19  5:49     ` Po Lu
@ 2021-11-19  6:19       ` Lars Ingebrigtsen
  2021-11-19  6:37         ` Po Lu
  0 siblings, 1 reply; 70+ messages in thread
From: Lars Ingebrigtsen @ 2021-11-19  6:19 UTC (permalink / raw)
  To: Po Lu; +Cc: emacs-devel

Po Lu <luangruo@yahoo.com> writes:

> Not on macOS, which is presumably where you tested the video playback,
> where a single xwidget can be displayed by only one Emacs window at a
> time.  On GNU systems, the offscreen rendering causes some video
> playback to consume large amounts of CPU (as it can't utilize hardware
> acceleration for video decoding).

Ah, I see.

> Try this:
>
>   (require 'xwidget)
>
>   (setq xw (make-xwidget 'media "foo" 100 100))
>   (insert (propertize "foo" 'display (list 'xwidget :xwidget xw)))
>   (xwidget-media-play xw)

Thanks.  But I get the following build error:

xwidget.c: In function 'Fdelete_xwidget_view':
xwidget.c:2303:34: error: 'struct xwidget_view' has no member named 'internal_window'
 2303 |         Fremhash (make_fixnum (xv->internal_window), x_window_to_xwv_map);
      |                                  ^~
  make[1]: *** [Makefile:393: xwidget.o] Error  1


-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-19  6:19       ` Lars Ingebrigtsen
@ 2021-11-19  6:37         ` Po Lu
  2021-11-19  6:53           ` Lars Ingebrigtsen
  2021-11-19 13:03           ` Eli Zaretskii
  0 siblings, 2 replies; 70+ messages in thread
From: Po Lu @ 2021-11-19  6:37 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 434 bytes --]

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Thanks.  But I get the following build error:
>
> xwidget.c: In function 'Fdelete_xwidget_view':
> xwidget.c:2303:34: error: 'struct xwidget_view' has no member named 'internal_window'
>  2303 |         Fremhash (make_fixnum (xv->internal_window), x_window_to_xwv_map);
>       |                                  ^~
>   make[1]: *** [Makefile:393: xwidget.o] Error  1

Try this instead:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Implement-a-media-xwidget-based-on-GStreamer.patch --]
[-- Type: text/x-patch, Size: 31924 bytes --]

From 310c856151e01f4c82a185eaa56314d15b1e706c Mon Sep 17 00:00:00 2001
From: Po Lu <luangruo@yahoo.com>
Date: Thu, 18 Nov 2021 18:10:45 +0800
Subject: [PATCH] Implement a media xwidget based on GStreamer

* configure.ac: Add option to use GStreamer for media playback.
* doc/lispref/display.texi (Xwidgets): Document new functions
and xwidget type.

* src/Makefile.in (EMACS_CFLAGS): Add GStreamer cflags.
(LIBES): Add GStreamer linker options.

* etc/NEWS: Announce `media' xwidget.
* etc/xterm.c (x_scroll_run): Don't resize cairo surface
if not a GTK xwidget.
(x_term_init): Initialize GStreamer.

* src/xwidget.c (gst_create_window)
(gst_message_cb, unlink_gst_xwidget_view)
(check_gstreamer_dependencies): New functions.

(Fmake_xwidget): Add support for media xwidgets.
(Fxwidget_perform_lispy_event): Return nil if it doesn't make
sense to perform an event.
(Fxwidget_resize): Add support for media widgets.
(xwidget_button, xwidget_motion_or_crossing): Handle non-GTK
xwidgets.
(xwidget_expose): Handle media xwidgets.
(x_draw_xwidget_glyph_string): Set up GStreamer widgets if
appropriate.
(Fxwidget_size_request): Return nil on widgets that can't
have a size request.
(Fdelete_xwidget_view): Clean up after GStreamer.
(Fxwidget_media_pause, Fxwidget_media_play): New functions.

(syms_of_xwidget): New symbols and subrs.
(kill_xwidget): Clean up after GStreamer.

* src/xwidget.h (struct xwidget, struct xwidget_view): Add
GStreamer specific fields for media xwidgets.
(XWIDGET_VIEW_GTK_P): New macro.
---
 configure.ac             |  13 +
 doc/lispref/display.texi |  12 +
 etc/NEWS                 |   7 +
 src/Makefile.in          |   7 +-
 src/xterm.c              |  16 +-
 src/xwidget.c            | 537 +++++++++++++++++++++++++++++++--------
 src/xwidget.h            |  25 ++
 7 files changed, 509 insertions(+), 108 deletions(-)

diff --git a/configure.ac b/configure.ac
index c231c2ceae..ae3f28f8db 100644
--- a/configure.ac
+++ b/configure.ac
@@ -485,6 +485,7 @@ AC_DEFUN
 OPTION_DEFAULT_ON([zlib],[don't compile with zlib decompression support])
 OPTION_DEFAULT_ON([modules],[don't compile with dynamic modules support])
 OPTION_DEFAULT_ON([threads],[don't compile with elisp threading support])
+OPTION_DEFAULT_OFF([gstreamer],[compile with xwidget video playback support using GStreamer])
 OPTION_DEFAULT_OFF([native-compilation],[compile with Emacs Lisp native compiler support])
 OPTION_DEFAULT_OFF([cygwin32-native-compilation],[use native compilation on 32-bit Cygwin])
 
@@ -2834,6 +2835,18 @@ AC_DEFUN
 fi
 AC_SUBST(XWIDGETS_OBJ)
 
+HAVE_GSTREAMER=no
+if test "$with_gstreamer" != "no" && test "${HAVE_X_WINDOWS}" = "yes" \
+   && test "${HAVE_XWIDGETS}" = "yes"; then
+  EMACS_CHECK_MODULES([GSTREAMER], "gstreamer-1.0 gstreamer-video-1.0")
+  if test "$HAVE_GSTREAMER" = "yes"; then
+    AC_DEFINE(HAVE_GSTREAMER, 1, [Define to 1 if using GStreamer for video support in xwidgets.])
+  fi
+fi
+
+AC_SUBST(GSTREAMER_CFLAGS)
+AC_SUBST(GSTREAMER_LIBS)
+
 CFLAGS=$OLD_CFLAGS
 LIBS=$OLD_LIBS
 
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 8decff6fa8..c35d63f848 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -6797,6 +6797,8 @@ Xwidgets
 @table @code
 @item webkit
 The WebKit component.
+@item media
+A media widget that allows to display videos inside Emacs buffers.
 @end table
 
 The @var{width} and @var{height} arguments specify the widget size in
@@ -7004,6 +7006,16 @@ Xwidgets
 be passed as an index to @code{xwidget-webkit-goto-history}.
 @end defun
 
+@defun xwidget-media-pause xwidget
+Suspend playback of @var{xwidget}, a media xwidget.  You can later
+resume playback using @code{xwidget-media-play}.
+@end defun
+
+@defun xwidget-media-pause xwidget
+Start or resume playback of @var{xwidget}, a media xwidget.  You can
+later pause playback using @code{xwidget-media-pause}.
+@end defun
+
 @node Buttons
 @section Buttons
 @cindex buttons in buffers
diff --git a/etc/NEWS b/etc/NEWS
index cee2844be3..8cb5495b4e 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -488,6 +488,13 @@ This is a convenience function to extract the field data from
 
 ** Xwidgets
 
++++
+*** New xwidget type 'media'.
+This xwidget type allows to display video content inside Emacs buffers.
+You must have the GStreamer library installed, along with the plugins
+"xvimagesink", "queue", "videotestsrc" and "tee", and Emacs must be
+built with '--with-gstreamer'.
+
 ---
 *** New user option 'xwidget-webkit-buffer-name-format'.
 Using this option you can control how the xwidget-webkit buffers are
diff --git a/src/Makefile.in b/src/Makefile.in
index 4c5535f8ad..646392c051 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -333,6 +333,9 @@ LIBGMP =
 LIBGCCJIT_LIBS = @LIBGCCJIT_LIBS@
 LIBGCCJIT_CFLAGS = @LIBGCCJIT_CFLAGS@
 
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+
 ## dynlib.o if necessary, else empty
 DYNLIB_OBJ = @DYNLIB_OBJ@
 
@@ -377,7 +380,7 @@ EMACS_CFLAGS=
   $(WEBKIT_CFLAGS) $(WEBP_CFLAGS) $(LCMS2_CFLAGS) \
   $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
   $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
-  $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \
+  $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) $(GSTREAMER_CFLAGS) \
   $(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \
   $(WERROR_CFLAGS)
 ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS)
@@ -524,7 +527,7 @@ LIBES =
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
    $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \
    $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \
-   $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS)
+   $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS) $(GSTREAMER_LIBS)
 
 ## FORCE it so that admin/unidata can decide whether this file is
 ## up-to-date.  Although since charprop depends on bootstrap-emacs,
diff --git a/src/xterm.c b/src/xterm.c
index 816b6dc5a8..a7116d9d95 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -4471,9 +4471,11 @@ x_scroll_run (struct window *w, struct run *run)
 					 view->y + view->clip_top,
 					 view->clip_right - view->clip_left,
 					 view->clip_bottom - view->clip_top);
-		      cairo_xlib_surface_set_size (view->cr_surface,
-						   view->clip_right - view->clip_left,
-						   view->clip_bottom - view->clip_top);
+
+		      if (XWIDGET_VIEW_GTK_P (view))
+			cairo_xlib_surface_set_size (view->cr_surface,
+						     view->clip_right - view->clip_left,
+						     view->clip_bottom - view->clip_top);
 		    }
 		  xwidget_expose (view);
 		  XFlush (dpy);
@@ -12940,6 +12942,14 @@ #define NUM_ARGV 10
         gtk_init (&argc, &argv2);
         request_sigio ();
 
+#ifdef HAVE_GSTREAMER
+	unrequest_sigio ();
+	/* gst_init might call XOpenDisplay, which fails if a signal
+	   is received.  */
+	gst_init (&argc, &argv2);
+	request_sigio ();
+#endif
+
         g_log_remove_handler ("GLib", id);
 
         xg_initialize ();
diff --git a/src/xwidget.c b/src/xwidget.c
index e1bf40ea43..fa460347a6 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -40,6 +40,10 @@ Copyright (C) 2011-2021 Free Software Foundation, Inc.
 #include <JavaScriptCore/JavaScript.h>
 #include <cairo.h>
 #include <X11/Xlib.h>
+#ifdef HAVE_GSTREAMER
+#include <gst/video/videooverlay.h>
+#define XG_WINDOW_HANDLE "xg-window-handle"
+#endif
 #elif defined NS_IMPL_COCOA
 #include "nsxwidget.h"
 #endif
@@ -111,6 +115,12 @@ webkit_decide_policy_cb (WebKitWebView *,
 static void find_widget (GtkWidget *t, struct widget_search_data *);
 static void mouse_target_changed (WebKitWebView *, WebKitHitTestResult *, guint,
 				  gpointer);
+#ifdef HAVE_GSTREAMER
+static GstBusSyncReply gst_create_window (GstBus *, GstMessage *, gpointer);
+static gboolean gst_message_cb (GstBus *, GstMessage *, gpointer);
+static bool check_gstreamer_dependencies (void);
+static void unlink_gst_xwidget_view (struct xwidget_view *);
+#endif
 #endif
 
 
@@ -123,6 +133,7 @@ DEFUN ("make-xwidget",
 TYPE is a symbol which can take one of the following values:
 
 - webkit
+- media
 
 RELATED is nil, or an xwidget.  When constructing a WebKit widget, it
 will share the same settings and internal subprocess as RELATED.
@@ -140,9 +151,18 @@ DEFUN ("make-xwidget",
   CHECK_FIXNAT (width);
   CHECK_FIXNAT (height);
 
-  if (!EQ (type, Qwebkit))
+  if (!EQ (type, Qwebkit) && !EQ (type, Qmedia))
     error ("Bad xwidget type");
 
+#ifdef HAVE_GSTREAMER
+  if (EQ (type, Qmedia)
+      && !check_gstreamer_dependencies ())
+    error ("Your Emacs is missing run-time dependencies required for GStreamer support");
+#else
+  if (EQ (type, Qmedia))
+    error ("Your Emacs was not built with GStreamer support");
+#endif
+
   struct xwidget *xw = allocate_xwidget ();
   Lisp_Object val;
   xw->type = type;
@@ -180,103 +200,142 @@ DEFUN ("make-xwidget",
       gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
                          xw->height);
 
-      if (EQ (xw->type, Qwebkit))
-        {
-	  WebKitWebView *related_view;
+      xw->xg_p = true;
+      WebKitWebView *related_view;
+
+      if (NILP (related)
+	  || !XWIDGETP (related)
+	  || !EQ (XXWIDGET (related)->type, Qwebkit))
+	{
+	  xw->widget_osr = webkit_web_view_new ();
+
+	  webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr),
+				    "about:blank");
+	  /* webkitgtk uses GSubprocess which sets sigaction causing
+	     Emacs to not catch SIGCHLD with its usual handle setup in
+	     'catch_child_signal'.  This resets the SIGCHLD sigaction.  */
+	  catch_child_signal ();
+	}
+      else
+	{
+	  related_view = WEBKIT_WEB_VIEW (XXWIDGET (related)->widget_osr);
+	  xw->widget_osr = webkit_web_view_new_with_related_view (related_view);
+	}
+
+      /* Enable the developer extras.  */
+      settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr));
+      g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL);
+
+      if (xw->xg_p)
+	{
+	  gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
+				       xw->height);
 
-	  if (NILP (related)
-	      || !XWIDGETP (related)
-	      || !EQ (XXWIDGET (related)->type, Qwebkit))
+	  if (EQ (xw->type, Qwebkit))
 	    {
-	      xw->widget_osr = webkit_web_view_new ();
-
-	      webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr),
-					"about:blank");
-	      /* webkitgtk uses GSubprocess which sets sigaction causing
-		 Emacs to not catch SIGCHLD with its usual handle setup in
-		 'catch_child_signal'.  This resets the SIGCHLD sigaction.  */
-	      catch_child_signal ();
+	      gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
+				 GTK_WIDGET (WEBKIT_WEB_VIEW (xw->widget_osr)));
 	    }
 	  else
 	    {
-	      related_view = WEBKIT_WEB_VIEW (XXWIDGET (related)->widget_osr);
-	      xw->widget_osr = webkit_web_view_new_with_related_view (related_view);
+	      gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
+				 xw->widget_osr);
 	    }
 
-	  /* Enable the developer extras.  */
-	  settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr));
-	  g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL);
+	  gtk_widget_show (xw->widget_osr);
+	  gtk_widget_show (xw->widgetwindow_osr);
+	  synthesize_focus_in_event (xw->widgetwindow_osr);
+
+
+	  g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
+			    "from-embedder", G_CALLBACK (from_embedder), NULL);
+	  g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
+			    "to-embedder", G_CALLBACK (to_embedder), NULL);
+
+	  /* Store some xwidget data in the gtk widgets for convenient
+	     retrieval in the event handlers.  */
+	  g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET, xw);
+	  g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET, xw);
+
+	  /* signals */
+	  if (EQ (xw->type, Qwebkit))
+	    {
+	      g_signal_connect (G_OBJECT (xw->widget_osr),
+				"load-changed",
+				G_CALLBACK (webkit_view_load_changed_cb), xw);
+
+	      g_signal_connect (G_OBJECT (webkit_context),
+				"download-started",
+				G_CALLBACK (webkit_download_cb), xw);
+
+	      g_signal_connect (G_OBJECT (xw->widget_osr),
+				"decide-policy",
+				G_CALLBACK
+				(webkit_decide_policy_cb),
+				xw);
+
+	      g_signal_connect (G_OBJECT (xw->widget_osr),
+				"mouse-target-changed",
+				G_CALLBACK (mouse_target_changed),
+				xw);
+	      g_signal_connect (G_OBJECT (xw->widget_osr),
+				"create",
+				G_CALLBACK (webkit_create_cb),
+				xw);
+	      g_signal_connect (G_OBJECT (xw->widget_osr),
+				"script-dialog",
+				G_CALLBACK (webkit_script_dialog_cb),
+				NULL);
+	      g_signal_connect (G_OBJECT (xw->widget_osr),
+				"run-file-chooser",
+			    G_CALLBACK (run_file_chooser_cb),
+				NULL);
+	    }
+
+	  g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event",
+			    G_CALLBACK (offscreen_damage_event), xw);
 	}
 
-      gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
-                                   xw->height);
+      unblock_input ();
+    }
+#ifdef HAVE_GSTREAMER
+  else
+    {
+      xw->xg_p = false;
+      xw->gst_pipeline = gst_pipeline_new (NULL);
+      xw->gst_source = gst_element_factory_make ("videotestsrc", NULL);
+      xw->gst_tee = gst_element_factory_make ("tee", NULL);
 
-      if (EQ (xw->type, Qwebkit))
-        {
-          gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
-                             GTK_WIDGET (WEBKIT_WEB_VIEW (xw->widget_osr)));
-        }
-      else
-        {
-          gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
-                             xw->widget_osr);
-        }
+      GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (xw->gst_pipeline));
+      GstElement *fakesink = gst_element_factory_make ("fakesink", NULL);
+      GstElement *queue = gst_element_factory_make ("queue", NULL);
 
-      gtk_widget_show (xw->widget_osr);
-      gtk_widget_show (xw->widgetwindow_osr);
-      synthesize_focus_in_event (xw->widgetwindow_osr);
+      g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
 
+      gst_bus_set_sync_handler (bus, gst_create_window, xw->gst_pipeline, NULL);
+      gst_bus_add_signal_watch (bus);
+      g_signal_connect (G_OBJECT (bus), "message",
+			G_CALLBACK (gst_message_cb), xw->gst_pipeline);
 
-      g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
-			"from-embedder", G_CALLBACK (from_embedder), NULL);
-      g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
-			"to-embedder", G_CALLBACK (to_embedder), NULL);
+      xw->gst_fakesink = fakesink;
 
-      /* Store some xwidget data in the gtk widgets for convenient
-         retrieval in the event handlers.  */
-      g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET, xw);
-      g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET, xw);
+      gst_object_ref (xw->gst_pipeline);
+      gst_object_ref (xw->gst_source);
+      gst_object_ref (xw->gst_tee);
+      gst_object_ref (xw->gst_fakesink);
 
-      /* signals */
-      if (EQ (xw->type, Qwebkit))
-        {
-          g_signal_connect (G_OBJECT (xw->widget_osr),
-                            "load-changed",
-                            G_CALLBACK (webkit_view_load_changed_cb), xw);
-
-          g_signal_connect (G_OBJECT (webkit_context),
-                            "download-started",
-                            G_CALLBACK (webkit_download_cb), xw);
-
-          g_signal_connect (G_OBJECT (xw->widget_osr),
-                            "decide-policy",
-                            G_CALLBACK
-                            (webkit_decide_policy_cb),
-                            xw);
-
-	  g_signal_connect (G_OBJECT (xw->widget_osr),
-			    "mouse-target-changed",
-			    G_CALLBACK (mouse_target_changed),
-			    xw);
-	  g_signal_connect (G_OBJECT (xw->widget_osr),
-			    "create",
-			    G_CALLBACK (webkit_create_cb),
-			    xw);
-	  g_signal_connect (G_OBJECT (xw->widget_osr),
-			    "script-dialog",
-			    G_CALLBACK (webkit_script_dialog_cb),
-			    NULL);
-	  g_signal_connect (G_OBJECT (xw->widget_osr),
-			    "run-file-chooser",
-			    G_CALLBACK (run_file_chooser_cb),
-			    NULL);
-        }
+      gst_bin_add_many (GST_BIN (xw->gst_pipeline), xw->gst_source,
+			xw->gst_tee, queue, fakesink, NULL);
 
-      g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event",
-			G_CALLBACK (offscreen_damage_event), xw);
+      gst_element_link_many (xw->gst_tee, queue, fakesink, NULL);
 
-      unblock_input ();
+      if (!gst_element_link (xw->gst_source, xw->gst_tee))
+	emacs_abort ();
+
+      if (!gst_element_set_state (xw->gst_pipeline, GST_STATE_PAUSED))
+	emacs_abort ();
     }
+#endif
 #elif defined NS_IMPL_COCOA
   nsxwidget_init (xw);
 #endif
@@ -335,6 +394,9 @@ DEFUN ("xwidget-perform-lispy-event",
     f = SELECTED_FRAME ();
 
 #ifdef USE_GTK
+  if (!xw->xg_p)
+    return Qnil;
+
   widget = gtk_window_get_focus (GTK_WINDOW (xw->widgetwindow_osr));
 
   if (!widget)
@@ -888,7 +950,8 @@ xwidget_button (struct xwidget_view *view,
 		bool down_p, int x, int y, int button,
 		int modifier_state, Time time)
 {
-  if (NILP (XXWIDGET (view->model)->buffer))
+  if (NILP (XXWIDGET (view->model)->buffer)
+      || !XWIDGET_VIEW_GTK_P (view))
     return;
 
   record_osr_embedder (view);
@@ -947,7 +1010,7 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
   int y;
   GtkWidget *target;
 
-  if (NILP (model->buffer))
+  if (NILP (model->buffer) || !model->xg_p)
     return;
 
   xg_event = gdk_event_new (event->type == MotionNotify
@@ -1117,7 +1180,17 @@ xwidget_expose (struct xwidget_view *xv)
 {
   struct xwidget *xw = XXWIDGET (xv->model);
 
-  xv_do_draw (xv, xw);
+  if (xw->xg_p)
+    xv_do_draw (xv, xw);
+#ifdef HAVE_GSTREAMER
+  else if (EQ (xw->type, Qmedia) && XWIDGET_LIVE_P (xw))
+    {
+      if (xv->wdesc != None)
+	XMoveWindow (xv->dpy, xv->internal_window,
+		     -xv->clip_left, -xv->clip_top);
+      gst_video_overlay_expose (GST_VIDEO_OVERLAY (xv->video_sink));
+    }
+#endif
 }
 #endif /* USE_GTK */
 
@@ -1690,12 +1763,81 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
 				 CopyFromParent, CWEventMask, &a);
       XLowerWindow (xv->dpy, xv->wdesc);
       XDefineCursor (xv->dpy, xv->wdesc, xv->cursor);
-      xv->cr_surface = cairo_xlib_surface_create (xv->dpy,
-						  xv->wdesc,
-						  FRAME_DISPLAY_INFO (s->f)->visual,
-						  clip_right - clip_left,
-						  clip_bottom - clip_top);
-      xv->cr_context = cairo_create (xv->cr_surface);
+
+      if (XWIDGET_VIEW_GTK_P (xv))
+	{
+	  xv->cr_surface = cairo_xlib_surface_create (xv->dpy,
+						      xv->wdesc,
+						      FRAME_DISPLAY_INFO (s->f)->visual,
+						      clip_right - clip_left,
+						      clip_bottom - clip_top);
+	  xv->cr_context = cairo_create (xv->cr_surface);
+	}
+#ifdef HAVE_GSTREAMER
+      else
+	{
+	  XFlush (xv->dpy);
+
+	  if (EQ (xww->type, Qmedia) && XWIDGET_LIVE_P (xww))
+	    {
+	      GstPadTemplate *templ;
+	      GstPad *sinkpad;
+
+	      a.event_mask = ExposureMask;
+	      a.background_pixel = FRAME_BACKGROUND_PIXEL (xv->frame);
+
+	      xv->internal_window = XCreateWindow (xv->dpy, xv->wdesc,
+						   -clip_left, -clip_top,
+						   xww->width, xww->height,
+						   0, CopyFromParent, CopyFromParent,
+						   CopyFromParent,
+						   (CWEventMask | CWBackPixel), &a);
+
+	      XMapWindow (xv->dpy, xv->internal_window);
+	      XFlush (xv->dpy);
+
+	      Fputhash (make_fixnum (xv->internal_window), xvw, x_window_to_xwv_map);
+
+	      templ = gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (xww->gst_tee),
+							  "src_%u");
+
+	      xv->teepad = gst_element_request_pad (xww->gst_tee,
+						    templ, NULL, NULL);
+	      xv->video_sink = gst_element_factory_make ("xvimagesink", NULL);
+	      xv->video_queue = gst_element_factory_make ("queue", NULL);
+
+	      gst_object_ref (xv->video_queue);
+	      gst_object_ref (xv->video_sink);
+
+	      g_object_set_data (G_OBJECT (xv->video_sink), XG_WINDOW_HANDLE,
+				 (gpointer) xv->internal_window);
+	      g_object_set (G_OBJECT (xv->video_sink), "display",
+			    FRAME_TERMINAL (xv->frame)->name, NULL);
+
+	      gst_video_overlay_handle_events (GST_VIDEO_OVERLAY (xv->video_sink),
+					       FALSE);
+
+	      gst_bin_add_many (GST_BIN (xww->gst_pipeline), xv->video_queue,
+				xv->video_sink, NULL);
+
+	      if (!gst_element_link (xv->video_queue, xv->video_sink))
+		emacs_abort ();
+
+	      gst_element_sync_state_with_parent (xv->video_queue);
+	      gst_element_sync_state_with_parent (xv->video_sink);
+
+	      sinkpad = gst_element_get_static_pad (xv->video_queue, "sink");
+	      gst_pad_link (xv->teepad, sinkpad);
+	      gst_object_unref (sinkpad);
+
+	      xv->sinkpad = sinkpad;
+
+	      gst_element_sync_state_with_parent (xww->gst_tee);
+
+	      xwidget_expose (xv);
+	    }
+	}
+#endif
       Fputhash (make_fixnum (xv->wdesc), xvw, x_window_to_xwv_map);
 
       moved = false;
@@ -1709,8 +1851,9 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
       XMoveResizeWindow (xv->dpy, xv->wdesc, x + clip_left, y + clip_top,
 			 clip_right - clip_left, clip_bottom - clip_top);
       XFlush (xv->dpy);
-      cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
-				   clip_bottom - clip_top);
+      if (XWIDGET_VIEW_GTK_P (xv))
+	cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
+				     clip_bottom - clip_top);
 #elif defined NS_IMPL_COCOA
       nsxwidget_move_view (xv, x + clip_left, y + clip_top);
 #endif
@@ -1740,8 +1883,10 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
 			     clip_bottom - clip_top);
 	    }
 	  XFlush (xv->dpy);
-	  cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
-				       clip_bottom - clip_top);
+
+	  if (xww->xg_p)
+	    cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
+					 clip_bottom - clip_top);
 	}
 #elif defined NS_IMPL_COCOA
       nsxwidget_resize_view (xv, clip_right - clip_left,
@@ -1765,7 +1910,10 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
       if (!xwidget_hidden (xv))
 	{
 #ifdef USE_GTK
-	  gtk_widget_queue_draw (xww->widget_osr);
+	  if (xww->xg_p)
+	    gtk_widget_queue_draw (xww->widget_osr);
+	  else
+	    xwidget_expose (xv);
 #elif defined NS_IMPL_COCOA
 	  nsxwidget_set_needsdisplay (xv);
 #endif
@@ -1788,6 +1936,12 @@ #define CHECK_WEBKIT_WIDGET(xw)				\
   if (NILP (xw->buffer) || !EQ (xw->type, Qwebkit))	\
     error ("Not a WebKit widget")
 
+#ifdef HAVE_GSTREAMER
+#define CHECK_MEDIA_WIDGET(xw)				\
+  if (NILP (xw->buffer) || !EQ (xw->type, Qmedia))	\
+    error ("Not a WebKit widget")
+#endif
+
 /* Macro that checks xwidget hold webkit web view first.  */
 #define WEBKIT_FN_INIT()						\
   CHECK_LIVE_XWIDGET (xwidget);						\
@@ -1989,6 +2143,14 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
 #ifdef USE_GTK
 	      xv->just_resized = true;
 	      SET_FRAME_GARBAGED (xv->frame);
+#ifdef HAVE_GSTREAMER
+	      if (EQ (xw->type, Qmedia))
+		{
+		  XResizeWindow (xv->dpy, xv->internal_window,
+				 xw->width, xw->height);
+		}
+#endif
+
 #else
 	      wset_redisplay (XWINDOW (xv->w));
 #endif
@@ -2000,7 +2162,7 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
 
   /* If there is an offscreen widget resize it first.  */
 #ifdef USE_GTK
-  if (xw->widget_osr)
+  if (xw->xg_p && xw->widget_osr)
     {
       gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
                          xw->height);
@@ -2030,9 +2192,14 @@ DEFUN ("xwidget-size-request",
 {
   CHECK_LIVE_XWIDGET (xwidget);
 #ifdef USE_GTK
-  GtkRequisition requisition;
-  gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition);
-  return list2i (requisition.width, requisition.height);
+  if (XXWIDGET (xwidget)->xg_p)
+    {
+      GtkRequisition requisition;
+      gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition);
+      return list2i (requisition.width, requisition.height);
+    }
+
+  return Qnil;
 #elif defined NS_IMPL_COCOA
   return nsxwidget_get_size (XXWIDGET (xwidget));
 #endif
@@ -2115,18 +2282,30 @@ DEFUN ("delete-xwidget-view",
 #ifdef USE_GTK
   struct xwidget *xw = XXWIDGET (xv->model);
   GdkWindow *w;
-
+#ifdef HAVE_GSTREAMER
+  block_input ();
+  if (XWIDGET_LIVE_P (xw) && EQ (xw->type, Qmedia))
+    unlink_gst_xwidget_view (xv);
+  unblock_input ();
+#endif
   if (xv->wdesc != None)
     {
       block_input ();
-      cairo_destroy (xv->cr_context);
-      cairo_surface_destroy (xv->cr_surface);
+      if (XWIDGET_VIEW_GTK_P (xv))
+	{
+	  cairo_destroy (xv->cr_context);
+	  cairo_surface_destroy (xv->cr_surface);
+	}
       XDestroyWindow (xv->dpy, xv->wdesc);
       Fremhash (make_fixnum (xv->wdesc), x_window_to_xwv_map);
+#ifdef HAVE_GSTREAMER
+      if (XWIDGET_LIVE_P (xw) && EQ (xw->type, Qmedia))
+	Fremhash (make_fixnum (xv->internal_window), x_window_to_xwv_map);
+#endif
       unblock_input ();
     }
 
-  if (xw->embedder_view == xv && !NILP (xw->buffer))
+  if (xw->xg_p && xw->embedder_view == xv && !NILP (xw->buffer))
     {
       w = gtk_widget_get_window (xw->widgetwindow_osr);
 
@@ -2555,6 +2734,77 @@ DEFUN ("xwidget-webkit-back-forward-list", Fxwidget_webkit_back_forward_list,
 
   return list3 (back, here, forward);
 }
+
+#ifdef HAVE_GSTREAMER
+DEFUN ("xwidget-media-pause", Fxwidget_media_pause, Sxwidget_media_pause,
+       1, 1, 0, doc: /* Pause specified media XWIDGET.
+This causes playback to stop until you resume it using
+`xwidget-media-play'.  */)
+  (Lisp_Object xwidget)
+{
+  struct xwidget *xw;
+  struct xwidget_view *xv;
+  Lisp_Object tem;
+
+  CHECK_LIVE_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+  CHECK_MEDIA_WIDGET (xw);
+
+  block_input ();
+  gst_element_set_state (xw->gst_pipeline, GST_STATE_PAUSED);
+  gst_element_sync_state_with_parent (xw->gst_tee);
+  gst_element_sync_state_with_parent (xw->gst_fakesink);
+
+  for (tem = internal_xwidget_view_list; CONSP (tem); tem = XCDR (tem))
+    {
+      xv = XXWIDGET_VIEW (XCAR (tem));
+
+      if (EQ (xv->model, xwidget))
+	{
+	  gst_element_sync_state_with_parent (xv->video_queue);
+	  gst_element_sync_state_with_parent (xv->video_sink);
+	}
+    }
+
+  unblock_input ();
+
+  return Qnil;
+}
+
+DEFUN ("xwidget-media-play", Fxwidget_media_play, Sxwidget_media_play,
+       1, 1, 0, doc: /* Resume playback of specified media XWIDGET.  */)
+  (Lisp_Object xwidget)
+{
+  struct xwidget *xw;
+  struct xwidget_view *xv;
+  Lisp_Object tem;
+
+  CHECK_LIVE_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+  CHECK_MEDIA_WIDGET (xw);
+
+  block_input ();
+  gst_element_set_state (xw->gst_pipeline, GST_STATE_PLAYING);
+  gst_element_sync_state_with_parent (xw->gst_tee);
+  gst_element_sync_state_with_parent (xw->gst_fakesink);
+
+  for (tem = internal_xwidget_view_list; CONSP (tem); tem = XCDR (tem))
+    {
+      xv = XXWIDGET_VIEW (XCAR (tem));
+
+      if (EQ (xv->model, xwidget))
+	{
+	  gst_element_sync_state_with_parent (xv->video_queue);
+	  gst_element_sync_state_with_parent (xv->video_sink);
+	}
+    }
+
+  gst_element_sync_state_with_parent (xw->gst_tee);
+  unblock_input ();
+
+  return Qnil;
+}
+#endif
 #endif
 
 void
@@ -2584,6 +2834,7 @@ syms_of_xwidget (void)
   defsubr (&Sxwidget_webkit_zoom);
   defsubr (&Sxwidget_webkit_execute_script);
   DEFSYM (Qwebkit, "webkit");
+  DEFSYM (Qmedia, "media");
 
   defsubr (&Sxwidget_size_request);
   defsubr (&Sdelete_xwidget_view);
@@ -2600,6 +2851,10 @@ syms_of_xwidget (void)
 #ifdef USE_GTK
   defsubr (&Sxwidget_webkit_load_html);
   defsubr (&Sxwidget_webkit_back_forward_list);
+#ifdef HAVE_GSTREAMER
+  defsubr (&Sxwidget_media_pause);
+  defsubr (&Sxwidget_media_play);
+#endif
 #endif
   defsubr (&Skill_xwidget);
 
@@ -2862,7 +3117,7 @@ kill_xwidget (struct xwidget *xw)
 #ifdef USE_GTK
   xw->buffer = Qnil;
 
-  if (xw->widget_osr && xw->widgetwindow_osr)
+  if (xw->xg_p && xw->widget_osr && xw->widgetwindow_osr)
     {
       gtk_widget_destroy (xw->widget_osr);
       gtk_widget_destroy (xw->widgetwindow_osr);
@@ -2882,6 +3137,26 @@ kill_xwidget (struct xwidget *xw)
 	}
     }
 
+#ifdef HAVE_GSTREAMER
+  Lisp_Object tem;
+
+  if (EQ (xw->type, Qmedia))
+    {
+      for (tem = internal_xwidget_view_list; CONSP (tem);
+	   tem = XCDR (tem))
+	{
+	  struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tem));
+
+	  if (XXWIDGET (xv->model) == xw)
+	    unlink_gst_xwidget_view (xv);
+	}
+      gst_object_unref (xw->gst_tee);
+      gst_object_unref (xw->gst_pipeline);
+      gst_object_unref (xw->gst_source);
+      gst_object_unref (xw->gst_fakesink);
+    }
+#endif
+
   xw->widget_osr = NULL;
   xw->widgetwindow_osr = NULL;
   xw->find_text = NULL;
@@ -2908,3 +3183,59 @@ kill_buffer_xwidgets (Lisp_Object buffer)
       }
     }
 }
+
+#ifdef HAVE_GSTREAMER
+static GstBusSyncReply
+gst_create_window (GstBus *bus, GstMessage *msg, gpointer user_data)
+{
+  GstObject *elm;
+  Window wdesc;
+
+  if (!gst_is_video_overlay_prepare_window_handle_message (msg))
+    return GST_BUS_PASS;
+
+  elm = GST_MESSAGE_SRC (msg);
+  wdesc = (Window) g_object_get_data (G_OBJECT (elm), XG_WINDOW_HANDLE);
+
+  gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (elm), wdesc);
+
+  return GST_BUS_DROP;
+}
+
+static gboolean
+gst_message_cb (GstBus *bus, GstMessage *message, gpointer user_data)
+{
+  return TRUE;
+}
+
+static bool
+check_gstreamer_dependencies (void)
+{
+  GstRegistry *registry = gst_registry_get ();
+
+  return (gst_registry_find_feature (registry, "xvimagesink",
+				     GST_TYPE_ELEMENT_FACTORY)
+	  && gst_registry_find_feature (registry, "queue",
+					GST_TYPE_ELEMENT_FACTORY)
+	  && gst_registry_find_feature (registry, "videotestsrc",
+					GST_TYPE_ELEMENT_FACTORY)
+	  && gst_registry_find_feature (registry, "tee",
+					GST_TYPE_ELEMENT_FACTORY));
+}
+
+static void
+unlink_gst_xwidget_view (struct xwidget_view *xv)
+{
+  struct xwidget *xw = XXWIDGET (xv->model);
+
+  gst_pad_unlink (xv->teepad, xv->sinkpad);
+  gst_element_unlink (xv->video_queue, xv->video_sink);
+
+  gst_element_set_state (xv->video_queue, GST_STATE_NULL);
+  gst_element_set_state (xv->video_sink, GST_STATE_NULL);
+  gst_bin_remove_many (GST_BIN (xw->gst_pipeline), xv->video_sink,
+		       xv->video_queue, NULL);
+  gst_object_unref (xv->video_sink);
+  gst_object_unref (xv->video_queue);
+}
+#endif
diff --git a/src/xwidget.h b/src/xwidget.h
index 78fe865dd8..66f7fb2c4c 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -39,6 +39,10 @@ #define XWIDGET_H_INCLUDED
 #import "nsxwidget.h"
 #endif
 
+#ifdef HAVE_GSTREAMER
+#include <gst/gst.h>
+#endif
+
 struct xwidget
 {
   union vectorlike_header header;
@@ -65,6 +69,16 @@ #define XWIDGET_H_INCLUDED
   char *find_text;
 
 #if defined (USE_GTK)
+  /* Whether or not the widget is used to display GTK widgets. */
+  bool xg_p;
+
+#ifdef HAVE_GSTREAMER
+  GstElement *gst_tee;
+  GstElement *gst_pipeline;
+  GstElement *gst_source;
+  GstElement *gst_fakesink;
+#endif
+
   /* For offscreen widgets, unused if not osr.  */
   GtkWidget *widget_osr;
   GtkWidget *widgetwindow_osr;
@@ -112,6 +126,14 @@ #define XWIDGET_H_INCLUDED
   Emacs_Cursor cursor;
   struct frame *frame;
 
+#ifdef HAVE_GSTREAMER
+  Window internal_window;
+  GstPad *teepad;
+  GstPad *sinkpad;
+  GstElement *video_sink;
+  GstElement *video_queue;
+#endif
+
   cairo_surface_t *cr_surface;
   cairo_t *cr_context;
   int just_resized;
@@ -159,6 +181,9 @@ #define XXWIDGET_VIEW(a) (eassert (XWIDGET_VIEW_P (a)), \
 #define CHECK_XWIDGET_VIEW(x) \
   CHECK_TYPE (XWIDGET_VIEW_P (x), Qxwidget_view_p, x)
 
+#define XWIDGET_VIEW_GTK_P(x) \
+  XXWIDGET ((x)->model)->xg_p
+
 #define XG_XWIDGET "emacs_xwidget"
 #define XG_XWIDGET_VIEW "emacs_xwidget_view"
 
-- 
2.31.1


[-- Attachment #3: Type: text/plain, Size: 315 bytes --]


But this probably means you don't have the GStreamer development files
installed.

The packages ought to be named "gstreamer1-devel" and
"gstreamer1-plugins-base-devel" or something to that effect.  Make sure
to install GStreamer 1.0, instead of GStreamer 0.10, and configure with
`--with-gstreamer=yes'.

Thanks!

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-19  6:37         ` Po Lu
@ 2021-11-19  6:53           ` Lars Ingebrigtsen
  2021-11-19 13:03           ` Eli Zaretskii
  1 sibling, 0 replies; 70+ messages in thread
From: Lars Ingebrigtsen @ 2021-11-19  6:53 UTC (permalink / raw)
  To: Po Lu; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 582 bytes --]

Po Lu <luangruo@yahoo.com> writes:

> But this probably means you don't have the GStreamer development files
> installed.
>
>
> The packages ought to be named "gstreamer1-devel" and
> "gstreamer1-plugins-base-devel" or something to that effect.  Make sure
> to install GStreamer 1.0, instead of GStreamer 0.10, and configure with
> `--with-gstreamer=yes'.

Ah, right.  For the people at home that wants to reproduce, I did:

sudo apt install libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev
./configure --with-xwidgets --with-gstreamer

and then everything seems to work here:


[-- Attachment #2: Type: image/png, Size: 9502 bytes --]

[-- Attachment #3: Type: text/plain, Size: 105 bytes --]



-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-19  6:37         ` Po Lu
  2021-11-19  6:53           ` Lars Ingebrigtsen
@ 2021-11-19 13:03           ` Eli Zaretskii
  2021-11-19 13:07             ` Po Lu
  1 sibling, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2021-11-19 13:03 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel

> From: Po Lu <luangruo@yahoo.com>
> Cc: emacs-devel@gnu.org
> Date: Fri, 19 Nov 2021 14:37:29 +0800
> 
> +@defun xwidget-media-pause xwidget
> +Suspend playback of @var{xwidget}, a media xwidget.  You can later
> +resume playback using @code{xwidget-media-play}.
> +@end defun
> +
> +@defun xwidget-media-pause xwidget
> +Start or resume playback of @var{xwidget}, a media xwidget.  You can
> +later pause playback using @code{xwidget-media-pause}.
> +@end defun

How do you stop the playback?

For that matter, why not have user commands to control playback?



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-19 13:03           ` Eli Zaretskii
@ 2021-11-19 13:07             ` Po Lu
  2021-11-19 13:22               ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Po Lu @ 2021-11-19 13:07 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: larsi, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> +@defun xwidget-media-pause xwidget
>> +Suspend playback of @var{xwidget}, a media xwidget.  You can later
>> +resume playback using @code{xwidget-media-play}.
>> +@end defun
>> +
>> +@defun xwidget-media-pause xwidget
>> +Start or resume playback of @var{xwidget}, a media xwidget.  You can
>> +later pause playback using @code{xwidget-media-pause}.
>> +@end defun

> How do you stop the playback?

That's the same as pausing playback, at least in GStreamer.

> For that matter, why not have user commands to control playback?

That would be for Lisp code using these primitives to implement.  (Just
like image-mode has most of the user commands related to images.)

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-19 13:07             ` Po Lu
@ 2021-11-19 13:22               ` Eli Zaretskii
  2021-11-19 13:33                 ` Po Lu
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2021-11-19 13:22 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel

> From: Po Lu <luangruo@yahoo.com>
> Cc: larsi@gnus.org,  emacs-devel@gnu.org
> Date: Fri, 19 Nov 2021 21:07:54 +0800
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> +@defun xwidget-media-pause xwidget
> >> +Suspend playback of @var{xwidget}, a media xwidget.  You can later
> >> +resume playback using @code{xwidget-media-play}.
> >> +@end defun
> >> +
> >> +@defun xwidget-media-pause xwidget
> >> +Start or resume playback of @var{xwidget}, a media xwidget.  You can
> >> +later pause playback using @code{xwidget-media-pause}.
> >> +@end defun
> 
> > How do you stop the playback?
> 
> That's the same as pausing playback, at least in GStreamer.

No, I mean stopping it so that it can never be resumed.

If GStreamer only supports those two actions, I wonder whether we
should have an abstraction layer above it.  But that could be in a
separate patch.

> > For that matter, why not have user commands to control playback?
> 
> That would be for Lisp code using these primitives to implement.  (Just
> like image-mode has most of the user commands related to images.)

Well, I hope it will be.  Right now, even playing an audio in Emacs is
very restrictive: it locks up the main thread until the audio finishes
playing.  That's not appropriate for a modern platform, so I wish we
could have a better UI and UX.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-19 13:22               ` Eli Zaretskii
@ 2021-11-19 13:33                 ` Po Lu
  2021-11-19 13:45                   ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Po Lu @ 2021-11-19 13:33 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: larsi, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> No, I mean stopping it so that it can never be resumed.

Ah, I understand now.  That would be `xwidget-kill'.

> Well, I hope it will be.  Right now, even playing an audio in Emacs is
> very restrictive: it locks up the main thread until the audio finishes
> playing.  That's not appropriate for a modern platform, so I wish we
> could have a better UI and UX.

GStreamer has an asynchronous interface, where the playback is performed
in separate threads, and events are posted to the main GLib event loop
which is run by the code in `xgselect.c'.

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-19 13:33                 ` Po Lu
@ 2021-11-19 13:45                   ` Eli Zaretskii
  0 siblings, 0 replies; 70+ messages in thread
From: Eli Zaretskii @ 2021-11-19 13:45 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel

> From: Po Lu <luangruo@yahoo.com>
> Cc: larsi@gnus.org,  emacs-devel@gnu.org
> Date: Fri, 19 Nov 2021 21:33:02 +0800
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > No, I mean stopping it so that it can never be resumed.
> 
> Ah, I understand now.  That would be `xwidget-kill'.

Then perhaps mention that in the doc string?

> > Well, I hope it will be.  Right now, even playing an audio in Emacs is
> > very restrictive: it locks up the main thread until the audio finishes
> > playing.  That's not appropriate for a modern platform, so I wish we
> > could have a better UI and UX.
> 
> GStreamer has an asynchronous interface, where the playback is performed
> in separate threads, and events are posted to the main GLib event loop
> which is run by the code in `xgselect.c'.

Sure, I meant to have user commands that take advantage of that.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-19  2:51 ` GStreamer xwidget Po Lu
  2021-11-19  4:01   ` T.V Raman
  2021-11-19  5:38   ` Lars Ingebrigtsen
@ 2021-11-20  5:07   ` Po Lu
  2021-11-20  7:23     ` Eli Zaretskii
  2021-11-21  5:19     ` Richard Stallman
  2021-11-20  7:42   ` Richard Stallman
  3 siblings, 2 replies; 70+ messages in thread
From: Po Lu @ 2021-11-20  5:07 UTC (permalink / raw)
  To: emacs-devel

Po Lu <luangruo@yahoo.com> writes:

> I would like to install the following change that introduces a
> GStreamer-based media widget.
>
> It depends on GStreamer, gst-plugins-base, and gst-plugins-good and is
> thus a compile-time option.

So is it OK if I install this?  Even if it doesn't do much ATM, it still
lays down a lot of important groundwork, including the ability to have
xwidgets that display directly to an X window without GTK.

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-20  5:07   ` Po Lu
@ 2021-11-20  7:23     ` Eli Zaretskii
  2021-11-20  7:27       ` Po Lu
  2021-11-21  5:19     ` Richard Stallman
  1 sibling, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2021-11-20  7:23 UTC (permalink / raw)
  To: Po Lu; +Cc: emacs-devel

> From: Po Lu <luangruo@yahoo.com>
> Date: Sat, 20 Nov 2021 13:07:31 +0800
> 
> So is it OK if I install this?  Even if it doesn't do much ATM, it still
> lays down a lot of important groundwork, including the ability to have
> xwidgets that display directly to an X window without GTK.

If you (or someone else) intend to work on building more useful
features on this soon enough, I'd prefer not to install until you've
implemented those more useful features.  If you don't intend to work
on this soon, perhaps a feature branch is in order?  I'm not sure it's
a good idea to install infrastructure that doesn't have enough
functionality to be useful to Lisp programs.

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-20  7:23     ` Eli Zaretskii
@ 2021-11-20  7:27       ` Po Lu
  0 siblings, 0 replies; 70+ messages in thread
From: Po Lu @ 2021-11-20  7:27 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> If you (or someone else) intend to work on building more useful
> features on this soon enough, I'd prefer not to install until you've
> implemented those more useful features.  If you don't intend to work
> on this soon, perhaps a feature branch is in order?  I'm not sure it's
> a good idea to install infrastructure that doesn't have enough
> functionality to be useful to Lisp programs.

I plan to do more work on these features in about a week, so I think
I'll wait until they're finished before installing.

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-19  2:51 ` GStreamer xwidget Po Lu
                     ` (2 preceding siblings ...)
  2021-11-20  5:07   ` Po Lu
@ 2021-11-20  7:42   ` Richard Stallman
  2021-11-20  8:05     ` Po Lu
  3 siblings, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-11-20  7:42 UTC (permalink / raw)
  To: Po Lu; +Cc: emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > I would like to install the following change that introduces a
  > GStreamer-based media widget.

  > It depends on GStreamer, gst-plugins-base, and gst-plugins-good and is
  > thus a compile-time option.

Before deciding whether to install this, we need to understand clearly
what jobs it can do.  What kinds of media does GStreamer stream?
Which formats?  Does GStreamer implement DRM?  Is GStreamer 100% free
ziyou software, with no exceptions?

We also have to think about whether it is good or bad to introduce
this nonmodularity.  What is better about showing videos this way,
rather than just launching vlc in another window?

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-20  7:42   ` Richard Stallman
@ 2021-11-20  8:05     ` Po Lu
  2021-11-20  8:16       ` Lars Ingebrigtsen
  2021-12-01  7:07       ` Richard Stallman
  0 siblings, 2 replies; 70+ messages in thread
From: Po Lu @ 2021-11-20  8:05 UTC (permalink / raw)
  To: Richard Stallman; +Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

>   > I would like to install the following change that introduces a
>   > GStreamer-based media widget.
>
>   > It depends on GStreamer, gst-plugins-base, and gst-plugins-good and is
>   > thus a compile-time option.

> Before deciding whether to install this, we need to understand clearly
> what jobs it can do.  What kinds of media does GStreamer stream?

The plugins that this change takes advantage of will only stream free
software, as it doesn't depend on gst-plugins-ugly or gst-plugins-bad.

> Which formats?  Does GStreamer implement DRM?

I can't give a definitive list of formats, but the GStreamer plugins
this change will take advantage of only support free formats, consist
entirely of free code, and have a policy against implementing DRM.

> Is GStreamer 100% free ziyou software, with no exceptions?

GStreamer itself is a framework that is 100% free (as in freedom)
software.  There are proprietary plugins that implement DRM, but they
are separate from GStreamer itself and the base and good plugins, and
Emacs will not use them even if present on a user's system.

> We also have to think about whether it is good or bad to introduce
> this nonmodularity.  What is better about showing videos this way,
> rather than just launching vlc in another window?

People seem to want that in Emacs.

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-20  8:05     ` Po Lu
@ 2021-11-20  8:16       ` Lars Ingebrigtsen
  2021-11-21  5:18         ` Richard Stallman
  2021-12-01  7:07       ` Richard Stallman
  1 sibling, 1 reply; 70+ messages in thread
From: Lars Ingebrigtsen @ 2021-11-20  8:16 UTC (permalink / raw)
  To: Po Lu; +Cc: Richard Stallman, emacs-devel

Po Lu <luangruo@yahoo.com> writes:

>> We also have to think about whether it is good or bad to introduce
>> this nonmodularity.  What is better about showing videos this way,
>> rather than just launching vlc in another window?
>
> People seem to want that in Emacs.

Reading web pages that have embedded videos is quite common.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-20  8:16       ` Lars Ingebrigtsen
@ 2021-11-21  5:18         ` Richard Stallman
  2021-11-21  5:27           ` Po Lu
  2021-11-21  6:52           ` Lars Ingebrigtsen
  0 siblings, 2 replies; 70+ messages in thread
From: Richard Stallman @ 2021-11-21  5:18 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: luangruo, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > Reading web pages that have embedded videos is quite common.

How _exactly_ does that relate to letting Emacs make GStreamer windows?
Please describe the scenario clearly and spell out the argument.
That way we can tell what conclusion really follows.

We should have this discussion now, _before_ installing any code for
GStreamer, because that's much easier than discussing it afterward.

The most important questions are these,

    Before deciding whether to install this, we need to understand clearly
    what jobs it can do.  What kinds of media does GStreamer stream?
    Which formats?  Does GStreamer implement DRM?  Is GStreamer 100% free
    ziyou software, with no exceptions?

because they will determine whether there is an important reason
to reject making Emacs work closely with GStreamer.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-20  5:07   ` Po Lu
  2021-11-20  7:23     ` Eli Zaretskii
@ 2021-11-21  5:19     ` Richard Stallman
  2021-11-21  6:53       ` Lars Ingebrigtsen
  1 sibling, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-11-21  5:19 UTC (permalink / raw)
  To: Po Lu; +Cc: emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > I would like to install the following change that introduces a
  > > GStreamer-based media widget.
  > >
  > > It depends on GStreamer, gst-plugins-base, and gst-plugins-good and is
  > > thus a compile-time option.

  > So is it OK if I install this?

Not now.  Please wait until we finish examining the issue and judge
whether this feature is ok to have in Emacs.


-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-21  5:18         ` Richard Stallman
@ 2021-11-21  5:27           ` Po Lu
  2021-11-22  4:31             ` Richard Stallman
  2021-11-21  6:52           ` Lars Ingebrigtsen
  1 sibling, 1 reply; 70+ messages in thread
From: Po Lu @ 2021-11-21  5:27 UTC (permalink / raw)
  To: Richard Stallman; +Cc: Lars Ingebrigtsen, emacs-devel

Richard Stallman <rms@gnu.org> writes:

> The most important questions are these,

>     Before deciding whether to install this, we need to understand clearly
>     what jobs it can do.  What kinds of media does GStreamer stream?
>     Which formats?  Does GStreamer implement DRM?  Is GStreamer 100% free
>     ziyou software, with no exceptions?

> because they will determine whether there is an important reason
> to reject making Emacs work closely with GStreamer.

Perhaps my mail didn't reach you, but I sent you mail answering your
questions earlier.

It is reproduced below for your convenience:

> From: Po Lu <luangruo@yahoo.com>
> Subject: Re: GStreamer xwidget
> To: Richard Stallman <rms@gnu.org>
> Cc: emacs-devel@gnu.org
> Date: Sat, 20 Nov 2021 16:05:07 +0800 (21 hours, 21 minutes, 9 seconds ago)
>
> Richard Stallman <rms@gnu.org> writes:
>
>>   > I would like to install the following change that introduces a
>>   > GStreamer-based media widget.
>>
>>   > It depends on GStreamer, gst-plugins-base, and gst-plugins-good and is
>>   > thus a compile-time option.
>>
>> Before deciding whether to install this, we need to understand clearly
>> what jobs it can do.  What kinds of media does GStreamer stream?
>
> The plugins that this change takes advantage of will only stream free
> software, as it doesn't depend on gst-plugins-ugly or gst-plugins-bad.
>
>> Which formats?  Does GStreamer implement DRM?
>
> I can't give a definitive list of formats, but the GStreamer plugins
> this change will take advantage of only support free formats, consist
> entirely of free code, and have a policy against implementing DRM.
>
>> Is GStreamer 100% free ziyou software, with no exceptions?
>
> GStreamer itself is a framework that is 100% free (as in freedom)
> software.  There are proprietary plugins that implement DRM, but they
> are separate from GStreamer itself and the base and good plugins, and
> Emacs will not use them even if present on a user's system.

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-21  5:18         ` Richard Stallman
  2021-11-21  5:27           ` Po Lu
@ 2021-11-21  6:52           ` Lars Ingebrigtsen
  2021-11-21 14:45             ` Arthur Miller
  2021-11-22  4:31             ` Richard Stallman
  1 sibling, 2 replies; 70+ messages in thread
From: Lars Ingebrigtsen @ 2021-11-21  6:52 UTC (permalink / raw)
  To: Richard Stallman; +Cc: luangruo, emacs-devel

Richard Stallman <rms@gnu.org> writes:

>   > Reading web pages that have embedded videos is quite common.
>
> How _exactly_ does that relate to letting Emacs make GStreamer windows?

Windows?  There's no GStreamer windows.

Po Lu's patch is for putting GStreamer widgets into buffers, and this
will allow eww to display the videos embedded in web pages in Emacs.

> Please describe the scenario clearly and spell out the argument.
> That way we can tell what conclusion really follows.

You seem to be demanding a lot of stuff here.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-21  5:19     ` Richard Stallman
@ 2021-11-21  6:53       ` Lars Ingebrigtsen
  2021-11-22  4:31         ` Richard Stallman
  0 siblings, 1 reply; 70+ messages in thread
From: Lars Ingebrigtsen @ 2021-11-21  6:53 UTC (permalink / raw)
  To: Richard Stallman; +Cc: Po Lu, emacs-devel

Richard Stallman <rms@gnu.org> writes:

>   > So is it OK if I install this?
>
> Not now.  Please wait until we finish examining the issue and judge
> whether this feature is ok to have in Emacs.

Po Lu has already answered all your question, and we have already
decided to add GStreamer support to Emacs.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-21  6:52           ` Lars Ingebrigtsen
@ 2021-11-21 14:45             ` Arthur Miller
  2021-11-23  6:09               ` Richard Stallman
  2021-11-22  4:31             ` Richard Stallman
  1 sibling, 1 reply; 70+ messages in thread
From: Arthur Miller @ 2021-11-21 14:45 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: luangruo, Richard Stallman, emacs-devel

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Richard Stallman <rms@gnu.org> writes:
>
>>   > Reading web pages that have embedded videos is quite common.
>>
>> How _exactly_ does that relate to letting Emacs make GStreamer windows?
>
> Windows?  There's no GStreamer windows.
>
> Po Lu's patch is for putting GStreamer widgets into buffers, and this
> will allow eww to display the videos embedded in web pages in Emacs.
>
>> Please describe the scenario clearly and spell out the argument.
>> That way we can tell what conclusion really follows.
>
> You seem to be demanding a lot of stuff here.

A possible application scenario would be also to stream or capture
your web camera; for example for chats or educational material, maybe playing
with image detection with Emacs and Elisp etc.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-21  5:27           ` Po Lu
@ 2021-11-22  4:31             ` Richard Stallman
  2021-11-22  4:41               ` Po Lu
  0 siblings, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-11-22  4:31 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > Perhaps my mail didn't reach you, but I sent you mail answering your
  > questions earlier.

I didn't see it before.  Thanks for repeating it.

Because I know nothing about GStreamer except what I've seen in these
messages, I can't be sure of the implications of these facts.  I don't
have enough context to fit them into.

  > > The plugins that this change takes advantage of will only stream free
  > > software,

That suggests the feature might be ok -- but verifying that calls
for some more discussion.

                as it doesn't depend on gst-plugins-ugly or gst-plugins-bad.

You have mentioned gst-plugins-good, gst-plugins-ugly and
gst-plugins-bad.  Can you tell me how they relate to GStreamer itself?
How does GStreamer interact with them?  Are they linked it by ld?
Is it static linking?

Does the choice of one of those inevitably have to be made when
building Emacs?  Does GStreamer ever use some sort of dynamic linking
to select one of them?

They say "plugins", not "plugin".  Is  there a separate plugin for each
media format?  If so, does selecting gst-plugins-good statically
link _all_ of the free plugins?  If not that, then what?


-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-21  6:53       ` Lars Ingebrigtsen
@ 2021-11-22  4:31         ` Richard Stallman
  0 siblings, 0 replies; 70+ messages in thread
From: Richard Stallman @ 2021-11-22  4:31 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: luangruo, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > Po Lu has already answered all your question, and we have already
  > decided to add GStreamer support to Emacs.

Don't jump the gun.  There's a possible moral issue here, so please
help me make sure this feature is ok.

It may take a few days to do this, -- but there's no rush.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-21  6:52           ` Lars Ingebrigtsen
  2021-11-21 14:45             ` Arthur Miller
@ 2021-11-22  4:31             ` Richard Stallman
  1 sibling, 0 replies; 70+ messages in thread
From: Richard Stallman @ 2021-11-22  4:31 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: luangruo, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > How _exactly_ does that relate to letting Emacs make GStreamer windows?

  > Windows?  There's no GStreamer windows.

  > Po Lu's patch is for putting GStreamer widgets into buffers, and this
  > will allow eww to display the videos embedded in web pages in Emacs.

Thank you for telling me this.  I don't know how this patch works, or
how GStreamer works, or how eww works -- that's why I am asking these
questions.

It's not easy to recognize all the questions that need to be asked.
Sometimes I make an assumption without realizing it, such as assuming
that a widget would be handled by telling a window to display it, and
it turns out that's mistaken.

  > > Please describe the scenario clearly and spell out the argument.
  > > That way we can tell what conclusion really follows.

  > You seem to be demanding a lot of stuff here.

I'm asking the questions that will enable me to understand the
situation so I can tell whether this feature fits the goals and values
of the GNU Project.  It is important to recognize situations where a
feature raises doubts, and think carefully about the issue before
installing the feature.

When we neglect to have that discussion in advance, the GNU Project
can drift into a contradictory moral position, and that is very bad.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-22  4:31             ` Richard Stallman
@ 2021-11-22  4:41               ` Po Lu
  2021-11-23  6:11                 ` Richard Stallman
  2021-11-23  6:11                 ` Richard Stallman
  0 siblings, 2 replies; 70+ messages in thread
From: Po Lu @ 2021-11-22  4:41 UTC (permalink / raw)
  To: Richard Stallman; +Cc: larsi, emacs-devel

Richard Stallman <rms@gnu.org> writes:

> Because I know nothing about GStreamer except what I've seen in these
> messages, I can't be sure of the implications of these facts.  I don't
> have enough context to fit them into.

Thanks, please see below.

> That suggests the feature might be ok -- but verifying that calls
> for some more discussion.
>
>                 as it doesn't depend on gst-plugins-ugly or gst-plugins-bad.

> You have mentioned gst-plugins-good, gst-plugins-ugly and
> gst-plugins-bad.  Can you tell me how they relate to GStreamer itself?

They are plugins maintained by the GStreamer developers, but are
separate from GStreamer itself.

> How does GStreamer interact with them?  Are they linked it by ld?
> Is it static linking?

They're not statically linked by GStreamer.  Instead, GStreamer will
dynamically link them depending on what the application requests.

> Does the choice of one of those inevitably have to be made when
> building Emacs?

No, see below.

> Does GStreamer ever use some sort of dynamic linking to select one of
> them?

GStreamer does, but it will not load any plugin Emacs doesn't ask it to.

> They say "plugins", not "plugin".  Is  there a separate plugin for each
> media format?

Yes, that is true.

> If so, does selecting gst-plugins-good statically link _all_ of the
> free plugins?  If not that, then what?

Asking for gst-plugins-base and gst-plugins-good will result in
GStreamer dynamically linking with the free plugins.  As long as Emacs C
code doesn't explictly tell GStreamer to load the ugly or bad plugins,
which are non-free, GStreamer will never load them.

The ugly and bad plugins are not installed with a default GStreamer
distribution either.  AFAIU, most GNU distributions do not have them in
their main package repositories either.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-21 14:45             ` Arthur Miller
@ 2021-11-23  6:09               ` Richard Stallman
  0 siblings, 0 replies; 70+ messages in thread
From: Richard Stallman @ 2021-11-23  6:09 UTC (permalink / raw)
  To: Arthur Miller; +Cc: luangruo, larsi, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > A possible application scenario would be also to stream or capture
  > your web camera;

That looks like is a niche scenario.  Does the argument for including
this feature rest on that scenario?  If so, it's pretty clear that
this isn't worth the effort of maintaining.

My point here is, niche uses are not enough to affect the issue at
hand.

I am sure the GStreamer feature has more important uses.  I'm not sure
what makes them so important, but if people think they are useful
enough to be worth the effort of maintaining it, I am sure that's true.

The issue that worries me is a potential deeper problem.  At present
it looks like things are probably ok -- see the other email -- but
it's not clear yet.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-22  4:41               ` Po Lu
@ 2021-11-23  6:11                 ` Richard Stallman
  2021-11-23  7:07                   ` Po Lu
  2021-11-23  6:11                 ` Richard Stallman
  1 sibling, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-11-23  6:11 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, rms, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > If so, does selecting gst-plugins-good statically link _all_ of the
  > > free plugins?  If not that, then what?

  > Asking for gst-plugins-base and gst-plugins-good will result in
  > GStreamer dynamically linking with the free plugins.  As long as Emacs C
  > code doesn't explictly tell GStreamer to load the ugly or bad plugins,
  > which are non-free, GStreamer will never load them.

This sounds mostly good, but this worries me:

  > > Does the choice of one of those inevitably have to be made when
  > > building Emacs?

  > No, see below.

I don't see any specifics about that point, and it is an important point.

Can you please show me precisely how Emacs would specify which plugins
to load?  What are the specifications of the interface?
What does the code actually look like?  If it uses any macros,
what does it macroexpand into?


-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-22  4:41               ` Po Lu
  2021-11-23  6:11                 ` Richard Stallman
@ 2021-11-23  6:11                 ` Richard Stallman
  2021-11-23  6:55                   ` Po Lu
  1 sibling, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-11-23  6:11 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > The ugly and bad plugins are not installed with a default GStreamer
  > distribution either.  AFAIU, most GNU distributions do not have them in
  > their main package repositories either.

This is not directly concerned with Emacs, but I'm curious.

According to Wikipedia, the "bad" problems of GStreamer have
_technical_ problems; perhaps they need more work.  Do you know
whether all the "bad" plug-ins are ziyou?

As for the "ugly" plug-ins, can you find for me a list of them, what
formats they support, and what the "distribution problem" of each one
is?  Basically, I'd like to know what the obstacles are to their use.

-- 
Dr Richard Stallman (https://stallman.org) Chief GNUisance of the GNU
Project (https://gnu.org) Founder, Free Software Foundation
(https://fsf.org) Internet Hall-of-Famer
(https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-23  6:11                 ` Richard Stallman
@ 2021-11-23  6:55                   ` Po Lu
  2021-11-24  4:28                     ` Richard Stallman
  0 siblings, 1 reply; 70+ messages in thread
From: Po Lu @ 2021-11-23  6:55 UTC (permalink / raw)
  To: Richard Stallman; +Cc: larsi, emacs-devel

Richard Stallman <rms@gnu.org> writes:

> This is not directly concerned with Emacs, but I'm curious.
>
> According to Wikipedia, the "bad" problems of GStreamer have
> _technical_ problems; perhaps they need more work.  Do you know
> whether all the "bad" plug-ins are ziyou?

I don't know, but I was told by word-of-mouth that the GStreamer
developers do not hold the "bad" plugins to any standard, both technical
and freedom-wise.

As such, they don't guarantee that those plugins are free software.

> As for the "ugly" plug-ins, can you find for me a list of them, what
> formats they support, and what the "distribution problem" of each one
> is?  Basically, I'd like to know what the obstacles are to their use.

Unfortunately, I don't know of a precise list of obstacles, but here's a
list of formats supported by the various plugins:

  - Microsoft ASF (possibly strangled by patents?)
  - DVD subtitles (though I don't know what precisely this is)
  - dvdlpcmdec (this possibly involves breaking DRM, could be illegal
    because of that)
  - RealMedia and RealAudio (patent encumbered, possible license problems)
  - "xingmux" (I couldn't find any information on this one)

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-23  6:11                 ` Richard Stallman
@ 2021-11-23  7:07                   ` Po Lu
  2021-11-23 20:54                     ` Richard Stallman
  0 siblings, 1 reply; 70+ messages in thread
From: Po Lu @ 2021-11-23  7:07 UTC (permalink / raw)
  To: Richard Stallman; +Cc: larsi, emacs-devel

Richard Stallman <rms@gnu.org> writes:

> Can you please show me precisely how Emacs would specify which plugins
> to load?  What are the specifications of the interface?  What does the
> code actually look like?  If it uses any macros, what does it
> macroexpand into?

Here's how one would create a GStreamer element (and in doing so load a
plugin):

  GstElement *element = gst_element_factory_make ("factoryname", NULL);

Where "factoryname" is the name of the element factory you want.

GStreamer will then find and load the shared library containing the
plugin that provides an element by that name, and then use it to create
the GstElement.

Obviously, creating a GstElement is insufficient, because for it to be
useful one will inevitably have to connect it to something, and
configure it.

For configuration, GstElements use GObject properties, so if I created
an element of the type "tee", provided by `gst-plugins-base', and I
wanted to configure it to work without any other element being attached
to it, I would set the property named "allow-not-linked" to `TRUE' as
follows:

  GstElement *tee = gst_element_factory_make ("tee", NULL);
  g_object_set (G_OBJECT (tee), "allow-not-linked", TRUE, NULL);

Where `g_object_set' is provided by the GObject library (an object
system for C that is free software, developed by GNOME) and `G_OBJECT'
is a macro that casts `tee' from GstElement to the type named `GObject'
after checking at run-time that the type of `tee' is correct.

Then, I have to put it in a GstBin (which is a container for various
GstElements) like so:

  gst_bin_add (GST_BIN (bin), tee);

Where `gst_bin_add' is a function provided by the GStreamer library,
`bin' is the bin, and `GST_BIN' is a cast macro similar to `G_OBJECT',
but checks that `bin' is of the type `GstBin' instead of `GstObject'.

Afterwards, I will have to "link" (note that this has nothing to do with
linking programs with object files) `tee' to some other element that
displays its output, like such:

  gst_element_link (tee, that_other_element);

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-23  7:07                   ` Po Lu
@ 2021-11-23 20:54                     ` Richard Stallman
  2021-11-24  0:32                       ` Po Lu
  0 siblings, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-11-23 20:54 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]


  > Here's how one would create a GStreamer element (and in doing so load a
  > plugin):

  >   GstElement *element = gst_element_factory_make ("factoryname", NULL);

  > Where "factoryname" is the name of the element factory you want.

This is incomplete -- I can't make sense of it.  It talks about things
I never heard of: "elements" and "element factories".

  > GStreamer will then find and load the shared library containing the
  > plugin that provides an element by that name, and then use it to create
  > the GstElement.

What does it mean for the plug-in to "provide" an "element"?

  > Obviously, creating a GstElement is insufficient, because for it to be
  > useful one will inevitably have to connect it to something, and
  > configure it.

What does that mean?

The story "The Gostak and the Doshes", by Miles Breuer, gives an idea
of how lost I feel at this point.

Is the argument "factoryname" the place where one specifies which format is
to be used?

You wrote doublequotes around that name.  What do those doublequotes mean?
Do they mean that the argument is supposed to have a C string as value?
Do they mean that the argument is supposed to be a C string constant?
Something else?

What data type is that argument?  Is it a C string?  Please show me a few
examples of real, valid, possible values for that argument.

What argument value would specify MPEG4?
What argument value would specify Webm?


How does the program control which set of plug-ins are permitted?
For instance, suppose the program wants to use only the "good" plug-ins.
What C code does it use to specify this?

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-23 20:54                     ` Richard Stallman
@ 2021-11-24  0:32                       ` Po Lu
  2021-11-25  5:32                         ` Richard Stallman
  0 siblings, 1 reply; 70+ messages in thread
From: Po Lu @ 2021-11-24  0:32 UTC (permalink / raw)
  To: Richard Stallman; +Cc: larsi, emacs-devel

Richard Stallman <rms@gnu.org> writes:

> This is incomplete -- I can't make sense of it.  It talks about things
> I never heard of: "elements" and "element factories".

"Elements" are the basic kind of data structure provided by plugins.
They can be linked to other elements, and perform actions on data
streams (such as decoding them into video or displaying the video
on-screen.)

Element factories search for elements by a given name inside plugins,
load plugins that contain said element, and use them to create the
element.

> What does it mean for the plug-in to "provide" an "element"?

It means the code in the element that processes data streams is provided
by the plugin (a shared library).

> Is the argument "factoryname" the place where one specifies which format is
> to be used?

Yes, as data formats are implemented as codec elements.

> You wrote doublequotes around that name.  What do those doublequotes mean?
> Do they mean that the argument is supposed to have a C string as value?

Yes.

> What data type is that argument?  Is it a C string?  Please show me a few
> examples of real, valid, possible values for that argument.

It is a C string.

> What argument value would specify MPEG4?

That would be "mp4mux".

> What argument value would specify Webm?

"webmmux".

> How does the program control which set of plug-ins are permitted?

As GStreamer doesn't load plugins by yourself, you do so by making sure
to only pass good plugin names to the element factory.

> For instance, suppose the program wants to use only the "good" plug-ins.
> What C code does it use to specify this?

As long as you don't explictly load bad plugins, you will be constrained
to the good plug-ins.

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-23  6:55                   ` Po Lu
@ 2021-11-24  4:28                     ` Richard Stallman
  0 siblings, 0 replies; 70+ messages in thread
From: Richard Stallman @ 2021-11-24  4:28 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > I don't know, but I was told by word-of-mouth that the GStreamer
  > developers do not hold the "bad" plugins to any standard, both technical
  > and freedom-wise.

  > As such, they don't guarantee that those plugins are free software.

If some of them are nonfree, we should not mention even the existence
of the category of "bad" plug-ins.

(It is too bad that they inform the users about them at all.)

  > Unfortunately, I don't know of a precise list of obstacles, but here's a
  > list of formats supported by the various plugins:

  >   - Microsoft ASF (possibly strangled by patents?)
  >   - DVD subtitles (though I don't know what precisely this is)
  >   - dvdlpcmdec (this possibly involves breaking DRM, could be illegal
  >     because of that)
  >   - RealMedia and RealAudio (patent encumbered, possible license problems)
  >   - "xingmux" (I couldn't find any information on this one)

Our way of looking at this kind of issue is very different from
theirs.  If a format is patented, we might have various different
responses to that, depending on the details of the situation.  But one
response we would certainly NOT have is, "You must not violate some
divine patent-holder's sacred rights."

If the plug-in violates the DMCA, we would not take the risk of
distributing it ourselves, but aside from that, we see nothing wrong
with its use on that score.  Breaking DRM is not wrong in the
slightest.  The injustice of DRM is in using it to restrict others.

However, if we don't know the situations for these plug-ins, I think
we have to avoid mentioning the ugly plug-ins unless we learned the situation
with each one.  And that's work we don't have an easy way to do.




-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-24  0:32                       ` Po Lu
@ 2021-11-25  5:32                         ` Richard Stallman
  2021-11-25  8:13                           ` Po Lu
  0 siblings, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-11-25  5:32 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > How does the program control which set of plug-ins are permitted?

  > As GStreamer doesn't load plugins by yourself, you do so by making sure
  > to only pass good plugin names to the element factory.

We're starting to close in on the crucial point.

Can you show me the code Emacs would use to control which plug-ins are
permitted?  In other words, how does a program "pass plug-in names"
to the element factory?

Does the program need to pass the list of good plug-in names?
If so, how does it get that list, and from where?

I'm trying to do a kind of security analysis of this.  Does passing
the right list of plug-in names depend on the cooperation of other
projects?  If so, which ones, and how would Emacs interact with them?
I want to make sure we are not volunerable to misbehavior on their
part.

If we'd need to trust some people, who are they, and what concretely
would we need to trust them to do?


-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-25  5:32                         ` Richard Stallman
@ 2021-11-25  8:13                           ` Po Lu
  2021-11-25 11:34                             ` Alexandre Garreau
  2021-11-27  4:08                             ` Richard Stallman
  0 siblings, 2 replies; 70+ messages in thread
From: Po Lu @ 2021-11-25  8:13 UTC (permalink / raw)
  To: Richard Stallman; +Cc: larsi, emacs-devel

Richard Stallman <rms@gnu.org> writes:

>   > As GStreamer doesn't load plugins by yourself, you do so by making sure
>   > to only pass good plugin names to the element factory.

> We're starting to close in on the crucial point.

> Can you show me the code Emacs would use to control which plug-ins are
> permitted?  In other words, how does a program "pass plug-in names"
> to the element factory?

In the function call to `gst_element_factory_make'.  We would have to
verify that the first argument, a C string, names a plugin included in
`gst-plugins-base' or `gst-plugins-good'.

> Does the program need to pass the list of good plug-in names?

No, it only has to refrain from passing a string that names a plugin
that is not free software to `gst_element_factory_make'.

> I'm trying to do a kind of security analysis of this.  Does passing
> the right list of plug-in names depend on the cooperation of other
> projects?

The GStreamer developers, who overlap greatly with other Freedesktop.org
projects.

> If so, which ones, and how would Emacs interact with them?  I want to
> make sure we are not volunerable to misbehavior on their part.

We would have to make sure that, when we decide to use a plugin in
Emacs, that it is part of `gst-plugins-base' or `gst-plugins-good'.

> If we'd need to trust some people, who are they, and what concretely
> would we need to trust them to do?

We would have to trust them to place only free plugins in
`gst-plugins-good' and `gst-plugins-base', and to document the plugins
correctly.

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-25  8:13                           ` Po Lu
@ 2021-11-25 11:34                             ` Alexandre Garreau
  2021-11-27  4:09                               ` Richard Stallman
  2021-11-27  4:08                             ` Richard Stallman
  1 sibling, 1 reply; 70+ messages in thread
From: Alexandre Garreau @ 2021-11-25 11:34 UTC (permalink / raw)
  To: emacs-devel; +Cc: Po Lu, larsi, Richard Stallman

Le Thursday, 25 November 2021, 09:13:06 CET Po Lu a écrit :
> Richard Stallman <rms@gnu.org> writes:
> >   > As GStreamer doesn't load plugins by yourself, you do so by making
> >   > sure
> >   > to only pass good plugin names to the element factory.
> > 
> > We're starting to close in on the crucial point.
> > 
> > Can you show me the code Emacs would use to control which plug-ins are
> > permitted?  In other words, how does a program "pass plug-in names"
> > to the element factory?
> 
> In the function call to `gst_element_factory_make'.  We would have to
> verify that the first argument, a C string, names a plugin included in
> `gst-plugins-base' or `gst-plugins-good'.

> > I'm trying to do a kind of security analysis of this.  Does passing
> > the right list of plug-in names depend on the cooperation of other
> > projects?
> 
> The GStreamer developers, who overlap greatly with other Freedesktop.org
> projects.

> We would have to trust them to place only free plugins in
> `gst-plugins-good' and `gst-plugins-base', and to document the plugins
> correctly.

Wait, it’s not needed to trust anyone.  There aren’t millions of plugins, 
maximum hundreds: it would be perfectly feasible to include the list of 
all of them into emacs.  The question is whether to *delegate* that work 
to GNOME, and the issue would then be when that list changes, what about 
updates, etc.

Btw, why whitelisting good and base, instead of blacklisting bad and ugly?  
Do we want to blacklist any unknown plugins?  GNU software, through 
configure for instance, has been known to ease not only classical hacking, 
by distros and full forks, but also by individual users, private 
configurations, etc. and still have all software interactions working…

Isn’t there a way to tell the license of the plugin inside each of him? if 
I remember well, GCC had some sort of a such thing (something to declare 
explicitely the plugin is under GPLv3 or GPLv3+), and I guess emacs too, 
right? It would be bad, I believe, if any individual programs a gst plugin 
for themselves (to begin, before to publish it), and cannot use it into 
emacs, even though it’s free… and neither a friend of them can, although 
they would be a free license to make the friend free…  it would mean to 
centralize the decision of “what plugins can run” into GNOME’s hand, and 
it’s actually, I believe, some sort of free-software, weak (*because* it’s 
free-software, then modifiable (btw it would be even better if that 
checking was done in lisp, or had some kind of configuration option for 
it: afaiu it’s illegal to distribute software with incompatible licenses, 
but not using one so, so an individual could still use emacs with some 
plugin that’s not juridically free-software because it has no license and 
the author is the only person to possess a copy of that plugin)) DRM…

On the other hand, the main risk here is if a distribution includes bad or 
ugly, then emacs would use proprietary software, not that the user 
programs or download one plugin, and that, by disfortune, the plugin the 
user chose is possibly proprietary, right? because since the user choose, 
well they can just as well choose a free software, and the 4 categories 
(good, base, bad, ugly) established by GNOME are outside of that…



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-25  8:13                           ` Po Lu
  2021-11-25 11:34                             ` Alexandre Garreau
@ 2021-11-27  4:08                             ` Richard Stallman
  2021-11-27  4:38                               ` Po Lu
  1 sibling, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-11-27  4:08 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > If so, which ones, and how would Emacs interact with them?  I want to
  > > make sure we are not volunerable to misbehavior on their part.

  > We would have to make sure that, when we decide to use a plugin in
  > Emacs, that it is part of `gst-plugins-base' or `gst-plugins-good'.


This leads me to more questions?

1. In the code you have currenly written, where does the plug-in name
come from?  In other words, how is it specified?

1a. Do Lisp programs specify it?

1a. Is there code in Emacs that figures out the right plug-in to use?
If so, what method does it use, and based on what information?

2. In the code you have currenly written, what prevents use of
a bad or ugly plug-in?

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-25 11:34                             ` Alexandre Garreau
@ 2021-11-27  4:09                               ` Richard Stallman
  2021-12-01 12:30                                 ` Dmitry Gutov
  0 siblings, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-11-27  4:09 UTC (permalink / raw)
  To: Alexandre Garreau; +Cc: luangruo, larsi, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > We would have to trust them to place only free plugins in
  > > `gst-plugins-good' and `gst-plugins-base', and to document the plugins
  > > correctly.

  > Wait, it’s not needed to trust anyone.  There aren’t millions of plugins, 
  > maximum hundreds: it would be perfectly feasible to include the list of 
  > all of them into emacs.  The question is whether to *delegate* that work 
  > to GNOME, and the issue would then be when that list changes, what about 
  > updates, etc.

Please state concretely what it is that you're disagreeing about.
Instead of arguing about whether to "trust GNOME", please tell
us what exactly the GStreamer developers did.  Then we can  see
whether that solves the problem.

  > Btw, why whitelisting good and base, instead of blacklisting bad and ugly? 

There are probably lots of nonfree plugins.  Trying to list them would
be a lot of work, and unreliable too.

If you want to use some plug-in that isn't in the good list, you can
edit the code and recompile.  Or patch in the string constant of your
choice with GDB.  Those take a little work, but they are not an obstacle
for a hacker.


-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-27  4:08                             ` Richard Stallman
@ 2021-11-27  4:38                               ` Po Lu
  2021-11-28  4:24                                 ` Richard Stallman
  0 siblings, 1 reply; 70+ messages in thread
From: Po Lu @ 2021-11-27  4:38 UTC (permalink / raw)
  To: Richard Stallman; +Cc: larsi, emacs-devel

Richard Stallman <rms@gnu.org> writes:

> This leads me to more questions?
>
> 1. In the code you have currenly written, where does the plug-in name
> come from?  In other words, how is it specified?

It's hard coded.

> 1a. Do Lisp programs specify it?

No.

> 1a. Is there code in Emacs that figures out the right plug-in to use?
> If so, what method does it use, and based on what information?

It doesn't dynamically determine plugins at all.  Instead, the name of
each plugin Emacs will use is hard coded inside C code.

> 2. In the code you have currenly written, what prevents use of
> a bad or ugly plug-in?

That nothing in the code will ever have a chance to load such a bad or
ugly plugin, as only the names of good plugins are specified.

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-27  4:38                               ` Po Lu
@ 2021-11-28  4:24                                 ` Richard Stallman
  2021-11-28  4:42                                   ` Po Lu
  0 siblings, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-11-28  4:24 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > 1. In the code you have currenly written, where does the plug-in name
  > > come from?  In other words, how is it specified?

  > It's hard coded.

Would you please show the code which gets the plug-in name and
specifies it?

  > > 1a. Is there code in Emacs that figures out the right plug-in to use?
  > > If so, what method does it use, and based on what information?

  > It doesn't dynamically determine plugins at all.  Instead, the name of
  > each plugin Emacs will use is hard coded inside C code.

That sounds safe.  Would you please show the code which
chooses the plug-in name to use in each case?

It starts to appear that this is ok, but I'd like to see those parts
and be sure.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-28  4:24                                 ` Richard Stallman
@ 2021-11-28  4:42                                   ` Po Lu
  2021-11-28  8:04                                     ` Yuri Khan
  2021-11-29  3:01                                     ` Richard Stallman
  0 siblings, 2 replies; 70+ messages in thread
From: Po Lu @ 2021-11-28  4:42 UTC (permalink / raw)
  To: Richard Stallman; +Cc: larsi, emacs-devel

Richard Stallman <rms@gnu.org> writes:

> That sounds safe.  Would you please show the code which
> chooses the plug-in name to use in each case?
>
> It starts to appear that this is ok, but I'd like to see those parts
> and be sure.

+static bool
+check_gstreamer_dependencies (void)
+{
+  GstRegistry *registry = gst_registry_get ();
+
+  return (gst_registry_find_feature (registry, "xvimagesink",
+				     GST_TYPE_ELEMENT_FACTORY)
+	  && gst_registry_find_feature (registry, "queue",
+					GST_TYPE_ELEMENT_FACTORY)
+	  && gst_registry_find_feature (registry, "videotestsrc",
+					GST_TYPE_ELEMENT_FACTORY)
+	  && gst_registry_find_feature (registry, "fakesink",
+					GST_TYPE_ELEMENT_FACTORY)
+	  && gst_registry_find_feature (registry, "tee",
+					GST_TYPE_ELEMENT_FACTORY));
+}

Here is where Emacs checks for the presence of the plugins it wants.
All of these plugins are in gst-plugins-base and gst-plugins-good.

+      xw->gst_source = gst_element_factory_make ("videotestsrc", NULL);
+      xw->gst_tee = gst_element_factory_make ("tee", NULL);

+      GstElement *fakesink = gst_element_factory_make ("fakesink", NULL);
+      GstElement *queue = gst_element_factory_make ("queue", NULL);

+	      xv->video_sink = gst_element_factory_make ("xvimagesink", NULL);
+	      xv->video_queue = gst_element_factory_make ("queue", NULL);

And here is where the plugins are created.  Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-28  4:42                                   ` Po Lu
@ 2021-11-28  8:04                                     ` Yuri Khan
  2021-11-28  8:16                                       ` Po Lu
  2021-11-29  3:02                                       ` Richard Stallman
  2021-11-29  3:01                                     ` Richard Stallman
  1 sibling, 2 replies; 70+ messages in thread
From: Yuri Khan @ 2021-11-28  8:04 UTC (permalink / raw)
  To: Po Lu; +Cc: Lars Magne Ingebrigtsen, Richard Stallman, Emacs developers

On Sun, 28 Nov 2021 at 11:43, Po Lu <luangruo@yahoo.com> wrote:

> +         && gst_registry_find_feature (registry, "videotestsrc",
> +                                       GST_TYPE_ELEMENT_FACTORY)

> +      xw->gst_source = gst_element_factory_make ("videotestsrc", NULL);

Here you are checking for and instantiating a known source element
that produces a fixed test image, but for any practical use (e.g.
playing a video from a web page or local file system) you’ll need to
instantiate a demultiplexer that knows how to split the original byte
stream into video, audio, and subtitle streams, and video and audio
decoders that handle the particular compression format. Some of those
could be patent-encumbered (and so end up in ugly) or poorly
maintained (bad). Are you planning to avoid those? If so, how? Also,
will the user be able to override the avoidance (“Yes I know those are
patent-encumbered and I have no problem with that”, or “Yes I know
that decoder might have a security vulnerability and I accept the
risk”)? If so, how?



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-28  8:04                                     ` Yuri Khan
@ 2021-11-28  8:16                                       ` Po Lu
  2021-11-29  3:02                                       ` Richard Stallman
  1 sibling, 0 replies; 70+ messages in thread
From: Po Lu @ 2021-11-28  8:16 UTC (permalink / raw)
  To: Yuri Khan; +Cc: Lars Magne Ingebrigtsen, Richard Stallman, Emacs developers

Yuri Khan <yuri.v.khan@gmail.com> writes:

> Here you are checking for and instantiating a known source element
> that produces a fixed test image, but for any practical use (e.g.
> playing a video from a web page or local file system) you’ll need to
> instantiate a demultiplexer that knows how to split the original byte
> stream into video, audio, and subtitle streams, and video and audio
> decoders that handle the particular compression format.

I will write individual pipelines for most of the common use cases,
taking care to use only plugins that are free software.

I do not plan on using playbins or any other elements that will load
plugins dynamically.

> Also, will the user be able to override the avoidance (“Yes I know
> those are patent-encumbered and I have no problem with that”, or “Yes
> I know that decoder might have a security vulnerability and I accept
> the risk”)? If so, how?

The user will not.  I don't want to make Emacs a tool that is more
convenient when used with proprietary software.

In short, I don't want Emacs to lead people who judge by convenience to
use proprietary software.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-28  4:42                                   ` Po Lu
  2021-11-28  8:04                                     ` Yuri Khan
@ 2021-11-29  3:01                                     ` Richard Stallman
  2021-11-29  3:12                                       ` Po Lu
  1 sibling, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-11-29  3:01 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > +  return (gst_registry_find_feature (registry, "xvimagesink",
  > +				     GST_TYPE_ELEMENT_FACTORY)
  > +	  && gst_registry_find_feature (registry, "queue",
  > +					GST_TYPE_ELEMENT_FACTORY)
  > +	  && gst_registry_find_feature (registry, "videotestsrc",
  > +					GST_TYPE_ELEMENT_FACTORY)
  > +	  && gst_registry_find_feature (registry, "fakesink",
  > +					GST_TYPE_ELEMENT_FACTORY)
  > +	  && gst_registry_find_feature (registry, "tee",
  > +					GST_TYPE_ELEMENT_FACTORY));

This takes me one step forward.  But you haven't explained what
this code does, and I can't recognize the meaning of anything.

What does gst_type_element_factory do?  It looks up something
in a registry, right?  What does a registry mean?

What is the meaning of the "xvimagesink" feature?
What is the meaning of the "queue" feature?
And so on?

Can you tell me an example that explains what this is doing and why?

  > Here is where Emacs checks for the presence of the plugins it wants.
  > All of these plugins are in gst-plugins-base and gst-plugins-good.

Are you saying that "xvimagesink", "queue", "videotestsrc", "fakesink"
and "tee" are the names of plug-ins?

If so, can you describe what each one does?

For instance, if the user specifies the URL of an mp4 file, which
of those plug-ins will Emacs tell GStreamer to load? 

Are you saying that those five plug-ins are the only five plug-ins
that Emacs will ever tell GStreamer to load?

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-28  8:04                                     ` Yuri Khan
  2021-11-28  8:16                                       ` Po Lu
@ 2021-11-29  3:02                                       ` Richard Stallman
  2021-11-29  7:31                                         ` Yuri Khan
  1 sibling, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-11-29  3:02 UTC (permalink / raw)
  To: Yuri Khan; +Cc: luangruo, larsi, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > +         && gst_registry_find_feature (registry, "videotestsrc",
  > > +                                       GST_TYPE_ELEMENT_FACTORY)

  > > +      xw->gst_source = gst_element_factory_make ("videotestsrc", NULL);
  ...

You seem to know something about this code.  Can you explain the
meaning of it?  What the dats structures are, and what these
operations actually do?

I'm trying to find out how Emacs determines which plug-ins to use
for any given argument supplied by the ueer.  And what do they depend on?
Does a given file format fully determine the plug-ins to use?

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-29  3:01                                     ` Richard Stallman
@ 2021-11-29  3:12                                       ` Po Lu
  2021-11-30  4:09                                         ` Richard Stallman
  0 siblings, 1 reply; 70+ messages in thread
From: Po Lu @ 2021-11-29  3:12 UTC (permalink / raw)
  To: Richard Stallman; +Cc: larsi, emacs-devel

Richard Stallman <rms@gnu.org> writes:

> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
>
>   > +  return (gst_registry_find_feature (registry, "xvimagesink",
>   > +				     GST_TYPE_ELEMENT_FACTORY)
>   > +	  && gst_registry_find_feature (registry, "queue",
>   > +					GST_TYPE_ELEMENT_FACTORY)
>   > +	  && gst_registry_find_feature (registry, "videotestsrc",
>   > +					GST_TYPE_ELEMENT_FACTORY)
>   > +	  && gst_registry_find_feature (registry, "fakesink",
>   > +					GST_TYPE_ELEMENT_FACTORY)
>   > +	  && gst_registry_find_feature (registry, "tee",
>   > +					GST_TYPE_ELEMENT_FACTORY));
>
> This takes me one step forward.  But you haven't explained what
> this code does, and I can't recognize the meaning of anything.

> What does gst_type_element_factory do?  It looks up something
> in a registry, right?  What does a registry mean?

Essentially, it searches for a plugin (an element factory) by a name in
the plugin registry, which is the data structure that tells GStreamer
how to look for plugins.

> What is the meaning of the "xvimagesink" feature?
> What is the meaning of the "queue" feature?

See below.

> And so on?
>
> Can you tell me an example that explains what this is doing and why?

> Are you saying that "xvimagesink", "queue", "videotestsrc", "fakesink"
> and "tee" are the names of plug-ins?
>
> If so, can you describe what each one does?

videotestsrc provides a test pattern.  xvimagesink displays the media to
an X window (solely an implementation detail, the window created is
internal to Emacs), fakesink is a plugin used to keep the data flow up
even if no Emacs window is currently displaying the xwidget, "tee"
allows a single video stream to display in multiple windows, and "queue"
provides an in-memory buffer that works in cooperation with a tee to
allow that kind of display.

> For instance, if the user specifies the URL of an mp4 file, which
> of those plug-ins will Emacs tell GStreamer to load? 

That feature is not implemented yet, and it will probably not be, as the
H.265 decoder is either ugly or bad (precisely which I don't remember).

> Are you saying that those five plug-ins are the only five plug-ins
> that Emacs will ever tell GStreamer to load?

Yes, in the future I will add other free plugins once I implement the
feature that allows it to load common free formats.

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-29  3:02                                       ` Richard Stallman
@ 2021-11-29  7:31                                         ` Yuri Khan
  2021-11-29  7:44                                           ` Po Lu
  2021-11-30  4:09                                           ` Richard Stallman
  0 siblings, 2 replies; 70+ messages in thread
From: Yuri Khan @ 2021-11-29  7:31 UTC (permalink / raw)
  To: Richard Stallman; +Cc: Po Lu, Lars Magne Ingebrigtsen, Emacs developers

On Mon, 29 Nov 2021 at 10:02, Richard Stallman <rms@gnu.org> wrote:

>   > > +         && gst_registry_find_feature (registry, "videotestsrc",
>   > > +                                       GST_TYPE_ELEMENT_FACTORY)
>
>   > > +      xw->gst_source = gst_element_factory_make ("videotestsrc", NULL);
>   ...
>
> You seem to know something about this code.

Disclaimer: I have not worked specifically with GStreamer, but I come
from a Windows background where I used to work with DirectShow. They
are technically similar.

> Can you explain the
> meaning of it?  What the dats structures are, and what these
> operations actually do?

I think the easiest way to explain media processing frameworks is to
make an analogy with UNIX pipes.

A typical UNIX process has a single input descriptor and two outputs
(stdout and stderr). You combine them in pipelines by connecting an
output of one program to the input of another.

Shell pipelines are typically linear or tree-like.

Media processing frameworks generalize this. Each “filter” or
“element” can have an arbitrary number of inputs and outputs, and they
are typed so the framework can check if the connection you are trying
to make is nonsensical. For example, you cannot meaningfully connect
an audio source to a video sink.

Filters and connections form a directed acyclic graph.

The videotestsrc element is a source. That is, it has no inputs, and
has one video output. For this particular filter, the output is a
fixed test image.

There is a sink filter that can display video. By connecting a
videotestsrc to a sink, you get a minimal complete graph that does
something.

A full graph for playing a video or audio clip will typically contain:

* A file or URL source. This knows the URL of the input file and
outputs a byte stream.

* A splitter or demultiplexer. This takes the byte stream and outputs
separate streams for any video, audio or subtitle tracks included.
Different container formats (e.g. AVI, MP4, Matroska, Ogg) require
different demux filters. (Closest UNIX analogy: zip and tar are
different containers, and use different programs.)
The user may not want all streams rendered — e.g. when watching a film
that contains audio tracks in English and Spanish, they will want just
one.

* Decoders for a subset of streams in the clip. (The user may not want
all streams rendered — e.g. when watching a film that contains audio
tracks in English and Spanish, they will want just one.) Each specific
video or audio compression format requires a different decoder filter.
(Analogy: deflate, xz, and bzip are different compression formats.) A
decoder takes a compressed stream from the demultiplexer and outputs
raw RGB or YCbCr video or PCM audio.

* “Renderers” or “sinks” for the decoded video and audio. These differ
by target video or audio subsystem (e.g. pulseaudio), hardware
acceleration capabilities, etc.


> I'm trying to find out how Emacs determines which plug-ins to use
> for any given argument supplied by the ueer.  And what do they depend on?
> Does a given file format fully determine the plug-ins to use?

A given file format (which is a combination of the container format
and compression formats of individual streams within) constrains the
set of possible rendering graphs.

A system may have multiple filters capable of filling each of the
roles listed above. In that case, the application (e.g. Emacs) can
choose between possibilities.

Frameworks have a way to try to automatically complete a rendering
graph for a source; I do not know all the details on how they resolve
ambiguities.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-29  7:31                                         ` Yuri Khan
@ 2021-11-29  7:44                                           ` Po Lu
  2021-11-29 21:12                                             ` Richard Stallman
  2021-11-30  4:09                                           ` Richard Stallman
  1 sibling, 1 reply; 70+ messages in thread
From: Po Lu @ 2021-11-29  7:44 UTC (permalink / raw)
  To: Yuri Khan; +Cc: Richard Stallman, Lars Magne Ingebrigtsen, Emacs developers

Yuri Khan <yuri.v.khan@gmail.com> writes:

> Frameworks have a way to try to automatically complete a rendering
> graph for a source; I do not know all the details on how they resolve
> ambiguities.

In GStreamer, the plugin used for that is the playbin plugin.  I refuse
to use that plugin and will instead write individual pipelines for
common playback formats, as the playbin likes to load arbitrary plugins
with no regard for whether or not they are free software.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-29  7:44                                           ` Po Lu
@ 2021-11-29 21:12                                             ` Richard Stallman
  2021-11-30  1:38                                               ` Po Lu
  0 siblings, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-11-29 21:12 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel, yuri.v.khan

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > In GStreamer, the plugin used for that is the playbin plugin.  I refuse
  > to use that plugin and will instead write individual pipelines for
  > common playback formats, as the playbin likes to load arbitrary plugins
  > with no regard for whether or not they are free software.

This sounds like the right approach, basically.

But I have a couple of ideas to suggest, to reduce the work.

1. Does playbin offer any hooks for the calling program to judge the plug-ins
it wants to load, and say "That plug-in is ok" or "That plug-in is no good"?
If it does, using them would be simpler and less work.

2. If playbin does not offer such a hook, we could patch playbin
to offer a suitable hook.  Maybe we could get that patch upstreamed.

3. We could make a copy of the code for playbin under another name,
and add those hooks to it.  We coulod link it staticly with Emacs.

WDYT?

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-29 21:12                                             ` Richard Stallman
@ 2021-11-30  1:38                                               ` Po Lu
  2021-11-30  8:30                                                 ` Yasushi SHOJI
  2021-12-01  7:04                                                 ` Richard Stallman
  0 siblings, 2 replies; 70+ messages in thread
From: Po Lu @ 2021-11-30  1:38 UTC (permalink / raw)
  To: Richard Stallman; +Cc: larsi, emacs-devel, yuri.v.khan

Richard Stallman <rms@gnu.org> writes:

> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
>
>   > In GStreamer, the plugin used for that is the playbin plugin.  I refuse
>   > to use that plugin and will instead write individual pipelines for
>   > common playback formats, as the playbin likes to load arbitrary plugins
>   > with no regard for whether or not they are free software.
>
> This sounds like the right approach, basically.
>
> But I have a couple of ideas to suggest, to reduce the work.
>
> 1. Does playbin offer any hooks for the calling program to judge the plug-ins
> it wants to load, and say "That plug-in is ok" or "That plug-in is no good"?
> If it does, using them would be simpler and less work.

I don't think so, but if someone else knows better, please chime in :)

> 2. If playbin does not offer such a hook, we could patch playbin
> to offer a suitable hook.  Maybe we could get that patch upstreamed.

Hmm, I will take a look at that.

> 3. We could make a copy of the code for playbin under another name,
> and add those hooks to it.  We coulod link it staticly with Emacs.

That would certainly complicate the Emacs building process a great deal.
Building GStreamer (including GStreamer plugins) is no easy task!



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-29  7:31                                         ` Yuri Khan
  2021-11-29  7:44                                           ` Po Lu
@ 2021-11-30  4:09                                           ` Richard Stallman
  1 sibling, 0 replies; 70+ messages in thread
From: Richard Stallman @ 2021-11-30  4:09 UTC (permalink / raw)
  To: Yuri Khan; +Cc: luangruo, larsi, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

Thanks for the very clear explanation.  Now I have a general overview
of the architecture of GStreamer.  It seems clean.

So each file (more generally, source)`, based on the combination of
container formats and stream formats it contains, requires a
collection of filters which correspond to them, and connections
between them.  Is that right?

So how can we make Emacs look at, and accept or reject, those filters
based on our nontechnical criteria?

Where is the code that figures out the filters and connections
for a given file?  Is that a general facility included in GSreamer?
Or is it part of the proposed change to Emacs?

If it is part of the proposed change to Emacs, could someone please
show me that code, and explain what the parts of it do?

If it is part of GStreamer, could someone please show me the
code in Emacs which calls that part of GStreamer, and explain for
me the arguments passed to it and the values it passes back?




-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-29  3:12                                       ` Po Lu
@ 2021-11-30  4:09                                         ` Richard Stallman
  2021-11-30  4:36                                           ` Po Lu
  0 siblings, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-11-30  4:09 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > Essentially, it searches for a plugin (an element factory) by a name in
  > the plugin registry, which is the data structure that tells GStreamer
  > how to look for plugins.

What code puts the data into that data stucture?
Is it done by a function in GStreamer that Emacs calls?
If so, what is its name, and where does Emacs call it from?

Can Emacs study the data structure after it is filled in?
Could Emacs delete some of the elements (i.e., put some
plug-ins off limits)?


-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-30  4:09                                         ` Richard Stallman
@ 2021-11-30  4:36                                           ` Po Lu
  2021-12-01  7:04                                             ` Richard Stallman
  0 siblings, 1 reply; 70+ messages in thread
From: Po Lu @ 2021-11-30  4:36 UTC (permalink / raw)
  To: Richard Stallman; +Cc: larsi, emacs-devel

Richard Stallman <rms@gnu.org> writes:

> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
>
>   > Essentially, it searches for a plugin (an element factory) by a name in
>   > the plugin registry, which is the data structure that tells GStreamer
>   > how to look for plugins.
>
> What code puts the data into that data stucture?
> Is it done by a function in GStreamer that Emacs calls?
> If so, what is its name, and where does Emacs call it from?

It is initialized by GStreamer when Emacs calls `gst_init'.  The data
structure is private to GStreamer, and as such, its contents are not
guaranteed to be stable.

> Can Emacs study the data structure after it is filled in?
> Could Emacs delete some of the elements (i.e., put some
> plug-ins off limits)?

Unfortunately, I don't think so.

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-30  1:38                                               ` Po Lu
@ 2021-11-30  8:30                                                 ` Yasushi SHOJI
  2021-11-30  9:29                                                   ` Po Lu
  2021-12-01  7:04                                                 ` Richard Stallman
  1 sibling, 1 reply; 70+ messages in thread
From: Yasushi SHOJI @ 2021-11-30  8:30 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, yuri.v.khan, Richard Stallman, emacs-devel

Hi Po,

On Tue, Nov 30, 2021 at 10:41 AM Po Lu <luangruo@yahoo.com> wrote:
> > 1. Does playbin offer any hooks for the calling program to judge the plug-ins
> > it wants to load, and say "That plug-in is ok" or "That plug-in is no good"?
> > If it does, using them would be simpler and less work.
>
> I don't think so, but if someone else knows better, please chime in :)

How about "element-setup"
https://gstreamer.freedesktop.org/documentation/playback/playbin.html?gi-language=c#playbin::element-setup

There is "license" field in `GstPlugin`:
https://gstreamer.freedesktop.org/documentation/gstreamer/gstplugin.html?gi-language=c#members

With these, I think you can craft what you want.

Best,
-- 
             yashi



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-30  8:30                                                 ` Yasushi SHOJI
@ 2021-11-30  9:29                                                   ` Po Lu
  2021-11-30 10:30                                                     ` Yasushi SHOJI
  0 siblings, 1 reply; 70+ messages in thread
From: Po Lu @ 2021-11-30  9:29 UTC (permalink / raw)
  To: Yasushi SHOJI; +Cc: larsi, yuri.v.khan, Richard Stallman, emacs-devel

Yasushi SHOJI <yasushi.shoji@gmail.com> writes:

> How about "element-setup"
> https://gstreamer.freedesktop.org/documentation/playback/playbin.html?gi-language=c#playbin::element-setup

Thanks!

> There is "license" field in `GstPlugin`:
> https://gstreamer.freedesktop.org/documentation/gstreamer/gstplugin.html?gi-language=c#members
>
> With these, I think you can craft what you want.

Thanks.  Do you know if the proprietary plugins have their `license'
fields labeled correctly?  What about patent-encumbered plugins?



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-30  9:29                                                   ` Po Lu
@ 2021-11-30 10:30                                                     ` Yasushi SHOJI
  0 siblings, 0 replies; 70+ messages in thread
From: Yasushi SHOJI @ 2021-11-30 10:30 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel, Richard Stallman, yuri.v.khan

On Tue, Nov 30, 2021 at 6:30 PM Po Lu <luangruo@yahoo.com> wrote:
> Thanks.  Do you know if the proprietary plugins have their `license'
> fields labeled correctly?  What about patent-encumbered plugins?

No I don't.
-- 
             yashi



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-30  1:38                                               ` Po Lu
  2021-11-30  8:30                                                 ` Yasushi SHOJI
@ 2021-12-01  7:04                                                 ` Richard Stallman
  2021-12-01  7:09                                                   ` Po Lu
  1 sibling, 1 reply; 70+ messages in thread
From: Richard Stallman @ 2021-12-01  7:04 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, yuri.v.khan, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > 1. Does playbin offer any hooks for the calling program to judge the plug-ins
  > > it wants to load, and say "That plug-in is ok" or "That plug-in is no good"?
  > > If it does, using them would be simpler and less work.

  > > 3. We could make a copy of the code for playbin under another name,
  > > and add those hooks to it.  We coulod link it staticly with Emacs.

  > That would certainly complicate the Emacs building process a great deal.
  > Building GStreamer (including GStreamer plugins) is no easy task!

We don't have to include the modified playbin _in GStreamer itself_.
We could make it self-contained by copying in whatever GStreamer
header material it depends on, so it will build easily as part of
Emacs.

However, releasing a modified GStreamer (modified in playbin) is
another alternative.  Free distros could use that version of
GStreamer.

The clean solution is to include those hooks in the main GStreamer
release; then Emacs can simply use them.  But we can't implement that
ourselves.  We can hope that the GStreamer developers will do so, but
until then, we don't have a responsibility to make this clean.  It is
ok if it includes kludges, as long as it doesn't make a lot of work
for us.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-30  4:36                                           ` Po Lu
@ 2021-12-01  7:04                                             ` Richard Stallman
  0 siblings, 0 replies; 70+ messages in thread
From: Richard Stallman @ 2021-12-01  7:04 UTC (permalink / raw)
  To: Po Lu; +Cc: larsi, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > It is initialized by GStreamer when Emacs calls `gst_init'.  The data
  > structure is private to GStreamer, and as such, its contents are not
  > guaranteed to be stable.

  > > Can Emacs study the data structure after it is filled in?
  > > Could Emacs delete some of the elements (i.e., put some
  > > plug-ins off limits)?

  > Unfortunately, I don't think so.

We can write unmodular code if that's the best solution.
We can have a file in Emacs that compiles using the GStreamer
header files -- perhaps syntactically transformed -- so it can
access this data structure and do what we want it to do.

We can write it so that it would be a reasonable added interface for
GStreamer, and ask them to install it.  But we will have a fallback if
they choose not to.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-20  8:05     ` Po Lu
  2021-11-20  8:16       ` Lars Ingebrigtsen
@ 2021-12-01  7:07       ` Richard Stallman
  2021-12-01  7:31         ` Po Lu
  2021-12-01  8:30         ` Alexandre Garreau
  1 sibling, 2 replies; 70+ messages in thread
From: Richard Stallman @ 2021-12-01  7:07 UTC (permalink / raw)
  To: Po Lu; +Cc: emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

I just saw some messages from Saturday that I had overlooked while
falling behind.

  > >   > It depends on GStreamer, gst-plugins-base, and gst-plugins-good and is
  > >   > thus a compile-time option.

  > The plugins that this change takes advantage of will only stream free
  > software, as it doesn't depend on gst-plugins-ugly or gst-plugins-bad.

Can you please show me how Emacs invokes get-plugins-good?
How does that function specify plugins to use?

  > > We also have to think about whether it is good or bad to introduce
  > > this nonmodularity.  What is better about showing videos this way,
  > > rather than just launching vlc in another window?

  > People seem to want that in Emacs.

That's not a very convincing reason.

If there is nothing bad about connecting Emacs to GStreamer, then
there's no reason to oppose it.  But if there is something bad,
it would take a good, strong reason to overcome that counter-reason.

  > Reading web pages that have embedded videos is quite common.

Those videos are very often links to Youtube, which depend on running
nonfree JS code.    If the aim of linking with GStreamer is to make
those embedded Youtube videos work in Emacs, we should not do it!

Unless we can bypass the JS code of Youtube.

We may be able to do that, if we make those embedded video links
automatically talk to invidious proxies rather than to youtube.

Can someone see how to implement that?

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-12-01  7:04                                                 ` Richard Stallman
@ 2021-12-01  7:09                                                   ` Po Lu
  0 siblings, 0 replies; 70+ messages in thread
From: Po Lu @ 2021-12-01  7:09 UTC (permalink / raw)
  To: Richard Stallman; +Cc: larsi, yuri.v.khan, emacs-devel

Richard Stallman <rms@gnu.org> writes:

> However, releasing a modified GStreamer (modified in playbin) is
> another alternative.  Free distros could use that version of
> GStreamer.

> The clean solution is to include those hooks in the main GStreamer
> release; then Emacs can simply use them.  But we can't implement that
> ourselves.  We can hope that the GStreamer developers will do so, but
> until then, we don't have a responsibility to make this clean.  It is
> ok if it includes kludges, as long as it doesn't make a lot of work
> for us.

I will certainly look into both of the options above, thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-12-01  7:07       ` Richard Stallman
@ 2021-12-01  7:31         ` Po Lu
  2021-12-01  8:30         ` Alexandre Garreau
  1 sibling, 0 replies; 70+ messages in thread
From: Po Lu @ 2021-12-01  7:31 UTC (permalink / raw)
  To: Richard Stallman; +Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

> Those videos are very often links to Youtube, which depend on running
> nonfree JS code.    If the aim of linking with GStreamer is to make
> those embedded Youtube videos work in Emacs, we should not do it!

> Unless we can bypass the JS code of Youtube.

Don't worry, we will not load the proprietary JavaScript, as shr (which
is the program that motivated me to work on this feature) is incapable
of running any JavaScript at all.

> We may be able to do that, if we make those embedded video links
> automatically talk to invidious proxies rather than to youtube.

> Can someone see how to implement that?

OTOH, that may actually be simple to implement, depending on the
interface exposed by invidious.

There are also programs such as youtube-dl, which allow to view YouTube
videos without running any JavaScript.

Perhaps we could use their interface instead, which other free software
such as mpv already makes use of.

But this is becoming something of a tangent.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-12-01  7:07       ` Richard Stallman
  2021-12-01  7:31         ` Po Lu
@ 2021-12-01  8:30         ` Alexandre Garreau
  1 sibling, 0 replies; 70+ messages in thread
From: Alexandre Garreau @ 2021-12-01  8:30 UTC (permalink / raw)
  To: Po Lu, emacs-devel; +Cc: rms, emacs-devel

Le merkredo, 1-a de decembro 2021, 8-a horo kaj 7:47 CET Richard Stallman 
a écrit :
> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
> 
> I just saw some messages from Saturday that I had overlooked while
> falling behind.
> 
>   > >   > It depends on GStreamer, gst-plugins-base, and
>   > >   > gst-plugins-good and is
>   > >   > thus a compile-time option.
>   > 
>   > The plugins that this change takes advantage of will only stream
>   > free
>   > software, as it doesn't depend on gst-plugins-ugly or
>   > gst-plugins-bad.
> 
> Can you please show me how Emacs invokes get-plugins-good?
> How does that function specify plugins to use?
> 
>   > > We also have to think about whether it is good or bad to introduce
>   > > this nonmodularity.  What is better about showing videos this way,
>   > > rather than just launching vlc in another window?
>   > 
>   > People seem to want that in Emacs.
> 
> That's not a very convincing reason.

Windowing is confusing, while embeding is more ergonomic, because it’s 
more straightforward to figure out/remember where things are, since they’re 
more related/constrained

>   > Reading web pages that have embedded videos is quite common.
> 
> Those videos are very often links to Youtube, which depend on running
> nonfree JS code.    If the aim of linking with GStreamer is to make
> those embedded Youtube videos work in Emacs, we should not do it!
> 
> Unless we can bypass the JS code of Youtube.
> 
> We may be able to do that, if we make those embedded video links
> automatically talk to invidious proxies rather than to youtube.
> 
> Can someone see how to implement that?

It would be better to mimick mpv or vlc in that respect, and use youtube-
dl or libquvi to get the direct links to the streams, and give that to 
gstreamer.  It would avoid an intermediary (what if the invidious proxy is 
malicious, requires a proprietary captcha, is overloaded, or stops 
working?).  Plus youtube-dl would allow that to work with most streaming 
platforms, not only youtube.  And youtube-dl devs are really active and do 
most of the up-to-date work of reverse engineering to keep those working 
correctly.

Isn’t that how ViewTube used to work?



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-11-27  4:09                               ` Richard Stallman
@ 2021-12-01 12:30                                 ` Dmitry Gutov
  2021-12-01 17:53                                   ` Arthur Miller
  0 siblings, 1 reply; 70+ messages in thread
From: Dmitry Gutov @ 2021-12-01 12:30 UTC (permalink / raw)
  To: rms, Alexandre Garreau; +Cc: luangruo, larsi, emacs-devel

This whole thread is very puzzling.

On 27.11.2021 07:09, Richard Stallman wrote:
>    > > We would have to trust them to place only free plugins in
>    > > `gst-plugins-good' and `gst-plugins-base', and to document the plugins
>    > > correctly.
> 
>    > Wait, it’s not needed to trust anyone.  There aren’t millions of plugins,
>    > maximum hundreds: it would be perfectly feasible to include the list of
>    > all of them into emacs.  The question is whether to*delegate*  that work
>    > to GNOME, and the issue would then be when that list changes, what about
>    > updates, etc.
> 
> Please state concretely what it is that you're disagreeing about.
> Instead of arguing about whether to "trust GNOME", please tell
> us what exactly the GStreamer developers did.  Then we can  see
> whether that solves the problem.

Whatever plugins are available on the user's system, are a result of the 
distro including them (which, by default, means only the "good" ones get 
in), as well as the ones the user installed explicitly. Possibly "bad" 
too (the less well-written ones).

The "licensing problems" with "ugly" plugins are more on the side of 
"not being distributed under LGPL", rather not being free software. Or 
maybe having dependencies like that, because I wasn't able to find an 
example of the former.

More likely, they are in that category because of the video/image 
formats being patent encumbered (so the distros can't easily distribute 
that code). But if the user has installed such a plugin manually, who 
are we to deny them the pleasure of viewing asf, realmedia or whatever?

>    > Btw, why whitelisting good and base, instead of blacklisting bad and ugly?
> 
> There are probably lots of nonfree plugins.  Trying to list them would
> be a lot of work, and unreliable too.

If you were designing the 'shell-command' command in Emacs today, would 
you start with a whitelist of all known free software programs and 
refuse to call anything not from that list?



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-12-01 12:30                                 ` Dmitry Gutov
@ 2021-12-01 17:53                                   ` Arthur Miller
  2021-12-02  0:51                                     ` Po Lu
  2021-12-02  2:47                                     ` chad
  0 siblings, 2 replies; 70+ messages in thread
From: Arthur Miller @ 2021-12-01 17:53 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: luangruo, larsi, rms, Alexandre Garreau, emacs-devel

Dmitry Gutov <dgutov@yandex.ru> writes:

> This whole thread is very puzzling.
>
> On 27.11.2021 07:09, Richard Stallman wrote:
>>    > > We would have to trust them to place only free plugins in
>>    > > `gst-plugins-good' and `gst-plugins-base', and to document the plugins
>>    > > correctly.
>>    > Wait, it’s not needed to trust anyone.  There aren’t millions of plugins,
>>    > maximum hundreds: it would be perfectly feasible to include the list of
>>    > all of them into emacs.  The question is whether to*delegate*  that work
>>    > to GNOME, and the issue would then be when that list changes, what about
>>    > updates, etc.
>> Please state concretely what it is that you're disagreeing about.
>> Instead of arguing about whether to "trust GNOME", please tell
>> us what exactly the GStreamer developers did.  Then we can  see
>> whether that solves the problem.
>
> Whatever plugins are available on the user's system, are a result of the distro
> including them (which, by default, means only the "good" ones get in), as well
> as the ones the user installed explicitly. Possibly "bad" too (the less
> well-written ones).

That, but, it still does not mean that proprietary codecs will not be present on
the OS even if a distro does not include them, even on a libre system.

A user can always install proprietary plugin(s), so it realy is up to user
consciusness.

If I remember well, people could just copy prorietary codecs from their Windows
systems and install them in gnu/linux to enable them in gstreamer, so there is
no guarantee that gstreamer won't play those.

I would really like to see gstreamer in Emacs, but I am not sure you can truly
prevent gstreamer from loading proprietary codecs.

https://lwn.net/Articles/217583/

Gstreamer seems to support those in order to support users who legaly purchase
licenses to proprietary formats, so getting this off gstreamer means probably
patching gstreamer and distributing own binary with Emacs. Prohibition should
maybe not be a goal?

> If you were designing the 'shell-command' command in Emacs today, would you
> start with a whitelist of all known free software programs and refuse to call
> anything not from that list?

Indeed. And how much are proprietary codecs different from linking Emacs to all
the system libraries in "unjust" systems, i.e. Windows and MacOS?

I think benefits of Emacs being able to play media outweigh the cons. In the
very end, if someone is bying DRM protected media, well, it is his/her personal
choice. In all these years with computing and DRM I have yet not purchased a
single DRM protected piece of software, beside few games back in time when they
used to come in paperboxes on CDs. I agree DRM is crap, but I also think it is a
personal choice people should make on their own.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-12-01 17:53                                   ` Arthur Miller
@ 2021-12-02  0:51                                     ` Po Lu
  2021-12-02  2:47                                     ` chad
  1 sibling, 0 replies; 70+ messages in thread
From: Po Lu @ 2021-12-02  0:51 UTC (permalink / raw)
  To: Arthur Miller; +Cc: Dmitry Gutov, larsi, rms, Alexandre Garreau, emacs-devel

Arthur Miller <arthur.miller@live.com> writes:

> If I remember well, people could just copy prorietary codecs from their Windows
> systems and install them in gnu/linux to enable them in gstreamer, so there is
> no guarantee that gstreamer won't play those.

If we do not explictly load them, they will not be loaded.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: GStreamer xwidget
  2021-12-01 17:53                                   ` Arthur Miller
  2021-12-02  0:51                                     ` Po Lu
@ 2021-12-02  2:47                                     ` chad
  1 sibling, 0 replies; 70+ messages in thread
From: chad @ 2021-12-02  2:47 UTC (permalink / raw)
  To: Arthur Miller
  Cc: Richard Stallman, EMACS development team, Po Lu,
	Alexandre Garreau, Dmitry Gutov, Lars Ingebrigtsen

[-- Attachment #1: Type: text/plain, Size: 598 bytes --]

On Wed, Dec 1, 2021 at 9:54 AM Arthur Miller <arthur.miller@live.com> wrote:

> I would really like to see gstreamer in Emacs, but I am not sure you can
> truly
> prevent gstreamer from loading proprietary codecs.
>

This is primarily true if the code uses the playbin module for gstreamer,
which most people do, and Po Lu is explicitly NOT doing. The manual process
they intend will instead miss some codecs (etc) that are supported on the
system, but it won't unknowingly load proprietary code (well, I guess
modulo some extreme behavior on the system maintainer's part).

Hope that helps,
~Chad

[-- Attachment #2: Type: text/html, Size: 982 bytes --]

^ permalink raw reply	[flat|nested] 70+ messages in thread

end of thread, other threads:[~2021-12-02  2:47 UTC | newest]

Thread overview: 70+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <87ee7cq2mu.fsf.ref@yahoo.com>
2021-11-19  2:51 ` GStreamer xwidget Po Lu
2021-11-19  4:01   ` T.V Raman
2021-11-19  4:21     ` Po Lu
2021-11-19  5:38   ` Lars Ingebrigtsen
2021-11-19  5:49     ` Po Lu
2021-11-19  6:19       ` Lars Ingebrigtsen
2021-11-19  6:37         ` Po Lu
2021-11-19  6:53           ` Lars Ingebrigtsen
2021-11-19 13:03           ` Eli Zaretskii
2021-11-19 13:07             ` Po Lu
2021-11-19 13:22               ` Eli Zaretskii
2021-11-19 13:33                 ` Po Lu
2021-11-19 13:45                   ` Eli Zaretskii
2021-11-20  5:07   ` Po Lu
2021-11-20  7:23     ` Eli Zaretskii
2021-11-20  7:27       ` Po Lu
2021-11-21  5:19     ` Richard Stallman
2021-11-21  6:53       ` Lars Ingebrigtsen
2021-11-22  4:31         ` Richard Stallman
2021-11-20  7:42   ` Richard Stallman
2021-11-20  8:05     ` Po Lu
2021-11-20  8:16       ` Lars Ingebrigtsen
2021-11-21  5:18         ` Richard Stallman
2021-11-21  5:27           ` Po Lu
2021-11-22  4:31             ` Richard Stallman
2021-11-22  4:41               ` Po Lu
2021-11-23  6:11                 ` Richard Stallman
2021-11-23  7:07                   ` Po Lu
2021-11-23 20:54                     ` Richard Stallman
2021-11-24  0:32                       ` Po Lu
2021-11-25  5:32                         ` Richard Stallman
2021-11-25  8:13                           ` Po Lu
2021-11-25 11:34                             ` Alexandre Garreau
2021-11-27  4:09                               ` Richard Stallman
2021-12-01 12:30                                 ` Dmitry Gutov
2021-12-01 17:53                                   ` Arthur Miller
2021-12-02  0:51                                     ` Po Lu
2021-12-02  2:47                                     ` chad
2021-11-27  4:08                             ` Richard Stallman
2021-11-27  4:38                               ` Po Lu
2021-11-28  4:24                                 ` Richard Stallman
2021-11-28  4:42                                   ` Po Lu
2021-11-28  8:04                                     ` Yuri Khan
2021-11-28  8:16                                       ` Po Lu
2021-11-29  3:02                                       ` Richard Stallman
2021-11-29  7:31                                         ` Yuri Khan
2021-11-29  7:44                                           ` Po Lu
2021-11-29 21:12                                             ` Richard Stallman
2021-11-30  1:38                                               ` Po Lu
2021-11-30  8:30                                                 ` Yasushi SHOJI
2021-11-30  9:29                                                   ` Po Lu
2021-11-30 10:30                                                     ` Yasushi SHOJI
2021-12-01  7:04                                                 ` Richard Stallman
2021-12-01  7:09                                                   ` Po Lu
2021-11-30  4:09                                           ` Richard Stallman
2021-11-29  3:01                                     ` Richard Stallman
2021-11-29  3:12                                       ` Po Lu
2021-11-30  4:09                                         ` Richard Stallman
2021-11-30  4:36                                           ` Po Lu
2021-12-01  7:04                                             ` Richard Stallman
2021-11-23  6:11                 ` Richard Stallman
2021-11-23  6:55                   ` Po Lu
2021-11-24  4:28                     ` Richard Stallman
2021-11-21  6:52           ` Lars Ingebrigtsen
2021-11-21 14:45             ` Arthur Miller
2021-11-23  6:09               ` Richard Stallman
2021-11-22  4:31             ` Richard Stallman
2021-12-01  7:07       ` Richard Stallman
2021-12-01  7:31         ` Po Lu
2021-12-01  8:30         ` Alexandre Garreau

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).