mediastream: Add gtk_media_stream_realize/unrealize()

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.
This commit is contained in:
Benjamin Otte 2018-03-18 03:20:02 +01:00
parent 09a21f1cd2
commit 04a3b8b6df
3 changed files with 124 additions and 9 deletions

View 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 static void
gtk_media_stream_set_property (GObject *object, gtk_media_stream_set_property (GObject *object,
guint prop_id, guint prop_id,
@ -260,6 +272,8 @@ gtk_media_stream_class_init (GtkMediaStreamClass *class)
class->pause = gtk_media_stream_default_pause; class->pause = gtk_media_stream_default_pause;
class->seek = gtk_media_stream_default_seek; class->seek = gtk_media_stream_default_seek;
class->update_audio = gtk_media_stream_default_update_audio; 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->set_property = gtk_media_stream_set_property;
gobject_class->get_property = gtk_media_stream_get_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]); 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: * gtk_media_stream_prepared:
* @self: a #GtkMediaStream * @self: a #GtkMediaStream

View File

@ -44,6 +44,11 @@ struct _GtkMediaStreamClass
void (* update_audio) (GtkMediaStream *self, void (* update_audio) (GtkMediaStream *self,
gboolean muted, gboolean muted,
double volume); double volume);
void (* realize) (GtkMediaStream *self,
GdkWindow *window);
void (* unrealize) (GtkMediaStream *self,
GdkWindow *window);
/* Padding for future expansion */ /* Padding for future expansion */
void (*_gtk_reserved1) (void); void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void); void (*_gtk_reserved2) (void);
@ -103,6 +108,12 @@ double gtk_media_stream_get_volume (GtkMediaStream
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
void gtk_media_stream_set_volume (GtkMediaStream *self, void gtk_media_stream_set_volume (GtkMediaStream *self,
double volume); 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 */ /* for implementations only */
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL

View File

@ -95,6 +95,31 @@ gtk_video_size_allocate (GtkWidget *widget,
gtk_widget_size_allocate (self->box, allocation, baseline, out_clip); 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 static void
gtk_video_unmap (GtkWidget *widget) gtk_video_unmap (GtkWidget *widget)
{ {
@ -181,6 +206,8 @@ gtk_video_class_init (GtkVideoClass *klass)
widget_class->measure = gtk_video_measure; widget_class->measure = gtk_video_measure;
widget_class->size_allocate = gtk_video_size_allocate; 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; widget_class->unmap = gtk_video_unmap;
gobject_class->dispose = gtk_video_dispose; 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, g_signal_handlers_disconnect_by_func (self->media_stream,
gtk_video_notify_cb, gtk_video_notify_cb,
self); 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); g_object_unref (self->media_stream);
self->media_stream = NULL; self->media_stream = NULL;
} }
@ -497,6 +526,8 @@ gtk_video_set_media_stream (GtkVideo *self,
if (stream) if (stream)
{ {
self->media_stream = g_object_ref (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, g_signal_connect (self->media_stream,
"notify", "notify",
G_CALLBACK (gtk_video_notify_cb), G_CALLBACK (gtk_video_notify_cb),
@ -522,8 +553,6 @@ void
gtk_video_set_file (GtkVideo *self, gtk_video_set_file (GtkVideo *self,
GFile *file) GFile *file)
{ {
GtkMediaStream *stream;
g_return_if_fail (GTK_IS_VIDEO (self)); g_return_if_fail (GTK_IS_VIDEO (self));
g_return_if_fail (file == NULL || G_IS_FILE (file)); 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)); g_object_freeze_notify (G_OBJECT (self));
if (file) if (file)
stream = gtk_media_file_new_for_file (file); {
GtkMediaStream *stream;
stream = gtk_media_file_new ();
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 else
stream = NULL; {
gtk_video_set_media_stream (self, NULL);
gtk_video_set_media_stream (self, stream); }
if (stream)
g_object_unref (stream);
g_object_thaw_notify (G_OBJECT (self)); g_object_thaw_notify (G_OBJECT (self));
} }