mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-08 17:50:10 +00:00
gtk: Add a GStreamer implementation of GtkMediaFile
This commit is contained in:
parent
182f39aba7
commit
2362e4d41e
@ -56,6 +56,9 @@
|
||||
/* Define if gio-unix is available */
|
||||
#mesondefine HAVE_GIO_UNIX
|
||||
|
||||
/* Define if GStreamer support is available */
|
||||
#mesondefine HAVE_GSTREAMER
|
||||
|
||||
/* Define to 1 if you have the `httpGetAuthString' function. */
|
||||
#mesondefine HAVE_HTTPGETAUTHSTRING
|
||||
|
||||
|
322
modules/media/gtkgstmediafile.c
Normal file
322
modules/media/gtkgstmediafile.c
Normal file
@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkgstmediafileprivate.h"
|
||||
#include "gtkgstpaintableprivate.h"
|
||||
|
||||
#include <gst/player/gstplayer.h>
|
||||
#include <gst/player/gstplayer-g-main-context-signal-dispatcher.h>
|
||||
|
||||
struct _GtkGstMediaFile
|
||||
{
|
||||
GtkMediaFile parent_instance;
|
||||
|
||||
GstPlayer *player;
|
||||
GdkPaintable *paintable;
|
||||
};
|
||||
|
||||
struct _GtkGstMediaFileClass
|
||||
{
|
||||
GtkMediaFileClass parent_class;
|
||||
};
|
||||
|
||||
#define TO_GST_TIME(ts) ((ts) * (GST_SECOND / G_USEC_PER_SEC))
|
||||
#define FROM_GST_TIME(ts) ((ts) / (GST_SECOND / G_USEC_PER_SEC))
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_paintable_snapshot (GdkPaintable *paintable,
|
||||
GdkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
GtkGstMediaFile *self = GTK_GST_MEDIA_FILE (paintable);
|
||||
|
||||
gdk_paintable_snapshot (self->paintable, snapshot, width, height);
|
||||
}
|
||||
|
||||
static GdkPaintable *
|
||||
gtk_gst_media_file_paintable_get_current_image (GdkPaintable *paintable)
|
||||
{
|
||||
GtkGstMediaFile *self = GTK_GST_MEDIA_FILE (paintable);
|
||||
|
||||
return gdk_paintable_get_current_image (self->paintable);
|
||||
}
|
||||
|
||||
static int
|
||||
gtk_gst_media_file_paintable_get_intrinsic_width (GdkPaintable *paintable)
|
||||
{
|
||||
GtkGstMediaFile *self = GTK_GST_MEDIA_FILE (paintable);
|
||||
|
||||
return gdk_paintable_get_intrinsic_width (self->paintable);
|
||||
}
|
||||
|
||||
static int
|
||||
gtk_gst_media_file_paintable_get_intrinsic_height (GdkPaintable *paintable)
|
||||
{
|
||||
GtkGstMediaFile *self = GTK_GST_MEDIA_FILE (paintable);
|
||||
|
||||
return gdk_paintable_get_intrinsic_height (self->paintable);
|
||||
}
|
||||
|
||||
static double gtk_gst_media_file_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
|
||||
{
|
||||
GtkGstMediaFile *self = GTK_GST_MEDIA_FILE (paintable);
|
||||
|
||||
return gdk_paintable_get_intrinsic_aspect_ratio (self->paintable);
|
||||
};
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_paintable_init (GdkPaintableInterface *iface)
|
||||
{
|
||||
iface->snapshot = gtk_gst_media_file_paintable_snapshot;
|
||||
iface->get_current_image = gtk_gst_media_file_paintable_get_current_image;
|
||||
iface->get_intrinsic_width = gtk_gst_media_file_paintable_get_intrinsic_width;
|
||||
iface->get_intrinsic_height = gtk_gst_media_file_paintable_get_intrinsic_height;
|
||||
iface->get_intrinsic_aspect_ratio = gtk_gst_media_file_paintable_get_intrinsic_aspect_ratio;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (GtkGstMediaFile, gtk_gst_media_file, GTK_TYPE_MEDIA_FILE, 0,
|
||||
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
|
||||
gtk_gst_media_file_paintable_init))
|
||||
void
|
||||
g_io_module_load (GIOModule *module)
|
||||
{
|
||||
g_type_module_use (G_TYPE_MODULE (module));
|
||||
|
||||
g_io_extension_point_implement (GTK_MEDIA_FILE_EXTENSION_POINT_NAME,
|
||||
GTK_TYPE_GST_MEDIA_FILE,
|
||||
"gstreamer",
|
||||
10);
|
||||
}
|
||||
|
||||
void
|
||||
g_io_module_unload (GIOModule *module)
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
char **
|
||||
g_io_module_query (void)
|
||||
{
|
||||
char *eps[] = {
|
||||
GTK_MEDIA_FILE_EXTENSION_POINT_NAME,
|
||||
NULL
|
||||
};
|
||||
|
||||
return g_strdupv (eps);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_position_updated_cb (GstPlayer *player,
|
||||
GstClockTime time,
|
||||
GtkGstMediaFile *self)
|
||||
{
|
||||
gtk_media_stream_update (GTK_MEDIA_STREAM (self), FROM_GST_TIME (time));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_duration_changed_cb (GstPlayer *player,
|
||||
GstClockTime duration,
|
||||
GtkGstMediaFile *self)
|
||||
{
|
||||
if (gtk_media_stream_is_prepared (GTK_MEDIA_STREAM (self)))
|
||||
return;
|
||||
|
||||
gtk_media_stream_prepared (GTK_MEDIA_STREAM (self),
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE,
|
||||
FROM_GST_TIME (duration));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_seek_done_cb (GstPlayer *player,
|
||||
GstClockTime time,
|
||||
GtkGstMediaFile *self)
|
||||
{
|
||||
/* if we're not seeking, we're doing the loop seek-back after EOS */
|
||||
if (gtk_media_stream_is_seeking (GTK_MEDIA_STREAM (self)))
|
||||
gtk_media_stream_seek_success (GTK_MEDIA_STREAM (self));
|
||||
gtk_media_stream_update (GTK_MEDIA_STREAM (self), FROM_GST_TIME (time));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_end_of_stream_cb (GstPlayer *player,
|
||||
GtkGstMediaFile *self)
|
||||
{
|
||||
if (gtk_media_stream_get_ended (GTK_MEDIA_STREAM (self)))
|
||||
return;
|
||||
|
||||
if (gtk_media_stream_get_loop (GTK_MEDIA_STREAM (self)))
|
||||
{
|
||||
gst_player_seek (self->player, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_media_stream_ended (GTK_MEDIA_STREAM (self));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_destroy_player (GtkGstMediaFile *self)
|
||||
{
|
||||
if (self->player == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->player, gtk_gst_media_file_duration_changed_cb, self);
|
||||
g_signal_handlers_disconnect_by_func (self->player, gtk_gst_media_file_position_updated_cb, self);
|
||||
g_signal_handlers_disconnect_by_func (self->player, gtk_gst_media_file_end_of_stream_cb, self);
|
||||
g_signal_handlers_disconnect_by_func (self->player, gtk_gst_media_file_seek_done_cb, self);
|
||||
g_object_unref (self->player);
|
||||
self->player = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_create_player (GtkGstMediaFile *file)
|
||||
{
|
||||
GtkGstMediaFile *self = GTK_GST_MEDIA_FILE (file);
|
||||
|
||||
if (self->player != NULL)
|
||||
return;
|
||||
|
||||
self->player = gst_player_new (GST_PLAYER_VIDEO_RENDERER (g_object_ref (self->paintable)),
|
||||
gst_player_g_main_context_signal_dispatcher_new (NULL));
|
||||
g_signal_connect (self->player, "duration-changed", G_CALLBACK (gtk_gst_media_file_duration_changed_cb), self);
|
||||
g_signal_connect (self->player, "position-updated", G_CALLBACK (gtk_gst_media_file_position_updated_cb), self);
|
||||
g_signal_connect (self->player, "end-of-stream", G_CALLBACK (gtk_gst_media_file_end_of_stream_cb), self);
|
||||
g_signal_connect (self->player, "seek-done", G_CALLBACK (gtk_gst_media_file_seek_done_cb), self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_open (GtkMediaFile *media_file)
|
||||
{
|
||||
GtkGstMediaFile *self = GTK_GST_MEDIA_FILE (media_file);
|
||||
GFile *file;
|
||||
|
||||
gtk_gst_media_file_create_player (self);
|
||||
|
||||
file = gtk_media_file_get_file (media_file);
|
||||
|
||||
if (file)
|
||||
{
|
||||
/* XXX: This is technically incorrect because GFile uris aren't real uris */
|
||||
char *uri = g_file_get_uri (file);
|
||||
|
||||
gst_player_set_uri (self->player, uri);
|
||||
|
||||
g_free (uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It's an input stream */
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
gst_player_pause (self->player);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_close (GtkMediaFile *file)
|
||||
{
|
||||
GtkGstMediaFile *self = GTK_GST_MEDIA_FILE (file);
|
||||
|
||||
gtk_gst_media_file_destroy_player (self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_gst_media_file_play (GtkMediaStream *stream)
|
||||
{
|
||||
GtkGstMediaFile *self = GTK_GST_MEDIA_FILE (stream);
|
||||
|
||||
gst_player_play (self->player);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_pause (GtkMediaStream *stream)
|
||||
{
|
||||
GtkGstMediaFile *self = GTK_GST_MEDIA_FILE (stream);
|
||||
|
||||
gst_player_pause (self->player);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_seek (GtkMediaStream *stream,
|
||||
gint64 timestamp)
|
||||
{
|
||||
GtkGstMediaFile *self = GTK_GST_MEDIA_FILE (stream);
|
||||
|
||||
gst_player_seek (self->player, TO_GST_TIME (timestamp));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_update_audio (GtkMediaStream *stream,
|
||||
gboolean muted,
|
||||
double volume)
|
||||
{
|
||||
GtkGstMediaFile *self = GTK_GST_MEDIA_FILE (stream);
|
||||
|
||||
gst_player_set_mute (self->player, muted);
|
||||
gst_player_set_volume (self->player, volume);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_dispose (GObject *object)
|
||||
{
|
||||
GtkGstMediaFile *self = GTK_GST_MEDIA_FILE (object);
|
||||
|
||||
gtk_gst_media_file_destroy_player (self);
|
||||
if (self->paintable)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (self->paintable, gdk_paintable_invalidate_size, self);
|
||||
g_signal_handlers_disconnect_by_func (self->paintable, gdk_paintable_invalidate_contents, self);
|
||||
g_clear_object (&self->paintable);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (gtk_gst_media_file_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_class_init (GtkGstMediaFileClass *klass)
|
||||
{
|
||||
GtkMediaFileClass *file_class = GTK_MEDIA_FILE_CLASS (klass);
|
||||
GtkMediaStreamClass *stream_class = GTK_MEDIA_STREAM_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
file_class->open = gtk_gst_media_file_open;
|
||||
file_class->close = gtk_gst_media_file_close;
|
||||
|
||||
stream_class->play = gtk_gst_media_file_play;
|
||||
stream_class->pause = gtk_gst_media_file_pause;
|
||||
stream_class->seek = gtk_gst_media_file_seek;
|
||||
stream_class->update_audio = gtk_gst_media_file_update_audio;
|
||||
|
||||
gobject_class->dispose = gtk_gst_media_file_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_media_file_init (GtkGstMediaFile *self)
|
||||
{
|
||||
self->paintable = gtk_gst_paintable_new ();
|
||||
g_signal_connect_swapped (self->paintable, "invalidate-size", G_CALLBACK (gdk_paintable_invalidate_size), self);
|
||||
g_signal_connect_swapped (self->paintable, "invalidate-contents", G_CALLBACK (gdk_paintable_invalidate_contents), self);
|
||||
}
|
||||
|
33
modules/media/gtkgstmediafileprivate.h
Normal file
33
modules/media/gtkgstmediafileprivate.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_GST_MEDIA_FILE_H__
|
||||
#define __GTK_GST_MEDIA_FILE_H__
|
||||
|
||||
#include <gtk/gtkmediafile.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_GST_MEDIA_FILE (gtk_gst_media_file_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GtkGstMediaFile, gtk_gst_media_file, GTK, GST_MEDIA_FILE, GtkMediaFile)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_GST_MEDIA_FILE_H__ */
|
227
modules/media/gtkgstpaintable.c
Normal file
227
modules/media/gtkgstpaintable.c
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkgstpaintableprivate.h"
|
||||
|
||||
#include "gtkgstsinkprivate.h"
|
||||
|
||||
#include <gst/player/gstplayer-video-renderer.h>
|
||||
|
||||
struct _GtkGstPaintable
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GdkPaintable *image;
|
||||
};
|
||||
|
||||
struct _GtkGstPaintableClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static void
|
||||
gtk_gst_paintable_paintable_snapshot (GdkPaintable *paintable,
|
||||
GdkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
GtkGstPaintable *self = GTK_GST_PAINTABLE (paintable);
|
||||
|
||||
if (self->image)
|
||||
gdk_paintable_snapshot (self->image, snapshot, width, height);
|
||||
}
|
||||
|
||||
static GdkPaintable *
|
||||
gtk_gst_paintable_paintable_get_current_image (GdkPaintable *paintable)
|
||||
{
|
||||
GtkGstPaintable *self = GTK_GST_PAINTABLE (paintable);
|
||||
|
||||
if (self->image)
|
||||
return GDK_PAINTABLE (g_object_ref (self->image));
|
||||
|
||||
g_warning ("FIXME: return empty something here");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
gtk_gst_paintable_paintable_get_intrinsic_width (GdkPaintable *paintable)
|
||||
{
|
||||
GtkGstPaintable *self = GTK_GST_PAINTABLE (paintable);
|
||||
|
||||
if (self->image)
|
||||
return gdk_paintable_get_intrinsic_width (self->image);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gtk_gst_paintable_paintable_get_intrinsic_height (GdkPaintable *paintable)
|
||||
{
|
||||
GtkGstPaintable *self = GTK_GST_PAINTABLE (paintable);
|
||||
|
||||
if (self->image)
|
||||
return gdk_paintable_get_intrinsic_height (self->image);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static double
|
||||
gtk_gst_paintable_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
|
||||
{
|
||||
GtkGstPaintable *self = GTK_GST_PAINTABLE (paintable);
|
||||
|
||||
if (self->image)
|
||||
return gdk_paintable_get_intrinsic_aspect_ratio (self->image);
|
||||
|
||||
return 0.0;
|
||||
};
|
||||
|
||||
static void
|
||||
gtk_gst_paintable_paintable_init (GdkPaintableInterface *iface)
|
||||
{
|
||||
iface->snapshot = gtk_gst_paintable_paintable_snapshot;
|
||||
iface->get_current_image = gtk_gst_paintable_paintable_get_current_image;
|
||||
iface->get_intrinsic_width = gtk_gst_paintable_paintable_get_intrinsic_width;
|
||||
iface->get_intrinsic_height = gtk_gst_paintable_paintable_get_intrinsic_height;
|
||||
iface->get_intrinsic_aspect_ratio = gtk_gst_paintable_paintable_get_intrinsic_aspect_ratio;
|
||||
}
|
||||
|
||||
static GstElement *
|
||||
gtk_gst_paintable_video_renderer_create_video_sink (GstPlayerVideoRenderer *renderer,
|
||||
GstPlayer *player)
|
||||
{
|
||||
GtkGstPaintable *self = GTK_GST_PAINTABLE (renderer);
|
||||
|
||||
return g_object_new (GTK_TYPE_GST_SINK,
|
||||
"paintable", self,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_paintable_video_renderer_init (GstPlayerVideoRendererInterface *iface)
|
||||
{
|
||||
iface->create_video_sink = gtk_gst_paintable_video_renderer_create_video_sink;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkGstPaintable, gtk_gst_paintable, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
|
||||
gtk_gst_paintable_paintable_init)
|
||||
G_IMPLEMENT_INTERFACE (GST_TYPE_PLAYER_VIDEO_RENDERER,
|
||||
gtk_gst_paintable_video_renderer_init));
|
||||
|
||||
static void
|
||||
gtk_gst_paintable_dispose (GObject *object)
|
||||
{
|
||||
GtkGstPaintable *self = GTK_GST_PAINTABLE (object);
|
||||
|
||||
g_clear_object (&self->image);
|
||||
|
||||
G_OBJECT_CLASS (gtk_gst_paintable_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_paintable_class_init (GtkGstPaintableClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = gtk_gst_paintable_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_paintable_init (GtkGstPaintable *self)
|
||||
{
|
||||
}
|
||||
|
||||
GdkPaintable *
|
||||
gtk_gst_paintable_new (void)
|
||||
{
|
||||
return g_object_new (GTK_TYPE_GST_PAINTABLE, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_paintable_set_paintable (GtkGstPaintable *self,
|
||||
GdkPaintable *paintable)
|
||||
{
|
||||
gboolean size_changed;
|
||||
|
||||
if (self->image == paintable)
|
||||
return;
|
||||
|
||||
if (self->image == NULL ||
|
||||
gdk_paintable_get_intrinsic_width (self->image) != gdk_paintable_get_intrinsic_width (paintable) ||
|
||||
gdk_paintable_get_intrinsic_height (self->image) != gdk_paintable_get_intrinsic_height (paintable) ||
|
||||
gdk_paintable_get_intrinsic_aspect_ratio (self->image) != gdk_paintable_get_intrinsic_aspect_ratio (paintable))
|
||||
size_changed = TRUE;
|
||||
else
|
||||
size_changed = FALSE;
|
||||
|
||||
g_set_object (&self->image, paintable);
|
||||
|
||||
if (size_changed)
|
||||
gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
|
||||
|
||||
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
|
||||
}
|
||||
|
||||
typedef struct _SetTextureInvocation SetTextureInvocation;
|
||||
|
||||
struct _SetTextureInvocation {
|
||||
GtkGstPaintable *paintable;
|
||||
GdkTexture *texture;
|
||||
};
|
||||
|
||||
static void
|
||||
set_texture_invocation_free (SetTextureInvocation *invoke)
|
||||
{
|
||||
g_object_unref (invoke->paintable);
|
||||
g_object_unref (invoke->texture);
|
||||
|
||||
g_slice_free (SetTextureInvocation, invoke);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_gst_paintable_set_texture_invoke (gpointer data)
|
||||
{
|
||||
SetTextureInvocation *invoke = data;
|
||||
|
||||
gtk_gst_paintable_set_paintable (invoke->paintable,
|
||||
GDK_PAINTABLE (invoke->texture));
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_gst_paintable_queue_set_texture (GtkGstPaintable *self,
|
||||
GdkTexture *texture)
|
||||
{
|
||||
SetTextureInvocation *invoke;
|
||||
|
||||
invoke = g_slice_new0 (SetTextureInvocation);
|
||||
invoke->paintable = g_object_ref (self);
|
||||
invoke->texture = g_object_ref (texture);
|
||||
|
||||
g_main_context_invoke_full (NULL,
|
||||
G_PRIORITY_DEFAULT,
|
||||
gtk_gst_paintable_set_texture_invoke,
|
||||
invoke,
|
||||
(GDestroyNotify) set_texture_invocation_free);
|
||||
}
|
||||
|
38
modules/media/gtkgstpaintableprivate.h
Normal file
38
modules/media/gtkgstpaintableprivate.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_GST_PAINTABLE_H__
|
||||
#define __GTK_GST_PAINTABLE_H__
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_GST_PAINTABLE (gtk_gst_paintable_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GtkGstPaintable, gtk_gst_paintable, GTK, GST_PAINTABLE, GObject)
|
||||
|
||||
GdkPaintable * gtk_gst_paintable_new (void);
|
||||
|
||||
void gtk_gst_paintable_queue_set_texture (GtkGstPaintable *self,
|
||||
GdkTexture *texture);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_GST_PAINTABLE_H__ */
|
261
modules/media/gtkgstsink.c
Normal file
261
modules/media/gtkgstsink.c
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkgstsinkprivate.h"
|
||||
|
||||
#include "gtkgstpaintableprivate.h"
|
||||
#include "gtkintl.h"
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_PAINTABLE,
|
||||
|
||||
N_PROPS,
|
||||
};
|
||||
|
||||
GST_DEBUG_CATEGORY (gtk_debug_gst_sink);
|
||||
#define GST_CAT_DEFAULT gtk_debug_gst_sink
|
||||
|
||||
#define FORMATS "{ BGRA, ARGB, RGBA, ABGR, RGB, BGR }"
|
||||
|
||||
static GstStaticPadTemplate gtk_gst_sink_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (FORMATS))
|
||||
);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkGstSink, gtk_gst_sink,
|
||||
GST_TYPE_VIDEO_SINK,
|
||||
GST_DEBUG_CATEGORY_INIT (gtk_debug_gst_sink,
|
||||
"gtkgstsink", 0, "GtkGstMediaFile Video Sink"));
|
||||
|
||||
static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
|
||||
|
||||
static void
|
||||
gtk_gst_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
|
||||
GstClockTime * start, GstClockTime * end)
|
||||
{
|
||||
GtkGstSink *gtk_sink;
|
||||
|
||||
gtk_sink = GTK_GST_SINK (bsink);
|
||||
|
||||
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
|
||||
*start = GST_BUFFER_TIMESTAMP (buf);
|
||||
if (GST_BUFFER_DURATION_IS_VALID (buf))
|
||||
*end = *start + GST_BUFFER_DURATION (buf);
|
||||
else {
|
||||
if (GST_VIDEO_INFO_FPS_N (>k_sink->v_info) > 0) {
|
||||
*end = *start +
|
||||
gst_util_uint64_scale_int (GST_SECOND,
|
||||
GST_VIDEO_INFO_FPS_D (>k_sink->v_info),
|
||||
GST_VIDEO_INFO_FPS_N (>k_sink->v_info));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_gst_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
{
|
||||
GtkGstSink *self = GTK_GST_SINK (bsink);
|
||||
|
||||
GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps);
|
||||
|
||||
if (!gst_video_info_from_caps (&self->v_info, caps))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GdkMemoryFormat
|
||||
gtk_gst_memory_format_from_video (GstVideoFormat format)
|
||||
{
|
||||
switch ((guint) format)
|
||||
{
|
||||
case GST_VIDEO_FORMAT_BGRA:
|
||||
return GDK_MEMORY_B8G8R8A8;
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
return GDK_MEMORY_A8R8G8B8;
|
||||
case GST_VIDEO_FORMAT_RGBA:
|
||||
return GDK_MEMORY_R8G8B8A8;
|
||||
case GST_VIDEO_FORMAT_ABGR:
|
||||
return GDK_MEMORY_A8B8G8R8;
|
||||
case GST_VIDEO_FORMAT_RGB:
|
||||
return GDK_MEMORY_R8G8B8;
|
||||
case GST_VIDEO_FORMAT_BGR:
|
||||
return GDK_MEMORY_B8G8R8;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return GDK_MEMORY_A8R8G8B8;
|
||||
}
|
||||
}
|
||||
|
||||
static GdkTexture *
|
||||
gtk_gst_sink_texture_from_buffer (GtkGstSink *self,
|
||||
GstBuffer *buffer)
|
||||
{
|
||||
GstVideoFrame frame;
|
||||
GdkTexture *texture;
|
||||
GBytes *bytes;
|
||||
|
||||
if (!gst_video_frame_map (&frame, &self->v_info, buffer, GST_MAP_READ))
|
||||
return NULL;
|
||||
|
||||
bytes = g_bytes_new_with_free_func (frame.data[0],
|
||||
frame.info.width * frame.info.stride[0],
|
||||
(GDestroyNotify) gst_buffer_unref,
|
||||
gst_buffer_ref (buffer));
|
||||
texture = gdk_memory_texture_new (frame.info.width,
|
||||
frame.info.height,
|
||||
gtk_gst_memory_format_from_video (GST_VIDEO_FRAME_FORMAT (&frame)),
|
||||
bytes,
|
||||
frame.info.stride[0]);
|
||||
gst_video_frame_unmap (&frame);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gtk_gst_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
|
||||
{
|
||||
GtkGstSink *self;
|
||||
GdkTexture *texture;
|
||||
|
||||
GST_TRACE ("rendering buffer:%p", buf);
|
||||
|
||||
self = GTK_GST_SINK (vsink);
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
||||
texture = gtk_gst_sink_texture_from_buffer (self, buf);
|
||||
if (texture)
|
||||
{
|
||||
gtk_gst_paintable_queue_set_texture (self->paintable, texture);
|
||||
g_object_unref (texture);
|
||||
}
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_sink_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
|
||||
{
|
||||
GtkGstSink *self = GTK_GST_SINK (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PAINTABLE:
|
||||
self->paintable = g_value_dup_object (value);
|
||||
if (self->paintable == NULL)
|
||||
self->paintable = GTK_GST_PAINTABLE (gtk_gst_paintable_new ());
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_sink_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkGstSink *self = GTK_GST_SINK (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PAINTABLE:
|
||||
g_value_set_object (value, self->paintable);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_sink_dispose (GObject *object)
|
||||
{
|
||||
GtkGstSink *self = GTK_GST_SINK (object);
|
||||
|
||||
g_clear_object (&self->paintable);
|
||||
|
||||
G_OBJECT_CLASS (gtk_gst_sink_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_sink_class_init (GtkGstSinkClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
|
||||
GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
|
||||
GstVideoSinkClass *gstvideosink_class = GST_VIDEO_SINK_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = gtk_gst_sink_set_property;
|
||||
gobject_class->get_property = gtk_gst_sink_get_property;
|
||||
gobject_class->dispose = gtk_gst_sink_dispose;
|
||||
|
||||
gstbasesink_class->set_caps = gtk_gst_sink_set_caps;
|
||||
gstbasesink_class->get_times = gtk_gst_sink_get_times;
|
||||
|
||||
gstvideosink_class->show_frame = gtk_gst_sink_show_frame;
|
||||
|
||||
/**
|
||||
* GtkGstSink:paintable:
|
||||
*
|
||||
* The paintable that provides the picture for this sink.
|
||||
*/
|
||||
properties[PROP_PAINTABLE] =
|
||||
g_param_spec_object ("paintable",
|
||||
P_("paintable"),
|
||||
P_("Paintable providing the picture"),
|
||||
GTK_TYPE_GST_PAINTABLE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
|
||||
gst_element_class_set_metadata (gstelement_class,
|
||||
"GtkMediaStream Video Sink",
|
||||
"Sink/Video", "The video sink used by GtkMediaStream",
|
||||
"Matthew Waters <matthew@centricular.com>, "
|
||||
"Benjamin Otte <otte@gnome.org>");
|
||||
|
||||
gst_element_class_add_static_pad_template (gstelement_class,
|
||||
>k_gst_sink_template);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gst_sink_init (GtkGstSink * gtk_sink)
|
||||
{
|
||||
}
|
||||
|
61
modules/media/gtkgstsinkprivate.h
Normal file
61
modules/media/gtkgstsinkprivate.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_GST_SINK_PRIVATE_H__
|
||||
#define __GTK_GST_SINK_PRIVATE_H__
|
||||
|
||||
#include "gtkgstpaintableprivate.h"
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/gstvideosink.h>
|
||||
#include <gst/video/video.h>
|
||||
|
||||
#define GTK_TYPE_GST_SINK (gtk_gst_sink_get_type())
|
||||
#define GTK_GST_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GTK_TYPE_GST_SINK,GtkGstSink))
|
||||
#define GTK_GST_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GTK_TYPE_GST_SINK,GtkGstSinkClass))
|
||||
#define GTK_GST_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_GST_SINK, GtkGstSinkClass))
|
||||
#define GST_IS_GTK_BASE_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GTK_TYPE_GST_SINK))
|
||||
#define GST_IS_GTK_BASE_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GTK_TYPE_GST_SINK))
|
||||
#define GTK_GST_SINK_CAST(obj) ((GtkGstSink*)(obj))
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GtkGstSink GtkGstSink;
|
||||
typedef struct _GtkGstSinkClass GtkGstSinkClass;
|
||||
|
||||
struct _GtkGstSink
|
||||
{
|
||||
/* <private> */
|
||||
GstVideoSink parent;
|
||||
|
||||
GstVideoInfo v_info;
|
||||
GtkGstPaintable * paintable;
|
||||
};
|
||||
|
||||
struct _GtkGstSinkClass
|
||||
{
|
||||
GstVideoSinkClass object_class;
|
||||
};
|
||||
|
||||
GType gtk_gst_sink_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_GST_SINK_PRIVATE_H__ */
|
@ -1,5 +1,6 @@
|
||||
all_media_backends = [
|
||||
'ffmpeg'
|
||||
'ffmpeg',
|
||||
'gstreamer'
|
||||
]
|
||||
|
||||
enabled_media_backends = get_option('media').split(',')
|
||||
@ -41,3 +42,18 @@ if media_backends.contains('ffmpeg')
|
||||
install : true)
|
||||
endif
|
||||
|
||||
if media_backends.contains('gstreamer')
|
||||
gstplayer_dep = dependency('gstreamer-player-1.0', version: '>= 1.12.3', required: true)
|
||||
cdata.set('HAVE_GSTREAMER', 1)
|
||||
|
||||
shared_module('media-gstreamer',
|
||||
'gtkgstmediafile.c',
|
||||
'gtkgstpaintable.c',
|
||||
'gtkgstsink.c',
|
||||
c_args: [
|
||||
'-DGTK_COMPILATION'
|
||||
],
|
||||
dependencies: [ libgtk_dep, gstplayer_dep ],
|
||||
install_dir: media_install_dir,
|
||||
install : true)
|
||||
endif
|
||||
|
Loading…
Reference in New Issue
Block a user