gtk: Add GtkMediaFile

GtkMediaFile is an implementation of GtkMediaStream to play back files.

Except it isn't an implementation yet, but only an interface.
This commit is contained in:
Benjamin Otte 2018-02-27 17:01:50 +01:00
parent 4db1a5f5c4
commit 29cccf5e84
4 changed files with 613 additions and 0 deletions

View File

@ -137,6 +137,7 @@
#include <gtk/gtkliststore.h>
#include <gtk/gtklockbutton.h>
#include <gtk/gtkmain.h>
#include <gtk/gtkmediafile.h>
#include <gtk/gtkmediastream.h>
#include <gtk/gtkmenu.h>
#include <gtk/gtkmenubar.h>

526
gtk/gtkmediafile.c Normal file
View File

@ -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;
}

84
gtk/gtkmediafile.h Normal file
View File

@ -0,0 +1,84 @@
/*
* 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_MEDIA_FILE_H__
#define __GTK_MEDIA_FILE_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkmediastream.h>
G_BEGIN_DECLS
#define GTK_TYPE_MEDIA_FILE (gtk_media_file_get_type ())
GDK_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (GtkMediaFile, gtk_media_file, GTK, MEDIA_FILE, GtkMediaStream)
struct _GtkMediaFileClass
{
GtkMediaStreamClass parent_class;
void (* open) (GtkMediaFile *self);
void (* close) (GtkMediaFile *self);
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
};
GDK_AVAILABLE_IN_ALL
GtkMediaStream * gtk_media_file_new (void);
GDK_AVAILABLE_IN_ALL
GtkMediaStream * gtk_media_file_new_for_filename (const char *filename);
GDK_AVAILABLE_IN_ALL
GtkMediaStream * gtk_media_file_new_for_resource (const char *resource_path);
GDK_AVAILABLE_IN_ALL
GtkMediaStream * gtk_media_file_new_for_file (GFile *file);
GDK_AVAILABLE_IN_ALL
GtkMediaStream * gtk_media_file_new_for_input_stream (GInputStream *stream);
GDK_AVAILABLE_IN_ALL
void gtk_media_file_clear (GtkMediaFile *self);
GDK_AVAILABLE_IN_ALL
void gtk_media_file_set_filename (GtkMediaFile *self,
const char *filename);
GDK_AVAILABLE_IN_ALL
void gtk_media_file_set_resource (GtkMediaFile *self,
const char *resource_path);
GDK_AVAILABLE_IN_ALL
void gtk_media_file_set_file (GtkMediaFile *self,
GFile *file);
GDK_AVAILABLE_IN_ALL
GFile * gtk_media_file_get_file (GtkMediaFile *self);
GDK_AVAILABLE_IN_ALL
void gtk_media_file_set_input_stream (GtkMediaFile *self,
GInputStream *stream);
GDK_AVAILABLE_IN_ALL
GInputStream * gtk_media_file_get_input_stream (GtkMediaFile *self);
G_END_DECLS
#endif /* __GTK_MEDIA_FILE_H__ */

View File

@ -251,6 +251,7 @@ gtk_public_sources = files([
'gtkliststore.c',
'gtklockbutton.c',
'gtkmain.c',
'gtkmediafile.c',
'gtkmediastream.c',
'gtkmenu.c',
'gtkmenubar.c',
@ -481,6 +482,7 @@ gtk_public_headers = files([
'gtkliststore.h',
'gtklockbutton.h',
'gtkmain.h',
'gtkmediafile.h',
'gtkmediastream.h',
'gtkmenu.h',
'gtkmenubar.h',