gst_plugins_base/ext/gnomevfs/gstgnomevfssink.c
branchRCL_3
changeset 30 7e817e7e631c
parent 0 0e761a78d257
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gst_plugins_base/ext/gnomevfs/gstgnomevfssink.c	Wed Sep 01 12:16:41 2010 +0100
@@ -0,0 +1,641 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ *                    2001 Bastien Nocera <hadess@hadess.net>
+ *                    2003 Colin Walters <walters@verbum.org>
+ *                    2005 Tim-Philipp Müller <tim centricular net>
+ *
+ * gstgnomevfssink.c: 
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-gnomevfssink
+ * @short_description: Write a stream to a GnomeVFS URI
+ * @see_also: #GstFileSink, #GstGnomeVFSSrc
+ *
+ * <refsect2>
+ * <para>
+ * This plugin writes incoming data to a local or remote location specified
+ * by an URI. This location can be specified using any protocol supported by
+ * the GnomeVFS library. Common protocols are 'file', 'ftp', or 'smb'.
+ * </para>
+ * <para>
+ * Example pipeline:
+ * <programlisting>
+ * gst-launch -v filesrc location=input.xyz ! gnomevfssink location=file:///home/joe/out.xyz
+ * </programlisting>
+ * The above pipeline will simply copy a local file. Instead of gnomevfssink,
+ * we could just as well have used the filesink element here.
+ * </para>
+ * <para>
+ * Another example pipeline:
+ * <programlisting>
+ * gst-launch -v filesrc location=foo.mp3 ! mad ! flacenc ! gnomevfssink location=smb://othercomputer/foo.flac
+ * </programlisting>
+ * The above pipeline will re-encode an mp3 file into FLAC format and store
+ * it on a remote host using the Samba protocol.
+ * </para>
+ * <para>
+ * Applications can connect to the allow-overwrite signal to receive a callback when an
+ * existing file will be overwritten. The return value of the signal will determine if
+ * gnomevfssink will overwrite the resource or abort with an error.
+ * </para>
+ * </refsect2>
+ *
+ * Last reviewed on 2006-02-28 (0.10.4)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstgnomevfssink.h"
+
+#include "gst/gst-i18n-plugin.h"
+
+#include <gst/gst.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <string.h>
+#include <errno.h>
+
+static const GstElementDetails gst_gnome_vfs_sink_details =
+GST_ELEMENT_DETAILS ("GnomeVFS Sink",
+    "Sink/File",
+    "Write a stream to a GnomeVFS URI",
+    "Bastien Nocera <hadess@hadess.net>");
+
+enum
+{
+  SIGNAL_ERASE_ASK,
+  LAST_SIGNAL
+};
+
+enum
+{
+  ARG_0,
+  ARG_LOCATION,
+  ARG_URI,
+  ARG_HANDLE
+};
+
+static void gst_gnome_vfs_sink_finalize (GObject * obj);
+
+static void gst_gnome_vfs_sink_uri_handler_init (gpointer g_iface,
+    gpointer iface_data);
+
+static void gst_gnome_vfs_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gnome_vfs_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_gnome_vfs_sink_open_file (GstGnomeVFSSink * sink);
+static void gst_gnome_vfs_sink_close_file (GstGnomeVFSSink * sink);
+static gboolean gst_gnome_vfs_sink_start (GstBaseSink * basesink);
+static gboolean gst_gnome_vfs_sink_stop (GstBaseSink * basesink);
+static GstFlowReturn gst_gnome_vfs_sink_render (GstBaseSink * basesink,
+    GstBuffer * buffer);
+static gboolean gst_gnome_vfs_sink_handle_event (GstBaseSink * basesink,
+    GstEvent * event);
+static gboolean gst_gnome_vfs_sink_query (GstPad * pad, GstQuery * query);
+
+static guint gst_gnome_vfs_sink_signals[LAST_SIGNAL];   /* all 0 */
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (gst_gnome_vfs_sink_debug);
+#define GST_CAT_DEFAULT gst_gnome_vfs_sink_debug
+
+static void
+gst_gnome_vfs_sink_do_init (GType type)
+{
+  static const GInterfaceInfo urihandler_info = {
+    gst_gnome_vfs_sink_uri_handler_init,
+    NULL,
+    NULL
+  };
+
+  g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
+
+  GST_DEBUG_CATEGORY_INIT (gst_gnome_vfs_sink_debug, "gnomevfssink", 0,
+      "Gnome VFS sink element");
+}
+
+GST_BOILERPLATE_FULL (GstGnomeVFSSink, gst_gnome_vfs_sink, GstBaseSink,
+    GST_TYPE_BASE_SINK, gst_gnome_vfs_sink_do_init);
+
+static void
+gst_gnome_vfs_sink_base_init (gpointer g_class)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&sinktemplate));
+
+  gst_element_class_set_details (element_class, &gst_gnome_vfs_sink_details);
+}
+
+static gboolean
+_gst_boolean_allow_overwrite_accumulator (GSignalInvocationHint * ihint,
+    GValue * return_accu, const GValue * handler_return, gpointer dummy)
+{
+  gboolean allow_overwrite;
+
+  allow_overwrite = g_value_get_boolean (handler_return);
+  if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
+    g_value_set_boolean (return_accu, allow_overwrite);
+
+  /* stop emission if signal doesn't allow overwriting */
+  return allow_overwrite;
+}
+
+static void
+gst_gnome_vfs_sink_class_init (GstGnomeVFSSinkClass * klass)
+{
+  GstBaseSinkClass *basesink_class;
+  GObjectClass *gobject_class;
+
+  gobject_class = (GObjectClass *) klass;
+  basesink_class = (GstBaseSinkClass *) klass;
+
+  gobject_class->set_property = gst_gnome_vfs_sink_set_property;
+  gobject_class->get_property = gst_gnome_vfs_sink_get_property;
+  gobject_class->finalize = gst_gnome_vfs_sink_finalize;
+
+  g_object_class_install_property (gobject_class, ARG_LOCATION,
+      g_param_spec_string ("location", "File Location",
+          "Location of the file to write", NULL, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, ARG_URI,
+      g_param_spec_boxed ("uri", "GnomeVFSURI", "URI for GnomeVFS",
+          GST_TYPE_GNOME_VFS_URI, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, ARG_HANDLE,
+      g_param_spec_boxed ("handle",
+          "GnomeVFSHandle", "Handle for GnomeVFS",
+          GST_TYPE_GNOME_VFS_HANDLE, G_PARAM_READWRITE));
+
+  /**
+   * GstGnomeVFSSink::allow-overwrite
+   * @sink: the object which received the signal
+   * @uri: the URI to be overwritten
+   *
+   * This signal is fired when gnomevfssink is about to overwrite an
+   * existing resource. The application can connect to this signal and ask
+   * the user if the resource may be overwritten. 
+   *
+   * Returns: A boolean indicating that the resource may be overwritten.
+   */
+  gst_gnome_vfs_sink_signals[SIGNAL_ERASE_ASK] =
+      g_signal_new ("allow-overwrite", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_CLEANUP, G_STRUCT_OFFSET (GstGnomeVFSSinkClass, erase_ask),
+      _gst_boolean_allow_overwrite_accumulator, NULL,
+      gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, GST_TYPE_GNOME_VFS_URI);
+
+  basesink_class->stop = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_stop);
+  basesink_class->start = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_start);
+  basesink_class->event = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_handle_event);
+  basesink_class->render = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_render);
+  basesink_class->get_times = NULL;
+}
+
+static void
+gst_gnome_vfs_sink_finalize (GObject * obj)
+{
+  GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (obj);
+
+  if (sink->uri) {
+    gnome_vfs_uri_unref (sink->uri);
+    sink->uri = NULL;
+  }
+
+  if (sink->uri_name) {
+    g_free (sink->uri_name);
+    sink->uri_name = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_gnome_vfs_sink_init (GstGnomeVFSSink * sink, GstGnomeVFSSinkClass * klass)
+{
+  gst_pad_set_query_function (GST_BASE_SINK_PAD (sink),
+      GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_query));
+
+  sink->uri = NULL;
+  sink->uri_name = NULL;
+  sink->handle = NULL;
+  sink->own_handle = FALSE;
+  sink->current_pos = 0;
+
+  GST_BASE_SINK (sink)->sync = FALSE;
+}
+
+static void
+gst_gnome_vfs_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstGnomeVFSSink *sink;
+  GstState cur_state;
+
+  sink = GST_GNOME_VFS_SINK (object);
+
+  gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0);
+
+  if (cur_state == GST_STATE_PLAYING || cur_state == GST_STATE_PAUSED) {
+    GST_WARNING_OBJECT (sink, "cannot set property when PAUSED or PLAYING");
+    return;
+  }
+
+  GST_OBJECT_LOCK (sink);
+
+  switch (prop_id) {
+    case ARG_LOCATION:{
+      const gchar *new_location;
+
+      if (sink->uri) {
+        gnome_vfs_uri_unref (sink->uri);
+        sink->uri = NULL;
+      }
+      if (sink->uri_name) {
+        g_free (sink->uri_name);
+        sink->uri_name = NULL;
+      }
+
+      new_location = g_value_get_string (value);
+      if (new_location) {
+        sink->uri_name = gst_gnome_vfs_location_to_uri_string (new_location);
+        sink->uri = gnome_vfs_uri_new (sink->uri_name);
+      }
+      break;
+    }
+    case ARG_URI:{
+      if (sink->uri) {
+        gnome_vfs_uri_unref (sink->uri);
+        sink->uri = NULL;
+      }
+      if (sink->uri_name) {
+        g_free (sink->uri_name);
+        sink->uri_name = NULL;
+      }
+      if (g_value_get_boxed (value)) {
+        sink->uri = (GnomeVFSURI *) g_value_dup_boxed (value);
+        sink->uri_name = gnome_vfs_uri_to_string (sink->uri, 0);
+      }
+      break;
+    }
+    case ARG_HANDLE:{
+      if (sink->uri) {
+        gnome_vfs_uri_unref (sink->uri);
+        sink->uri = NULL;
+      }
+      if (sink->uri_name) {
+        g_free (sink->uri_name);
+        sink->uri_name = NULL;
+      }
+      sink->handle = g_value_get_boxed (value);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  GST_OBJECT_UNLOCK (sink);
+}
+
+static void
+gst_gnome_vfs_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstGnomeVFSSink *sink;
+
+  sink = GST_GNOME_VFS_SINK (object);
+
+  GST_OBJECT_LOCK (sink);
+
+  switch (prop_id) {
+    case ARG_LOCATION:
+      g_value_set_string (value, sink->uri_name);
+      break;
+    case ARG_URI:
+      g_value_set_boxed (value, sink->uri);
+      break;
+    case ARG_HANDLE:
+      g_value_set_boxed (value, sink->handle);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  GST_OBJECT_UNLOCK (sink);
+}
+
+static gboolean
+gst_gnome_vfs_sink_open_file (GstGnomeVFSSink * sink)
+{
+  GnomeVFSResult result;
+
+  if (sink->uri) {
+    /* open the file, all permissions, umask will apply */
+    result = gnome_vfs_create_uri (&(sink->handle), sink->uri,
+        GNOME_VFS_OPEN_WRITE, TRUE,
+        GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE |
+        GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_WRITE |
+        GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_OTHER_WRITE);
+
+    /* if the file existed and the property says to ask, then ask! */
+    if (result == GNOME_VFS_ERROR_FILE_EXISTS) {
+      gboolean erase_anyway = FALSE;
+
+      g_signal_emit (G_OBJECT (sink),
+          gst_gnome_vfs_sink_signals[SIGNAL_ERASE_ASK], 0, sink->uri,
+          &erase_anyway);
+      if (erase_anyway) {
+        result = gnome_vfs_create_uri (&(sink->handle), sink->uri,
+            GNOME_VFS_OPEN_WRITE, FALSE,
+            GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE |
+            GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_WRITE |
+            GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_OTHER_WRITE);
+      }
+    }
+
+    GST_DEBUG_OBJECT (sink, "open: %s", gnome_vfs_result_to_string (result));
+
+    if (result != GNOME_VFS_OK) {
+      gchar *filename = gnome_vfs_uri_to_string (sink->uri,
+          GNOME_VFS_URI_HIDE_PASSWORD);
+
+      GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
+          (_("Could not open vfs file \"%s\" for writing: %s."),
+              filename, gnome_vfs_result_to_string (result)), GST_ERROR_SYSTEM);
+      g_free (filename);
+      return FALSE;
+    }
+    sink->own_handle = TRUE;
+  } else if (!sink->handle) {
+    GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (_("No filename given")),
+        (NULL));
+    return FALSE;
+  } else {
+    sink->own_handle = FALSE;
+  }
+
+  sink->current_pos = 0;
+
+  return TRUE;
+}
+
+static void
+gst_gnome_vfs_sink_close_file (GstGnomeVFSSink * sink)
+{
+  GnomeVFSResult result;
+
+  if (sink->own_handle) {
+    /* close the file */
+    result = gnome_vfs_close (sink->handle);
+
+    if (result != GNOME_VFS_OK) {
+      gchar *filename = gnome_vfs_uri_to_string (sink->uri,
+          GNOME_VFS_URI_HIDE_PASSWORD);
+
+      GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE,
+          (_("Could not close vfs file \"%s\"."), filename), GST_ERROR_SYSTEM);
+      g_free (filename);
+    }
+
+    sink->own_handle = FALSE;
+    sink->handle = NULL;
+  }
+}
+
+static gboolean
+gst_gnome_vfs_sink_start (GstBaseSink * basesink)
+{
+  gboolean ret;
+
+  ret = gst_gnome_vfs_sink_open_file (GST_GNOME_VFS_SINK (basesink));
+
+  return ret;
+}
+
+static gboolean
+gst_gnome_vfs_sink_stop (GstBaseSink * basesink)
+{
+  GST_DEBUG_OBJECT (basesink, "closing ...");
+  gst_gnome_vfs_sink_close_file (GST_GNOME_VFS_SINK (basesink));
+  return TRUE;
+}
+
+static gboolean
+gst_gnome_vfs_sink_handle_event (GstBaseSink * basesink, GstEvent * event)
+{
+  GstGnomeVFSSink *sink;
+  gboolean ret = TRUE;
+
+  sink = GST_GNOME_VFS_SINK (basesink);
+
+  GST_DEBUG_OBJECT (sink, "processing %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_NEWSEGMENT:{
+      GnomeVFSResult res;
+      GstFormat format;
+      gint64 offset;
+
+      gst_event_parse_new_segment (event, NULL, NULL, &format, &offset,
+          NULL, NULL);
+
+      if (format != GST_FORMAT_BYTES) {
+        GST_WARNING_OBJECT (sink, "ignored NEWSEGMENT event in %s format",
+            gst_format_get_name (format));
+        break;
+      }
+
+      GST_LOG_OBJECT (sink, "seeking to offset %" G_GINT64_FORMAT, offset);
+      res = gnome_vfs_seek (sink->handle, GNOME_VFS_SEEK_START, offset);
+
+      if (res != GNOME_VFS_OK) {
+        GST_ERROR_OBJECT (sink, "Failed to seek to offset %"
+            G_GINT64_FORMAT ": %s", offset, gnome_vfs_result_to_string (res));
+        ret = FALSE;
+      } else {
+        sink->current_pos = offset;
+      }
+
+      break;
+    }
+
+    case GST_EVENT_FLUSH_START:
+    case GST_EVENT_EOS:{
+      /* No need to flush with GnomeVfs */
+      break;
+    }
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_gnome_vfs_sink_query (GstPad * pad, GstQuery * query)
+{
+  GstGnomeVFSSink *sink;
+  GstFormat format;
+
+  sink = GST_GNOME_VFS_SINK (GST_PAD_PARENT (pad));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:
+      gst_query_parse_position (query, &format, NULL);
+      switch (format) {
+        case GST_FORMAT_DEFAULT:
+        case GST_FORMAT_BYTES:
+          gst_query_set_position (query, GST_FORMAT_BYTES, sink->current_pos);
+          return TRUE;
+        default:
+          return FALSE;
+      }
+
+    case GST_QUERY_FORMATS:
+      gst_query_set_formats (query, 2, GST_FORMAT_DEFAULT, GST_FORMAT_BYTES);
+      return TRUE;
+
+    default:
+      return gst_pad_query_default (pad, query);
+  }
+}
+
+static GstFlowReturn
+gst_gnome_vfs_sink_render (GstBaseSink * basesink, GstBuffer * buf)
+{
+  GnomeVFSFileSize written, cur_pos;
+  GstGnomeVFSSink *sink;
+  GnomeVFSResult result;
+  GstFlowReturn ret;
+
+  sink = GST_GNOME_VFS_SINK (basesink);
+
+  if (gnome_vfs_tell (sink->handle, &cur_pos) == GNOME_VFS_OK) {
+    /* bring up to date with current position for proper reporting */
+    sink->current_pos = cur_pos;
+  }
+
+  result = gnome_vfs_write (sink->handle, GST_BUFFER_DATA (buf),
+      GST_BUFFER_SIZE (buf), &written);
+
+  switch (result) {
+    case GNOME_VFS_OK:{
+      GST_DEBUG_OBJECT (sink, "wrote %" G_GINT64_FORMAT " bytes at %"
+          G_GINT64_FORMAT, (gint64) written, (gint64) cur_pos);
+
+      if (written < GST_BUFFER_SIZE (buf)) {
+        /* FIXME: what to do here? (tpm) */
+        g_warning ("%s: %d bytes should be written, only %"
+            G_GUINT64_FORMAT " bytes written", G_STRLOC,
+            GST_BUFFER_SIZE (buf), written);
+      }
+
+      sink->current_pos += GST_BUFFER_SIZE (buf);
+      ret = GST_FLOW_OK;
+      break;
+    }
+    case GNOME_VFS_ERROR_NO_SPACE:{
+      /* TODO: emit signal/send msg on out-of-diskspace and
+       * handle this gracefully (see open bug) (tpm) */
+      GST_ELEMENT_ERROR (sink, RESOURCE, NO_SPACE_LEFT, (NULL),
+          ("bufsize=%u, written=%u", GST_BUFFER_SIZE (buf), (guint) written));
+      ret = GST_FLOW_ERROR;
+      break;
+    }
+    default:{
+      gchar *filename = gnome_vfs_uri_to_string (sink->uri,
+          GNOME_VFS_URI_HIDE_PASSWORD);
+
+      GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
+          (_("Error while writing to file \"%s\"."), filename),
+          ("%s, bufsize=%u, written=%u", gnome_vfs_result_to_string (result),
+              GST_BUFFER_SIZE (buf), (guint) written));
+
+      g_free (filename);
+      ret = GST_FLOW_ERROR;
+      break;
+    }
+  }
+
+  return GST_FLOW_OK;
+}
+
+/*** GSTURIHANDLER INTERFACE *************************************************/
+
+static GstURIType
+gst_gnome_vfs_sink_uri_get_type (void)
+{
+  return GST_URI_SINK;
+}
+
+static gchar **
+gst_gnome_vfs_sink_uri_get_protocols (void)
+{
+  static gchar **protocols = NULL;
+
+  if (!protocols)
+    protocols = gst_gnomevfs_get_supported_uris ();
+
+  return protocols;
+}
+
+static const gchar *
+gst_gnome_vfs_sink_uri_get_uri (GstURIHandler * handler)
+{
+  GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (handler);
+
+  return sink->uri_name;
+}
+
+static gboolean
+gst_gnome_vfs_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri)
+{
+  GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (handler);
+  GstState cur_state;
+
+  gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0);
+
+  if (cur_state == GST_STATE_PLAYING || cur_state == GST_STATE_PAUSED) {
+    GST_WARNING_OBJECT (sink, "cannot set uri when PAUSED or PLAYING");
+    return FALSE;
+  }
+
+  g_object_set (sink, "location", uri, NULL);
+
+  return TRUE;
+}
+
+static void
+gst_gnome_vfs_sink_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = gst_gnome_vfs_sink_uri_get_type;
+  iface->get_protocols = gst_gnome_vfs_sink_uri_get_protocols;
+  iface->get_uri = gst_gnome_vfs_sink_uri_get_uri;
+  iface->set_uri = gst_gnome_vfs_sink_uri_set_uri;
+}