mediastream: Add gtk_media_stream_realize/unrealize()
authorBenjamin Otte <otte@redhat.com>
Sun, 18 Mar 2018 02:20:02 +0000 (03:20 +0100)
committerBenjamin Otte <otte@redhat.com>
Sun, 18 Mar 2018 20:01:23 +0000 (21:01 +0100)
This allows widget to attach their streams to GdkWindow(s)

The idea is to allow attaching a stream to windowing system(s) so the
stream can make use of its resources, in particular GL contexts.

I am however unsure what to attach to:
- GtkWindow
- GdkWindow
- GtkWidget
- GskRenderer
Each of these provide advantages and disadvantages.

So I'm very much open to better suggestions.

gtk/gtkmediastream.c
gtk/gtkmediastream.h
gtk/gtkvideo.c

index aadec8562289c9050f829a25223c4d582b84c97a..0688ed199c6b0eeb445c91c6734adf4b9d5092c9 100644 (file)
@@ -127,6 +127,18 @@ gtk_media_stream_default_update_audio (GtkMediaStream *self,
 {
 }
 
+static void
+gtk_media_stream_default_realize (GtkMediaStream *self,
+                                  GdkWindow      *window)
+{
+}
+
+static void
+gtk_media_stream_default_unrealize (GtkMediaStream *self,
+                                    GdkWindow      *window)
+{
+}
+
 static void
 gtk_media_stream_set_property (GObject      *object,
                                guint         prop_id,
@@ -260,6 +272,8 @@ gtk_media_stream_class_init (GtkMediaStreamClass *class)
   class->pause = gtk_media_stream_default_pause;
   class->seek = gtk_media_stream_default_seek;
   class->update_audio = gtk_media_stream_default_update_audio;
+  class->realize = gtk_media_stream_default_realize;
+  class->unrealize = gtk_media_stream_default_unrealize;
 
   gobject_class->set_property = gtk_media_stream_set_property;
   gobject_class->get_property = gtk_media_stream_get_property;
@@ -839,6 +853,60 @@ gtk_media_stream_set_volume (GtkMediaStream *self,
   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VOLUME]);
 }
 
+/**
+ * gtk_media_stream_realize:
+ * @self: a #GtkMediaStream
+ * @window: a #GdkWindow
+ *
+ * Called by users to attach the media stream to a #GdkWindow they manage.
+ * The stream can then access the resources of @window for its rendering
+ * purposes. In particular, media streams might want to create
+ * #GdkGLContexts or sync to the #GdkFrameClock.
+ *
+ * Whoever calls this function is responsible for calling
+ * gtk_media_stream_unrealize() before either the stream or @window get
+ * destroyed.
+ *
+ * Multiple calls to this function may happen from different users of the
+ * video, even with the same @window. Each of these calls must be followed
+ * by its own call to gtk_media_stream_unrealize().
+ *
+ * It is not required to call this function to make a media stream work.
+ **/
+void
+gtk_media_stream_realize (GtkMediaStream *self,
+                          GdkWindow      *window)
+{
+  g_return_if_fail (GTK_IS_MEDIA_STREAM (self));
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  g_object_ref (self);
+  g_object_ref (window);
+
+  GTK_MEDIA_STREAM_GET_CLASS (self)->realize (self, window);
+}
+
+/**
+ * gtk_media_stream_unrealize:
+ * @self: a #GtkMediaStream previously realized
+ * @window: the #GdkWindow the stream was realized with
+ *
+ * Undoes a previous call to gtk_media_stream_realize() and causes
+ * the stream to release all resources it had allocated from @window.
+ **/
+void
+gtk_media_stream_unrealize (GtkMediaStream *self,
+                            GdkWindow      *window)
+{
+  g_return_if_fail (GTK_IS_MEDIA_STREAM (self));
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  GTK_MEDIA_STREAM_GET_CLASS (self)->unrealize (self, window);
+
+  g_object_unref (window);
+  g_object_unref (self);
+}
+
 /**
  * gtk_media_stream_prepared:
  * @self: a #GtkMediaStream
index 30296965183ce07615954475c240042399b2eaa7..a04fafd8fac823e1827a1ded01a40323181dff68 100644 (file)
@@ -44,6 +44,11 @@ struct _GtkMediaStreamClass
   void                  (* update_audio)                        (GtkMediaStream *self,
                                                                  gboolean        muted,
                                                                  double          volume);
+  void                  (* realize)                             (GtkMediaStream *self,
+                                                                 GdkWindow      *window);
+  void                  (* unrealize)                           (GtkMediaStream *self,
+                                                                 GdkWindow      *window);
+
   /* Padding for future expansion */
   void (*_gtk_reserved1) (void);
   void (*_gtk_reserved2) (void);
