Commit 25f85868 authored by Benjamin Otte's avatar Benjamin Otte

implement URI schemes

Original commit message from CVS:
implement URI schemes
Elements can now register as a source or sink for a protocol and applications can use gst_element_make_from_uri () to get an element that handles a given URI.
This patch provides:
- removal of old broken URI handling scheme.
- new URI handling using interfaces.
- updates for registry to save handled URIs.
- interface for URI handlers.
- implementation of that in filesrc and filesink for the file:// URI
- extension to pipeline parsing to allow specifying only a URI instead of element

Does not include:
- tests
- inclusion in docs build
parent 4e8fb086
......@@ -10248,6 +10248,15 @@ Destroy the scheduler
@parent:
@Returns:
<!-- ##### FUNCTION gst_uri_handler_create ##### -->
<para>
</para>
@handler:
@name:
@Returns:
<!-- ##### FUNCTION gst_uri_handler_destroy ##### -->
<para>
......@@ -10255,6 +10264,43 @@ Destroy the scheduler
@handler:
<!-- ##### FUNCTION gst_uri_handler_find ##### -->
<para>
</para>
@name:
@Returns:
<!-- ##### FUNCTION gst_uri_handler_find_by_uri ##### -->
<para>
</para>
@uri:
@Returns:
<!-- ##### FUNCTION gst_uri_handler_make_by_uri ##### -->
<para>
</para>
@uri:
@name:
@Returns:
<!-- ##### FUNCTION gst_uri_handler_new ##### -->
<para>
</para>
@name:
@uri:
@longdesc:
@element:
@property:
@Returns:
<!-- ##### FUNCTION gst_util_get_bool_arg ##### -->
<para>
......
......@@ -15,54 +15,3 @@ and the element property that can handle a given URI.
</para>
<!-- ##### FUNCTION gst_uri_handler_new ##### -->
<para>
</para>
@name:
@uri:
@longdesc:
@element:
@property:
@Returns:
<!-- ##### FUNCTION gst_uri_handler_find ##### -->
<para>
</para>
@name:
@Returns:
<!-- ##### FUNCTION gst_uri_handler_find_by_uri ##### -->
<para>
</para>
@uri:
@Returns:
<!-- ##### FUNCTION gst_uri_handler_create ##### -->
<para>
</para>
@handler:
@name:
@Returns:
<!-- ##### FUNCTION gst_uri_handler_make_by_uri ##### -->
<para>
</para>
@uri:
@name:
@Returns:
......@@ -173,7 +173,7 @@ gst_fakesink_class_init (GstFakeSinkClass *klass)
gst_fakesink_signals[SIGNAL_HANDOFF] =
g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstFakeSinkClass, handoff), NULL, NULL,
gst_marshal_VOID__POINTER_OBJECT, G_TYPE_NONE, 1,
gst_marshal_VOID__POINTER_OBJECT, G_TYPE_NONE, 2,
GST_TYPE_BUFFER, GST_TYPE_PAD);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesink_set_property);
......
......@@ -69,6 +69,7 @@ GST_PAD_FORMATS_FUNCTION (gst_filesink_get_formats,
static void gst_filesink_base_init (gpointer g_class);
static void gst_filesink_class_init (GstFileSinkClass *klass);
static void gst_filesink_init (GstFileSink *filesink);
static void gst_filesink_dispose (GObject *object);
static void gst_filesink_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
......@@ -83,6 +84,8 @@ static gboolean gst_filesink_pad_query (GstPad *pad, GstQueryType type,
GstFormat *format, gint64 *value);
static void gst_filesink_chain (GstPad *pad,GstData *_data);
static void gst_filesink_uri_handler_init (gpointer g_iface, gpointer iface_data);
static GstElementStateReturn gst_filesink_change_state (GstElement *element);
static GstElementClass *parent_class = NULL;
......@@ -105,7 +108,14 @@ gst_filesink_get_type (void)
0,
(GInstanceInitFunc)gst_filesink_init,
};
static const GInterfaceInfo urihandler_info = {
gst_filesink_uri_handler_init,
NULL,
NULL
};
filesink_type = g_type_register_static (GST_TYPE_ELEMENT, "GstFileSink", &filesink_info, 0);
g_type_add_interface_static (filesink_type, GST_TYPE_URI_HANDLER, &urihandler_info);
GST_DEBUG_CATEGORY_INIT (gst_filesink_debug, "filesink", 0, "filesink element");
}
......@@ -138,8 +148,8 @@ gst_filesink_class_init (GstFileSinkClass *klass)
gobject_class->set_property = gst_filesink_set_property;
gobject_class->get_property = gst_filesink_get_property;
gobject_class->dispose = gst_filesink_dispose;
}
static void
gst_filesink_init (GstFileSink *filesink)
{
......@@ -158,7 +168,38 @@ gst_filesink_init (GstFileSink *filesink)
filesink->filename = NULL;
filesink->file = NULL;
}
static void
gst_filesink_dispose (GObject *object)
{
GstFileSink *sink = GST_FILESINK (object);
G_OBJECT_CLASS (parent_class)->dispose (object);
g_free (sink->uri);
sink->uri = NULL;
g_free (sink->filename);
sink->filename = NULL;
}
static gboolean
gst_filesink_set_location (GstFileSink *sink, const gchar *location)
{
/* the element must be stopped or paused in order to do this */
if (GST_STATE (sink) > GST_STATE_PAUSED)
return FALSE;
if (GST_STATE (sink) == GST_STATE_PAUSED &&
GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN))
return FALSE;
g_free (sink->filename);
g_free (sink->uri);
sink->filename = g_strdup (location);
sink->uri = gst_uri_construct ("file", location);
if (GST_STATE (sink) == GST_STATE_PAUSED)
gst_filesink_open_file (sink);
return TRUE;
}
static void
gst_filesink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
......@@ -169,16 +210,7 @@ gst_filesink_set_property (GObject *object, guint prop_id, const GValue *value,
switch (prop_id) {
case ARG_LOCATION:
/* the element must be stopped or paused in order to do this */
g_return_if_fail (GST_STATE (sink) <= GST_STATE_PAUSED);
if (GST_STATE (sink) == GST_STATE_PAUSED)
g_return_if_fail (!GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN));
if (sink->filename)
g_free (sink->filename);
sink->filename = g_strdup (g_value_get_string (value));
if (GST_STATE (sink) == GST_STATE_PAUSED)
gst_filesink_open_file (sink);
gst_filesink_set_location (sink, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
......@@ -435,3 +467,54 @@ gst_filesink_change_state (GstElement *element)
return GST_STATE_SUCCESS;
}
/*** GSTURIHANDLER INTERFACE *************************************************/
static guint
gst_filesink_uri_get_type (void)
{
return GST_URI_SINK;
}
static gchar **
gst_filesink_uri_get_protocols(void)
{
static gchar *protocols[] = {"file", NULL};
return protocols;
}
static const gchar *
gst_filesink_uri_get_uri (GstURIHandler *handler)
{
GstFileSink *sink = GST_FILESINK (handler);
return sink->uri;
}
static gboolean
gst_filesink_uri_set_uri (GstURIHandler *handler, const gchar *uri)
{
gchar *protocol, *location;
gboolean ret;
GstFileSink *sink = GST_FILESINK (handler);
protocol = gst_uri_get_protocol (uri);
if (strcmp (protocol, "file") != 0) {
g_free (protocol);
return FALSE;
}
g_free (protocol);
location = gst_uri_get_location (uri);
ret = gst_filesink_set_location (sink, location);
g_free (location);
return ret;
}
static void
gst_filesink_uri_handler_init (gpointer g_iface, gpointer iface_data)
{
GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
iface->get_type = gst_filesink_uri_get_type;
iface->get_protocols = gst_filesink_uri_get_protocols;
iface->get_uri = gst_filesink_uri_get_uri;
iface->set_uri = gst_filesink_uri_set_uri;
}
......@@ -53,6 +53,7 @@ struct _GstFileSink {
GstElement element;
gchar *filename;
gchar *uri;
FILE *file;
guint64 data_written;
......
......@@ -136,6 +136,8 @@ static gboolean gst_filesrc_srcpad_query (GstPad *pad, GstQueryType type,
static GstElementStateReturn gst_filesrc_change_state (GstElement *element);
static void gst_filesrc_uri_handler_init (gpointer g_iface, gpointer iface_data);
static GstElementClass *parent_class = NULL;
/*static guint gst_filesrc_signals[LAST_SIGNAL] = { 0 };*/
......@@ -157,8 +159,15 @@ gst_filesrc_get_type(void)
0,
(GInstanceInitFunc)gst_filesrc_init,
};
static const GInterfaceInfo urihandler_info = {
gst_filesrc_uri_handler_init,
NULL,
NULL
};
filesrc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstFileSrc", &filesrc_info, 0);
g_type_add_interface_static (filesrc_type, GST_TYPE_URI_HANDLER, &urihandler_info);
GST_DEBUG_CATEGORY_INIT (gst_filesrc_debug, "filesrc", 0, "filesrc element");
}
return filesrc_type;
......@@ -263,8 +272,32 @@ gst_filesrc_dispose (GObject *object)
g_mutex_free (src->map_regions_lock);
if (src->filename)
g_free (src->filename);
if (src->uri)
g_free (src->uri);
}
static gboolean
gst_filesrc_set_location (GstFileSrc *src, const gchar *location)
{
/* the element must be stopped in order to do this */
if (GST_STATE (src) == GST_STATE_PLAYING)
return FALSE;
if (src->filename) g_free (src->filename);
if (src->uri) g_free (src->uri);
/* clear the filename if we get a NULL (is that possible?) */
if (location == NULL) {
src->filename = NULL;
src->uri = NULL;
} else {
src->filename = g_strdup (location);
src->uri = gst_uri_construct ("file", src->filename);
}
g_object_notify (G_OBJECT (src), "location");
gst_uri_handler_new_uri (GST_URI_HANDLER (src), src->uri);
return TRUE;
}
static void
gst_filesrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
......@@ -278,19 +311,7 @@ gst_filesrc_set_property (GObject *object, guint prop_id, const GValue *value, G
switch (prop_id) {
case ARG_LOCATION:
/* the element must be stopped in order to do this */
g_return_if_fail (GST_STATE (src) < GST_STATE_PLAYING);
if (src->filename) g_free (src->filename);
/* clear the filename if we get a NULL (is that possible?) */
if (g_value_get_string (value) == NULL) {
gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL);
src->filename = NULL;
/* otherwise set the new filename */
} else {
src->filename = g_strdup (g_value_get_string (value));
}
g_object_notify (G_OBJECT (src), "location");
gst_filesrc_set_location (src, g_value_get_string (value));
break;
case ARG_BLOCKSIZE:
src->block_size = g_value_get_ulong (value);
......@@ -918,3 +939,55 @@ error:
gst_event_unref (event);
return FALSE;
}
/*** GSTURIHANDLER INTERFACE *************************************************/
static guint
gst_filesrc_uri_get_type (void)
{
return GST_URI_SRC;
}
static gchar **
gst_filesrc_uri_get_protocols(void)
{
static gchar *protocols[] = {"file", NULL};
return protocols;
}
static const gchar *
gst_filesrc_uri_get_uri (GstURIHandler *handler)
{
GstFileSrc *src = GST_FILESRC (handler);
return src->uri;
}
static gboolean
gst_filesrc_uri_set_uri (GstURIHandler *handler, const gchar *uri)
{
gchar *protocol, *location;
gboolean ret;
GstFileSrc *src = GST_FILESRC (handler);
protocol = gst_uri_get_protocol (uri);
if (strcmp (protocol, "file") != 0) {
g_free (protocol);
return FALSE;
}
g_free (protocol);
location = gst_uri_get_location (uri);
ret = gst_filesrc_set_location (src, location);
g_free (location);
return ret;
}
static void
gst_filesrc_uri_handler_init (gpointer g_iface, gpointer iface_data)
{
GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
iface->get_type = gst_filesrc_uri_get_type;
iface->get_protocols = gst_filesrc_uri_get_protocols;
iface->get_uri = gst_filesrc_uri_get_uri;
iface->set_uri = gst_filesrc_uri_set_uri;
}
......@@ -58,6 +58,7 @@ struct _GstFileSrc {
guint pagesize; /* system page size*/
gchar *filename; /* filename */
gchar *uri; /* caching the URI */
gint fd; /* open file descriptor*/
off_t filelen; /* what's the file length?*/
......
......@@ -398,7 +398,11 @@ struct _GstElementFactory {
GList * padtemplates;
guint numpadtemplates;
GList *interfaces; /* interfaces this element implements */
/* URI interface stuff */
guint uri_type;
gchar ** uri_protocols;
GList * interfaces; /* interfaces this element implements */
GST_OBJECT_PADDING
};
......@@ -423,8 +427,10 @@ G_CONST_RETURN gchar * gst_element_factory_get_klass (GstElementFactory *factor
G_CONST_RETURN gchar * gst_element_factory_get_description (GstElementFactory *factory);
G_CONST_RETURN gchar * gst_element_factory_get_version (GstElementFactory *factory);
G_CONST_RETURN gchar * gst_element_factory_get_author (GstElementFactory *factory);
guint gst_element_factory_get_num_pad_templates (GstElementFactory *factory);
G_CONST_RETURN GList * gst_element_factory_get_pad_templates (GstElementFactory *factory);
guint gst_element_factory_get_num_padtemplates (GstElementFactory *factory);
G_CONST_RETURN GList * gst_element_factory_get_padtemplates (GstElementFactory *factory);
guint gst_element_factory_get_uri_type (GstElementFactory *factory);
gchar ** gst_element_factory_get_uri_protocols (GstElementFactory *factory);
GstElement* gst_element_factory_create (GstElementFactory *factory,
const gchar *name);
......
......@@ -26,6 +26,7 @@
#include "gstelement.h"
#include "gstregistrypool.h"
#include "gstinfo.h"
#include "gsturi.h"
GST_DEBUG_CATEGORY_STATIC (element_factory_debug);
#define GST_CAT_DEFAULT element_factory_debug
......@@ -85,6 +86,9 @@ gst_element_factory_init (GstElementFactory *factory)
factory->padtemplates = NULL;
factory->numpadtemplates = 0;
factory->uri_type = GST_URI_UNKNOWN;
factory->uri_protocols = NULL;
factory->interfaces = NULL;
}
/**
......@@ -150,6 +154,11 @@ gst_element_factory_cleanup (GstElementFactory *factory)
g_list_free (factory->padtemplates);
factory->padtemplates = NULL;
factory->numpadtemplates = 0;
factory->uri_type = GST_URI_UNKNOWN;
if (factory->uri_protocols) {
g_strfreev (factory->uri_protocols);
factory->uri_protocols = NULL;
}
g_list_foreach (factory->interfaces, (GFunc) g_free, NULL);
g_list_free (factory->interfaces);
......@@ -198,6 +207,20 @@ gst_element_register (GstPlugin *plugin, const gchar *name, guint rank, GType ty
g_list_foreach (factory->padtemplates, (GFunc) g_object_ref, NULL);
factory->numpadtemplates = klass->numpadtemplates;
/* special stuff for URI handling */
if (g_type_is_a (type, GST_TYPE_URI_HANDLER)) {
GstURIHandlerInterface *iface = (GstURIHandlerInterface *)
g_type_interface_peek (klass, GST_TYPE_URI_HANDLER);
if (!iface || !iface->get_type || !iface->get_protocols)
goto error;
factory->uri_type = iface->get_type ();
if (!GST_URI_TYPE_IS_VALID (factory->uri_type))
goto error;
factory->uri_protocols = g_strdupv (iface->get_protocols ());
if (!factory->uri_protocols)
goto error;
}
interfaces = g_type_interfaces (type, &n_interfaces);
for (i = 0; i < n_interfaces; i++) {
__gst_element_factory_add_interface (factory, g_type_name (interfaces[i]));
......@@ -205,10 +228,13 @@ gst_element_register (GstPlugin *plugin, const gchar *name, guint rank, GType ty
g_free (interfaces);
gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE (factory), rank);
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
return TRUE;
error:
gst_element_factory_cleanup (factory);
return FALSE;
}
/**
* gst_element_factory_create:
......@@ -422,7 +448,7 @@ __gst_element_factory_add_interface (GstElementFactory *elementfactory, const gc
* gst_element_factory_get_pad_templates:
* @factory: a #GstElementFactory
*
* Gets the #Glist of pad templates for this factory.
* Gets the #GList of padtemplates for this factory.
*
* Returns: the padtemplates
*/
......@@ -433,6 +459,38 @@ gst_element_factory_get_pad_templates (GstElementFactory *factory)
return factory->padtemplates;
}
/**
* gst_element_factory_get_uri_type:
* @factory: a #GstElementFactory
*
* Gets the type of URIs the element supports or GST_URI_UNKNOWN if none.
*
* Returns: type of URIs this element supports
*/
guint
gst_element_factory_get_uri_type (GstElementFactory *factory)
{
g_return_val_if_fail (GST_IS_ELEMENT_FACTORY (factory), GST_URI_UNKNOWN);
return factory->uri_type;
}
/**
* gst_element_factory_get_uri_protocols:
* @factory: a #GstElementFactory
*
* Gets a NULL-terminated array of protocols this element supports or NULL, if
* no protocols are supported. You may not change the contents of the returned
* array as it is still ownt by the element factory. Use g_strdupv() if you want to.
*
* Returns: the supported protocols or NULL
*/
gchar **
gst_element_factory_get_uri_protocols (GstElementFactory *factory)
{
g_return_val_if_fail (GST_IS_ELEMENT_FACTORY (factory), NULL);
return factory->uri_protocols;
}
/**
* gst_element_factory_can_src_caps :
* @factory: factory to query
......
......@@ -147,7 +147,7 @@ gst_plugin_feature_type_name_filter (GstPluginFeature *feature,
* the most appropriate feature.
*/
void
gst_plugin_feature_set_rank (GstPluginFeature *feature, guint16 rank)
gst_plugin_feature_set_rank (GstPluginFeature *feature, guint rank)
{
g_return_if_fail (feature != NULL);
g_return_if_fail (GST_IS_PLUGIN_FEATURE (feature));
......@@ -155,7 +155,7 @@ gst_plugin_feature_set_rank (GstPluginFeature *feature, guint16 rank)
feature->rank = rank;
}
/**
* gst_plugin_feature_set_rank:
* gst_plugin_feature_set_name:
* @feature: a feature
* @name: the name to set
*
......@@ -175,4 +175,34 @@ gst_plugin_feature_set_name (GstPluginFeature *feature, const gchar *name)
feature->name = g_strdup (name);
}
}
/**
* gst_plugin_feature_get rank:
* @feature: a feature
*
* Gets the rank of a plugin feature.
*
* Returns: The rank of the feature
*/
guint
gst_plugin_feature_get_rank (GstPluginFeature *feature)
{
g_return_val_if_fail (GST_IS_PLUGIN_FEATURE (feature), GST_RANK_NONE);
return feature->rank;
}
/**
* gst_plugin_feature_set_name:
* @feature: a feature
*
* Gets the name of a pluginfeature.
*
* Returns: the name
*/
G_CONST_RETURN gchar *
gst_plugin_feature_get_name (GstPluginFeature *feature)
{
g_return_val_if_fail (GST_IS_PLUGIN_FEATURE (feature), NULL);
return feature->name;
}
......@@ -44,10 +44,10 @@ typedef struct _GstPluginFeatureClass GstPluginFeatureClass;
struct _GstPluginFeature {
GObject object;
/*< private >*/
gchar *name;
gint rank;