diff options
Diffstat (limited to 'gtk/gtkmediafile.c')
-rw-r--r-- | gtk/gtkmediafile.c | 526 |
1 files changed, 526 insertions, 0 deletions
diff --git a/gtk/gtkmediafile.c b/gtk/gtkmediafile.c new file mode 100644 index 0000000000..edc121fe3e --- /dev/null +++ b/gtk/gtkmediafile.c @@ -0,0 +1,526 @@ +/* + * 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 "gtkmediafile.h" + +#include "gtkintl.h" + +/** + * SECTION:gtkmediafile + * @Short_description: Open media files for use in GTK + * @Title: GtkMediaFile + * @See_also: #GtkMediaStream + * + * #GtkMediaFile is the implementation for media file usage with #GtkMediaStream. + * + * This provides a simple way to play back video files with GTK. + */ + +typedef struct _GtkMediaFilePrivate GtkMediaFilePrivate; + +struct _GtkMediaFilePrivate +{ + GFile *file; + GInputStream *input_stream; +}; + +enum { + PROP_0, + PROP_FILE, + PROP_INPUT_STREAM, + + N_PROPS, +}; + +static GParamSpec *properties[N_PROPS] = { NULL, }; + +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkMediaFile, gtk_media_file, GTK_TYPE_MEDIA_STREAM, + G_ADD_PRIVATE (GtkMediaFile)) + +#define GTK_MEDIA_FILE_WARN_NOT_IMPLEMENTED_METHOD(obj,method) \ + g_critical ("Media file of type '%s' does not implement GtkMediaFile::" # method, G_OBJECT_TYPE_NAME (obj)) + +static void +gtk_media_file_default_open (GtkMediaFile *self) +{ + GTK_MEDIA_FILE_WARN_NOT_IMPLEMENTED_METHOD (self, open); +} + +static void +gtk_media_file_default_close (GtkMediaFile *self) +{ + gtk_media_stream_unprepared (GTK_MEDIA_STREAM (self)); +} + +static void +gtk_media_file_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) + +{ + GtkMediaFile *self = GTK_MEDIA_FILE (object); + + switch (prop_id) + { + case PROP_FILE: + gtk_media_file_set_file (self, g_value_get_object (value)); + break; + + case PROP_INPUT_STREAM: + gtk_media_file_set_input_stream (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_media_file_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkMediaFile *self = GTK_MEDIA_FILE (object); + GtkMediaFilePrivate *priv = gtk_media_file_get_instance_private (self); + + switch (prop_id) + { + case PROP_FILE: + g_value_set_object (value, priv->file); + break; + + case PROP_INPUT_STREAM: + g_value_set_object (value, priv->input_stream); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_media_file_dispose (GObject *object) +{ + GtkMediaFile *self = GTK_MEDIA_FILE (object); + GtkMediaFilePrivate *priv = gtk_media_file_get_instance_private (self); + + g_clear_object (&priv->file); + g_clear_object (&priv->input_stream); + + G_OBJECT_CLASS (gtk_media_file_parent_class)->dispose (object); +} + +static void +gtk_media_file_class_init (GtkMediaFileClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + + class->open = gtk_media_file_default_open; + class->close = gtk_media_file_default_close; + + gobject_class->set_property = gtk_media_file_set_property; + gobject_class->get_property = gtk_media_file_get_property; + gobject_class->dispose = gtk_media_file_dispose; + + /** + * GtkMediaFile:file: + * + * The file being played back or %NULL if not playing a file. + */ + properties[PROP_FILE] = + g_param_spec_object ("file", + P_("File"), + P_("File being played back"), + G_TYPE_FILE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GtkMediaFile:input-stream: + * + * The stream being played back or %NULL if not playing a stream, like when playing a file. + */ + properties[PROP_INPUT_STREAM] = + g_param_spec_object ("input-stream", + P_("Input stream"), + P_("Input stream being played back"), + G_TYPE_INPUT_STREAM, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (gobject_class, N_PROPS, properties); +} + +static void +gtk_media_file_init (GtkMediaFile *self) +{ +} + +static GType +gtk_media_file_get_impl_type (void) +{ + g_assert_not_reached (); + return G_TYPE_INVALID; +} + +/** + * gtk_media_file_new: + * + * Creates a new empty media file. + * + * Returns: a new #GtkMediaFile + **/ +GtkMediaStream * +gtk_media_file_new (void) +{ + return g_object_new (gtk_media_file_get_impl_type (), NULL); +} + +/** + * gtk_media_file_new_for_filename: + * @filename: filename to open + * + * This is a utility function that converts the given @filename + * to a #GFile and calls gtk_media_file_new_for_file(). + * + * Returns: a new #GtkMediaFile playing @filename + **/ +GtkMediaStream * +gtk_media_file_new_for_filename (const char *filename) +{ + GtkMediaStream *result; + GFile *file; + + if (filename) + file = g_file_new_for_path (filename); + else + file = NULL; + + result = gtk_media_file_new_for_file (file); + + if (file) + g_object_unref (file); + + return result; +} + +/** + * gtk_media_file_new_for_resource: + * @resource_path: resource path to open + * + * This is a utility function that converts the given @resource + * to a #GFile and calls gtk_media_file_new_for_file(). + * + * Returns: a new #GtkMediaFile playing @resource_path + **/ +GtkMediaStream * +gtk_media_file_new_for_resource (const char *resource_path) +{ + GtkMediaStream *result; + GFile *file; + + if (resource_path) + { + char *uri, *escaped; + + escaped = g_uri_escape_string (resource_path, + G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE); + uri = g_strconcat ("resource://", escaped, NULL); + g_free (escaped); + + file = g_file_new_for_uri (uri); + g_free (uri); + } + else + { + file = NULL; + } + + result = gtk_media_file_new_for_file (file); + + if (file) + g_object_unref (file); + + return result; +} + +/** + * gtk_media_file_new_for_file: + * @file: (allow-none): The file to play + * + * Creates a new media file to play @file. + * + * Returns: a new #GtkMediaFile playing @file + **/ +GtkMediaStream * +gtk_media_file_new_for_file (GFile *file) +{ + g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL); + + return g_object_new (gtk_media_file_get_impl_type (), + "file", file, + NULL); +} + +/** + * gtk_media_file_new_for_input_stream: + * @stream: (allow-none): The stream to play + * + * Creates a new media file to play @stream. If you want the + * resulting media to be seekable, the stream should implement + * the #GSeekable interface. + * + * Returns: a new #GtkMediaFile + **/ +GtkMediaStream * +gtk_media_file_new_for_input_stream (GInputStream *stream) +{ + g_return_val_if_fail (stream == NULL || G_IS_INPUT_STREAM (stream), NULL); + + return g_object_new (gtk_media_file_get_impl_type (), + "input-stream", stream, + NULL); +} + +static gboolean +gtk_media_file_is_open (GtkMediaFile *self) +{ + GtkMediaFilePrivate *priv = gtk_media_file_get_instance_private (self); + + return priv->file || priv->input_stream; +} + +/** + * gtk_media_file_clear: + * @self: a #GtkMediaFile + * + * Resets the media file to be empty. + **/ +void +gtk_media_file_clear (GtkMediaFile *self) +{ + GtkMediaFilePrivate *priv = gtk_media_file_get_instance_private (self); + + g_return_if_fail (GTK_IS_MEDIA_FILE (self)); + + if (!gtk_media_file_is_open (self)) + return; + + GTK_MEDIA_FILE_GET_CLASS (self)->close (self); + + if (priv->input_stream) + { + g_clear_object (&priv->input_stream); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INPUT_STREAM]); + } + if (priv->file) + { + g_clear_object (&priv->file); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FILE]); + } +} + +/** + * gtk_media_file_set_filename: + * @self: a #GtkMediaFile + * @filename: (allow-none): name of file to play + * + * This is a utility function that converts the given @filename + * to a #GFile and calls gtk_media_file_set_file(). + **/ +void +gtk_media_file_set_filename (GtkMediaFile *self, + const char *filename) +{ + GFile *file; + + g_return_if_fail (GTK_IS_MEDIA_FILE (self)); + + if (filename) + file = g_file_new_for_path (filename); + else + file = NULL; + + gtk_media_file_set_file (self, file); + + if (file) + g_object_unref (file); +} + +/** + * gtk_media_file_set_resource: + * @self: a #GtkMediaFile + * @resource_path: (allow-none): path to resource to play + * + * This is a utility function that converts the given @resource_path + * to a #GFile and calls gtk_media_file_set_file(). + **/ +void +gtk_media_file_set_resource (GtkMediaFile *self, + const char *resource_path) +{ + GFile *file; + + g_return_if_fail (GTK_IS_MEDIA_FILE (self)); + + if (resource_path) + { + char *uri, *escaped; + + escaped = g_uri_escape_string (resource_path, + G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE); + uri = g_strconcat ("resource://", escaped, NULL); + g_free (escaped); + + file = g_file_new_for_uri (uri); + g_free (uri); + } + else + { + file = NULL; + } + + + gtk_media_file_set_file (self, file); + + if (file) + g_object_unref (file); +} + +/** + * gtk_media_file_set_file: + * @self: a #GtkMediaFile + * @file: (allow-none): the file to play + * + * If any file is still playing, stop playing it. + * + * Then start playing the given @file. + **/ +void +gtk_media_file_set_file (GtkMediaFile *self, + GFile *file) +{ + GtkMediaFilePrivate *priv = gtk_media_file_get_instance_private (self); + + g_return_if_fail (GTK_IS_MEDIA_FILE (self)); + g_return_if_fail (file == NULL || G_IS_FILE (file)); + + if (file) + g_object_ref (file); + + g_object_freeze_notify (G_OBJECT (self)); + + gtk_media_file_clear (self); + + if (file) + { + priv->file = file; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FILE]); + + GTK_MEDIA_FILE_GET_CLASS (self)->open (self); + } + + g_object_thaw_notify (G_OBJECT (self)); +} + +/** + * gtk_media_file_get_file: + * @self: a #GtkMediaFile + * + * Returns the file that @self is currently playing from. + * + * When @self is not playing or not playing from a file, + * %NULL is returned. + * + * Returns: (nullable): The currently playing file or %NULL if not + * playing from a file. + **/ +GFile * +gtk_media_file_get_file (GtkMediaFile *self) +{ + GtkMediaFilePrivate *priv = gtk_media_file_get_instance_private (self); + + g_return_val_if_fail (GTK_IS_MEDIA_FILE (self), NULL); + + return priv->file; +} + +/** + * gtk_media_file_set_input_stream: + * @self: a #GtkMediaFile + * @stream: (allow-none): the stream to play from + * + * If anything is still playing, stop playing it. Then start + * playing the given @stream. + * + * Full control about the @stream is assumed for the duration of + * playback. The stream will not bt be closed. + **/ +void +gtk_media_file_set_input_stream (GtkMediaFile *self, + GInputStream *stream) +{ + GtkMediaFilePrivate *priv = gtk_media_file_get_instance_private (self); + + g_return_if_fail (GTK_IS_MEDIA_FILE (self)); + g_return_if_fail (stream == NULL || G_IS_INPUT_STREAM (stream)); + + if (stream) + g_object_ref (stream); + + g_object_freeze_notify (G_OBJECT (self)); + + gtk_media_file_clear (self); + + if (stream) + { + priv->input_stream = stream; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INPUT_STREAM]); + + GTK_MEDIA_FILE_GET_CLASS (self)->open (self); + } + + g_object_thaw_notify (G_OBJECT (self)); +} + +/** + * gtk_media_file_get_input_stream: + * @self: a #GtkMediaFile + * + * Returns the stream that @self is currently playing from. + * + * When @self is not playing or not playing from a stream, + * %NULL is returned. + * + * Returns: (nullable): The currently playing stream or %NULL if not + * playing from a stream. + **/ +GInputStream * +gtk_media_file_get_input_stream (GtkMediaFile *self) +{ + GtkMediaFilePrivate *priv = gtk_media_file_get_instance_private (self); + + g_return_val_if_fail (GTK_IS_MEDIA_FILE (self), NULL); + + return priv->input_stream; +} |