@@ -103,6 +108,12 @@ double                  gtk_media_stream_get_volume             (GtkMediaStream
 GDK_AVAILABLE_IN_ALL
 void                    gtk_media_stream_set_volume             (GtkMediaStream *self,
                                                                  double          volume);
+GDK_AVAILABLE_IN_ALL
+void                    gtk_media_stream_realize                (GtkMediaStream *self,
+                                                                 GdkWindow      *window);
+GDK_AVAILABLE_IN_ALL
+void                    gtk_media_stream_unrealize              (GtkMediaStream *self,
+                                                                 GdkWindow      *window);
 
 /* for implementations only */
 GDK_AVAILABLE_IN_ALL
index bf51a236f82345d20acdf6995d5bf32d2a088be6..755acdde9843b37765dd5215ee0c4441270480f2 100644 (file)
@@ -95,6 +95,31 @@ gtk_video_size_allocate (GtkWidget           *widget,
   gtk_widget_size_allocate (self->box, allocation, baseline, out_clip);
 }
 
+static void
+gtk_video_realize (GtkWidget *widget)
+{
+  GtkVideo *self = GTK_VIDEO (widget);
+
+  GTK_WIDGET_CLASS (gtk_video_parent_class)->realize (widget);
+
+  if (self->media_stream)
+    gtk_media_stream_realize (self->media_stream, gtk_widget_get_window (GTK_WIDGET (self)));
+
+  if (self->file)
+    gtk_media_file_set_file (GTK_MEDIA_FILE (self->media_stream), self->file);
+}
+
+static void
+gtk_video_unrealize (GtkWidget *widget)
+{
+  GtkVideo *self = GTK_VIDEO (widget);
+
+  if (self->media_stream)
+    gtk_media_stream_unrealize (self->media_stream, gtk_widget_get_window (GTK_WIDGET (self)));
+
+  GTK_WIDGET_CLASS (gtk_video_parent_class)->unrealize (widget);
+}
+
 static void
 gtk_video_unmap (GtkWidget *widget)
 {
@@ -181,6 +206,8 @@ gtk_video_class_init (GtkVideoClass *klass)
 
   widget_class->measure = gtk_video_measure;
   widget_class->size_allocate = gtk_video_size_allocate;
+  widget_class->realize = gtk_video_realize;
+  widget_class->unrealize = gtk_video_unrealize;
   widget_class->unmap = gtk_video_unmap;
 
   gobject_class->dispose = gtk_video_dispose;
@@ -490,6 +517,8 @@ gtk_video_set_media_stream (GtkVideo       *self,
       g_signal_handlers_disconnect_by_func (self->media_stream,
                                             gtk_video_notify_cb,
                                             self);
+      if (gtk_widget_get_realized (GTK_WIDGET (self)))
+        gtk_media_stream_unrealize (self->media_stream, gtk_widget_get_window (GTK_WIDGET (self)));
       g_object_unref (self->media_stream);
       self->media_stream = NULL;
     }
@@ -497,6 +526,8 @@ gtk_video_set_media_stream (GtkVideo       *self,
   if (stream)
     {
       self->media_stream = g_object_ref (stream);
+      if (gtk_widget_get_realized (GTK_WIDGET (self)))
+        gtk_media_stream_realize (stream, gtk_widget_get_window (GTK_WIDGET (self)));
       g_signal_connect (self->media_stream,
                         "notify",
                         G_CALLBACK (gtk_video_notify_cb),
@@ -522,8 +553,6 @@ void
 gtk_video_set_file (GtkVideo *self,
                     GFile    *file)
 {
-  GtkMediaStream *stream;
-
   g_return_if_fail (GTK_IS_VIDEO (self));
   g_return_if_fail (file == NULL || G_IS_FILE (file));
 
@@ -533,14 +562,21 @@ gtk_video_set_file (GtkVideo *self,
   g_object_freeze_notify (G_OBJECT (self));
 
   if (file)
-    stream = gtk_media_file_new_for_file (file);
-  else
-    stream = NULL;
+    {
+      GtkMediaStream *stream;
 
-  gtk_video_set_media_stream (self, stream);
+      stream = gtk_media_file_new ();
 
-  if (stream)
-    g_object_unref (stream);
+      gtk_video_set_media_stream (self, stream);
+      if (gtk_widget_get_realized (GTK_WIDGET (self)))
+        gtk_media_file_set_file (GTK_MEDIA_FILE (stream), file);
+
+      g_object_unref (stream);
+    }
+  else
+    {
+      gtk_video_set_media_stream (self, NULL);
+    }
 
   g_object_thaw_notify (G_OBJECT (self));
 }