[gnome-subtitles] Switched to gtksink to display gstreamer video
- From: Pedro Castro <pcastro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-subtitles] Switched to gtksink to display gstreamer video
- Date: Sun, 1 Jul 2018 17:51:45 +0000 (UTC)
commit 18cb1460594b558f0f70dce1c6102ad716d8d4e3
Author: Pedro Castro <pedro gnomesubtitles org>
Date: Sun Jul 1 18:48:26 2018 +0100
Switched to gtksink to display gstreamer video
Gstreamer was previously embedded by using gst-video-overlay
and using the Xid of the UI's socket widget. This presented
a number of flows. The implementation now uses gtksink, together
with the gst-playbin element that was already in use.
src/External/GStreamerPlaybin/Engine.cs | 71 ++++++++++--------
src/External/GStreamerPlaybin/main.c | 87 +++++++++++++---------
.../PlayerCouldNotInitiateEngineException.cs | 5 +-
src/GnomeSubtitles/Ui/VideoPreview/Player.cs | 55 ++++++++------
4 files changed, 132 insertions(+), 86 deletions(-)
---
diff --git a/src/External/GStreamerPlaybin/Engine.cs b/src/External/GStreamerPlaybin/Engine.cs
index c7c1691..d1ef937 100644
--- a/src/External/GStreamerPlaybin/Engine.cs
+++ b/src/External/GStreamerPlaybin/Engine.cs
@@ -1,7 +1,7 @@
/*
Copyright (C) 2007 Goran Sterjov, Pedro Castro
- Copyright (C) 2011 Pedro Castro
+ Copyright (C) 2011-2018 Pedro Castro
This file is part of the GStreamer Playbin Wrapper.
Derived from Fuse.
@@ -21,11 +21,27 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-
-
+using Gtk;
using System;
using System.Runtime.InteropServices;
+/*
+ * There are a number of ways to integrate gstreamer into an application. This implementation uses a
gstreamer
+ * playbin (which is a gstreamer pipeline with a number of additional features) with a video sink set to a
+ * gtksink (instead of the default "auto" video sink). Once initialized, this video sink allows returning
+ * its GtkWidget, which is then added to the application UI. Most of the hard work is done in the auxiliary
+ * gstreamer_playbin C library, whereas here we use bindings to that library.
+ *
+ * Previously, this implementation relied on gst_video_overlay_set_window_handle which received the X11 id
+ * of the Gdk.Window to which we wanted gstreamer to attach to, however this implementation presented many
+ * glitches which weren't simple to solve (ex: screen went black when switching between apps, and also when
+ * updating the current subtitle while the video was paused).
+ *
+ * Reference to other ways to implement gstreamer into a GTK application:
+ * - https://github.com/GNOME/clutter-gst (does a lot more than a simple integration; used in Totem)
+ * - https://developer.gnome.org/totem/stable/BaconVideoWidget.html (Totem bacon video widget)
+ */
+
namespace GStreamer
{
@@ -95,11 +111,11 @@ namespace GStreamer
/// Load the GStreamer library and attach it
/// to the specified window.
/// </summary>
- public bool Initiate (ulong x_window_id)
+ public bool Initiate ()
{
// load the gstreamer library
- IntPtr ptr = gst_binding_init (x_window_id);
+ IntPtr ptr = gst_binding_init ();
if(ptr == IntPtr.Zero)
{
@@ -124,19 +140,10 @@ namespace GStreamer
status = MediaStatus.Unloaded;
+
return true;
}
-
-
- /// <summary>
- /// Load the GStreamer library.
- /// </summary>
- public bool Initiate ()
- {
- return Initiate (0);
- }
-
-
+
/// <summary>
/// Disposes the GStreamer library.
@@ -200,13 +207,13 @@ namespace GStreamer
}
}
- /// <summary>
- /// Changes the window to which video playback is attached to.
- /// </summary>
- public void SetWindow (ulong window_id)
- {
- gst_binding_set_xid (engine, window_id);
- }
+ ///// <summary>
+ ///// Changes the window to which video playback is attached to.
+ ///// </summary>
+ //public void SetWindow (ulong window_id)
+ //{
+ // gst_binding_set_xid (engine, window_id);
+ //}
@@ -374,6 +381,11 @@ namespace GStreamer
{
get { return status; }
}
+
+ public Widget GetVideoWidget ()
+ {
+ return new Widget(gst_binding_get_video_widget(engine));
+ }
@@ -458,8 +470,7 @@ namespace GStreamer
else
return null;
}
-
-
+
// private convenience properties
bool isPlaying { get{ return status == MediaStatus.Playing; } }
@@ -468,7 +479,7 @@ namespace GStreamer
// core engine functions
[DllImport("gstreamer_playbin")]
- static extern IntPtr gst_binding_init (ulong xwin);
+ static extern IntPtr gst_binding_init ();
[DllImport("gstreamer_playbin")]
static extern void gst_binding_deinit (HandleRef play);
[DllImport("gstreamer_playbin")]
@@ -479,8 +490,8 @@ namespace GStreamer
static extern void gst_binding_pause (HandleRef play);
[DllImport("gstreamer_playbin")]
static extern void gst_binding_unload (HandleRef play);
- [DllImport("gstreamer_playbin")]
- static extern void gst_binding_set_xid (HandleRef play, ulong xid);
+ //[DllImport("gstreamer_playbin")]
+ //static extern void gst_binding_set_xid (HandleRef play, ulong xid);
// engine property functions
@@ -520,9 +531,11 @@ namespace GStreamer
[DllImport("gstreamer_playbin")]
static extern void gst_binding_set_visual (HandleRef play, string vis_name);
-
[DllImport("gstreamer_playbin")]
static extern IntPtr gst_binding_get_visuals_list (HandleRef play);
+
+ [DllImport("gstreamer_playbin")]
+ static extern IntPtr gst_binding_get_video_widget (HandleRef play);
}
diff --git a/src/External/GStreamerPlaybin/main.c b/src/External/GStreamerPlaybin/main.c
index dce6bf9..5f91415 100644
--- a/src/External/GStreamerPlaybin/main.c
+++ b/src/External/GStreamerPlaybin/main.c
@@ -22,7 +22,7 @@
*/
#include <gst/gst.h>
-#include <gst/video/videooverlay.h>
+//#include <gst/video/videooverlay.h>
#include <gst/tag/tag.h>
#include <string.h>
@@ -63,8 +63,9 @@ struct gstTag
struct gstPlay
{
GstElement *element;
- gulong xid;
- GstVideoOverlay *overlay;
+ GstElement *video_element;
+// gulong xid;
+// GstVideoOverlay *overlay;
gchar *vis_name;
@@ -86,23 +87,23 @@ gboolean gst_binding_load_video_info(gstPlay *play);
gboolean gst_binding_has_video(gstPlay *play);
gboolean gst_binding_has_audio(gstPlay *play);
-static GstBusSyncReply
-gst_sync_watch(GstBus *bus, GstMessage *message, gpointer data)
-{
- gstPlay *play = (gstPlay *)data;
- if (play == NULL)
- return FALSE;
-
- if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ELEMENT)
- {
- if (gst_is_video_overlay_prepare_window_handle_message(message))
- {
- play->overlay = GST_VIDEO_OVERLAY(GST_MESSAGE_SRC(message));
- gst_video_overlay_set_window_handle(play->overlay, play->xid);
- }
- }
- return TRUE;
-}
+// static GstBusSyncReply
+// gst_sync_watch(GstBus *bus, GstMessage *message, gpointer data)
+// {
+// gstPlay *play = (gstPlay *)data;
+// if (play == NULL)
+// return FALSE;
+
+// if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ELEMENT)
+// {
+// if (gst_is_video_overlay_prepare_window_handle_message(message))
+// {
+// play->overlay = GST_VIDEO_OVERLAY(GST_MESSAGE_SRC(message));
+// //gst_video_overlay_set_window_handle(play->overlay, play->xid);
+// }
+// }
+// return TRUE;
+// }
static gboolean
gst_async_watch(GstBus *bus, GstMessage *message, gpointer data)
@@ -230,7 +231,8 @@ gboolean isValid(gstPlay *play)
}
// initiates gstreamer as a playbin pipeline
-gstPlay *gst_binding_init(gulong xwin)
+//gstPlay *gst_binding_init(gulong xwin)
+gstPlay *gst_binding_init()
{
gstPlay *play = g_new0(gstPlay, 1);
@@ -238,16 +240,33 @@ gstPlay *gst_binding_init(gulong xwin)
play->element = gst_element_factory_make("playbin", "play");
if (play->element == NULL)
return NULL;
- play->xid = xwin;
+
+// play->xid = xwin;
+
+ play->video_element = gst_element_factory_make ("gtksink", "gtksink");
+ if (play->video_element == NULL) {
+ return NULL;
+ }
+
+ g_object_set(G_OBJECT(play->element), "video-sink", play->video_element, NULL);
- gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(play->element)),
- gst_sync_watch, play, NULL);
+// gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(play->element)),
+// gst_sync_watch, play, NULL);
gst_bus_add_watch(gst_pipeline_get_bus(GST_PIPELINE(play->element)),
gst_async_watch, play);
return play;
}
+/* Gets the GtkWidget inside the gtksink video element */
+void *gst_binding_get_video_widget(gstPlay *play)
+{
+ void *widget;
+ g_object_get (play->video_element, "widget", &widget, NULL);
+ return widget;
+}
+
+
// releases any references to gstreamer
void gst_binding_deinit(gstPlay *play)
{
@@ -520,15 +539,15 @@ gboolean gst_binding_load_video_info(gstPlay *play)
return FALSE;
}
-void gst_binding_set_xid(gstPlay *play, gulong xid)
-{
- if (play == NULL)
- return;
+// void gst_binding_set_xid(gstPlay *play, gulong xid)
+// {
+// if (play == NULL)
+// return;
- play->xid = xid;
- if (play->overlay != NULL && GST_IS_VIDEO_OVERLAY(play->overlay))
- gst_video_overlay_set_window_handle(play->overlay, xid);
-}
+// play->xid = xid;
+// if (play->overlay != NULL && GST_IS_VIDEO_OVERLAY(play->overlay))
+// gst_video_overlay_set_window_handle(play->overlay, xid);
+// }
void gst_binding_set_eos_cb(gstPlay *play, eosCallback cb)
{
@@ -616,8 +635,8 @@ done:
static void
setup_vis(gstPlay *play)
{
- if (play->xid == 0)
- return;
+// if (play->xid == 0)
+// return;
GstElement *vis_bin = NULL;
GstElement *vis_element = NULL;
diff --git a/src/GnomeSubtitles/Ui/VideoPreview/Exceptions/PlayerCouldNotInitiateEngineException.cs
b/src/GnomeSubtitles/Ui/VideoPreview/Exceptions/PlayerCouldNotInitiateEngineException.cs
index 3cb5b43..8e5bd87 100644
--- a/src/GnomeSubtitles/Ui/VideoPreview/Exceptions/PlayerCouldNotInitiateEngineException.cs
+++ b/src/GnomeSubtitles/Ui/VideoPreview/Exceptions/PlayerCouldNotInitiateEngineException.cs
@@ -1,6 +1,6 @@
/*
* This file is part of Gnome Subtitles.
- * Copyright (C) 2008 Pedro Castro
+ * Copyright (C) 2008-2018 Pedro Castro
*
* Gnome Subtitles is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +23,9 @@ namespace GnomeSubtitles.Ui.VideoPreview.Exceptions {
public class PlayerCouldNotInitiateEngineException : ApplicationException {
+ public PlayerCouldNotInitiateEngineException (string message) : base(message) {
+ }
+
}
}
diff --git a/src/GnomeSubtitles/Ui/VideoPreview/Player.cs b/src/GnomeSubtitles/Ui/VideoPreview/Player.cs
index 35a0dee..73a6874 100644
--- a/src/GnomeSubtitles/Ui/VideoPreview/Player.cs
+++ b/src/GnomeSubtitles/Ui/VideoPreview/Player.cs
@@ -17,7 +17,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-using Gdk;
using GnomeSubtitles.Ui.VideoPreview.Exceptions;
using GStreamer;
using Gtk;
@@ -34,7 +33,7 @@ public delegate void VideoDurationEventHandler (TimeSpan duration);
public class Player {
private AspectFrame frame = null;
- private Socket socket = null;
+ //private Socket socket = null;
private Playbin playbin = null;
private PlayerPositionWatcher position = null;
private bool hasFoundDuration = false;
@@ -51,11 +50,11 @@ public class Player {
public Player (AspectFrame aspectFrame) {
this.frame = aspectFrame;
- InitializeSocket();
+ //InitializeSocket();
InitializePositionWatcher();
InitializePlaybin();
}
-
+
/* Events */
public event PlayerErrorEventHandler Error;
@@ -180,31 +179,43 @@ public class Player {
/* Private members */
- private void InitializeSocket () {
- socket = new Socket();
- /* Set the socket background color. If we don't do this, the socket/video
- * area will show a copy of the UI elements (menu, labels, other
- * components) when the video isn't loaded.
- */
- RGBA black = new RGBA();
- black.Red = 0;
- black.Green = 0;
- black.Blue = 0;
- black.Alpha = 1;
- socket.OverrideBackgroundColor(StateFlags.Normal, black);
+ //private void InitializeSocket () {
+ // socket = new Socket();
- frame.Child = socket;
+ // /* Set the socket background color. If we don't do this, the socket/video
+ // * area will show a copy of the UI elements (menu, labels, other
+ // * components) when the video isn't loaded.
+ // */
+ // RGBA black = new RGBA();
+ // black.Red = 0;
+ // black.Green = 0;
+ // black.Blue = 0;
+ // black.Alpha = 1;
+ // socket.OverrideBackgroundColor(StateFlags.Normal, black);
+ // socket.DoubleBuffered = false;
- socket.Realize();
- socket.Show();
- }
+ // frame.Child = socket;
+
+ // socket.Realize();
+ // socket.Show();
+ //}
private void InitializePlaybin () {
playbin = new Playbin();
- if (!playbin.Initiate(socket.Id))
- throw new PlayerCouldNotInitiateEngineException();
+ if (!playbin.Initiate()) {
+ throw new PlayerCouldNotInitiateEngineException("Unable to initiate the playbin
engine");
+ }
+
+ Widget videoWidget = playbin.GetVideoWidget();
+ if (videoWidget == null) {
+ throw new PlayerCouldNotInitiateEngineException("Unable to get the video widget from
the playbin engine");
+ }
+
+ frame.Child = videoWidget;
+ videoWidget.Realize();
+ videoWidget.Show();
playbin.Error += OnPlaybinError;
playbin.EndOfStream += OnPlaybinEndOfStream;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]