Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / ext / gnomevfs / gstgnomevfssink.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *                    2001 Bastien Nocera <hadess@hadess.net>
5  *                    2003 Colin Walters <walters@verbum.org>
6  *                    2005 Tim-Philipp Müller <tim centricular net>
7  *
8  * gstgnomevfssink.c: 
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */
25
26 /**
27  * SECTION:element-gnomevfssink
28  * @see_also: #GstFileSink, #GstGnomeVFSSrc
29  *
30  * This plugin writes incoming data to a local or remote location specified
31  * by an URI. This location can be specified using any protocol supported by
32  * the GnomeVFS library. Common protocols are 'file', 'ftp', or 'smb'.
33  *
34  * Applications can connect to the #GstGnomeVFSSink::allow-overwrite signal to
35  * receive a callback when an existing file will be overwritten. The return
36  * value of the signal will determine if gnomevfssink will overwrite the
37  * resource or abort with an error.
38  *
39  * <refsect2>
40  * <title>Example launch lines</title>
41  * |[
42  * gst-launch -v filesrc location=input.xyz ! gnomevfssink location=file:///home/joe/out.xyz
43  * ]| The above pipeline will simply copy a local file. Instead of gnomevfssink,
44  * we could just as well have used the filesink element here.
45  * |[
46  * gst-launch -v filesrc location=foo.mp3 ! mad ! flacenc ! gnomevfssink location=smb://othercomputer/foo.flac
47  * ]| The above pipeline will re-encode an mp3 file into FLAC format and store
48  * it on a remote host using the Samba protocol.
49  * </refsect2>
50  *
51  * Last reviewed on 2006-02-28 (0.10.4)
52  */
53
54 #ifdef HAVE_CONFIG_H
55 #include "config.h"
56 #endif
57
58 #include "gstgnomevfssink.h"
59
60 #include "gst/gst-i18n-plugin.h"
61
62 #include <gst/gst.h>
63 #include <libgnomevfs/gnome-vfs.h>
64 #include <string.h>
65 #include <errno.h>
66
67 enum
68 {
69   SIGNAL_ERASE_ASK,
70   LAST_SIGNAL
71 };
72
73 enum
74 {
75   ARG_0,
76   ARG_LOCATION,
77   ARG_URI,
78   ARG_HANDLE
79 };
80
81 static void gst_gnome_vfs_sink_finalize (GObject * obj);
82
83 static void gst_gnome_vfs_sink_uri_handler_init (gpointer g_iface,
84     gpointer iface_data);
85
86 static void gst_gnome_vfs_sink_set_property (GObject * object, guint prop_id,
87     const GValue * value, GParamSpec * pspec);
88 static void gst_gnome_vfs_sink_get_property (GObject * object, guint prop_id,
89     GValue * value, GParamSpec * pspec);
90
91 static gboolean gst_gnome_vfs_sink_open_file (GstGnomeVFSSink * sink);
92 static void gst_gnome_vfs_sink_close_file (GstGnomeVFSSink * sink);
93 static gboolean gst_gnome_vfs_sink_start (GstBaseSink * basesink);
94 static gboolean gst_gnome_vfs_sink_stop (GstBaseSink * basesink);
95 static GstFlowReturn gst_gnome_vfs_sink_render (GstBaseSink * basesink,
96     GstBuffer * buffer);
97 static gboolean gst_gnome_vfs_sink_handle_event (GstBaseSink * basesink,
98     GstEvent * event);
99 static gboolean gst_gnome_vfs_sink_query (GstPad * pad, GstQuery * query);
100
101 static guint gst_gnome_vfs_sink_signals[LAST_SIGNAL];   /* all 0 */
102
103 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
104     GST_PAD_SINK,
105     GST_PAD_ALWAYS,
106     GST_STATIC_CAPS_ANY);
107
108 GST_DEBUG_CATEGORY_STATIC (gst_gnome_vfs_sink_debug);
109 #define GST_CAT_DEFAULT gst_gnome_vfs_sink_debug
110
111 static void
112 gst_gnome_vfs_sink_do_init (GType type)
113 {
114   static const GInterfaceInfo urihandler_info = {
115     gst_gnome_vfs_sink_uri_handler_init,
116     NULL,
117     NULL
118   };
119
120   g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
121
122   GST_DEBUG_CATEGORY_INIT (gst_gnome_vfs_sink_debug, "gnomevfssink", 0,
123       "Gnome VFS sink element");
124 }
125
126 GST_BOILERPLATE_FULL (GstGnomeVFSSink, gst_gnome_vfs_sink, GstBaseSink,
127     GST_TYPE_BASE_SINK, gst_gnome_vfs_sink_do_init);
128
129 static void
130 gst_gnome_vfs_sink_base_init (gpointer g_class)
131 {
132   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
133
134   gst_element_class_add_pad_template (element_class,
135       gst_static_pad_template_get (&sinktemplate));
136
137   gst_element_class_set_details_simple (element_class,
138       "GnomeVFS Sink", "Sink/File",
139       "Write a stream to a GnomeVFS URI", "Bastien Nocera <hadess@hadess.net>");
140 }
141
142 static gboolean
143 _gst_boolean_allow_overwrite_accumulator (GSignalInvocationHint * ihint,
144     GValue * return_accu, const GValue * handler_return, gpointer dummy)
145 {
146   gboolean allow_overwrite;
147
148   allow_overwrite = g_value_get_boolean (handler_return);
149   if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
150     g_value_set_boolean (return_accu, allow_overwrite);
151
152   /* stop emission if signal doesn't allow overwriting */
153   return allow_overwrite;
154 }
155
156 static void
157 gst_gnome_vfs_sink_class_init (GstGnomeVFSSinkClass * klass)
158 {
159   GstBaseSinkClass *basesink_class;
160   GObjectClass *gobject_class;
161
162   gobject_class = (GObjectClass *) klass;
163   basesink_class = (GstBaseSinkClass *) klass;
164
165   gobject_class->set_property = gst_gnome_vfs_sink_set_property;
166   gobject_class->get_property = gst_gnome_vfs_sink_get_property;
167   gobject_class->finalize = gst_gnome_vfs_sink_finalize;
168
169   g_object_class_install_property (gobject_class, ARG_LOCATION,
170       g_param_spec_string ("location", "File Location",
171           "Location of the file to write", NULL,
172           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
173   g_object_class_install_property (gobject_class, ARG_URI,
174       g_param_spec_boxed ("uri", "GnomeVFSURI", "URI for GnomeVFS",
175           GST_TYPE_GNOME_VFS_URI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
176   g_object_class_install_property (gobject_class, ARG_HANDLE,
177       g_param_spec_boxed ("handle", "GnomeVFSHandle", "Handle for GnomeVFS",
178           GST_TYPE_GNOME_VFS_HANDLE,
179           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
180
181   /**
182    * GstGnomeVFSSink::allow-overwrite
183    * @sink: the object which received the signal
184    * @uri: the URI to be overwritten
185    *
186    * This signal is fired when gnomevfssink is about to overwrite an
187    * existing resource. The application can connect to this signal and ask
188    * the user if the resource may be overwritten. 
189    *
190    * Returns: A boolean indicating that the resource may be overwritten.
191    */
192   gst_gnome_vfs_sink_signals[SIGNAL_ERASE_ASK] =
193       g_signal_new ("allow-overwrite", G_TYPE_FROM_CLASS (klass),
194       G_SIGNAL_RUN_CLEANUP, G_STRUCT_OFFSET (GstGnomeVFSSinkClass, erase_ask),
195       _gst_boolean_allow_overwrite_accumulator, NULL,
196       gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, GST_TYPE_GNOME_VFS_URI);
197
198   basesink_class->stop = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_stop);
199   basesink_class->start = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_start);
200   basesink_class->event = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_handle_event);
201   basesink_class->render = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_render);
202   basesink_class->get_times = NULL;
203 }
204
205 static void
206 gst_gnome_vfs_sink_finalize (GObject * obj)
207 {
208   GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (obj);
209
210   if (sink->uri) {
211     gnome_vfs_uri_unref (sink->uri);
212     sink->uri = NULL;
213   }
214
215   if (sink->uri_name) {
216     g_free (sink->uri_name);
217     sink->uri_name = NULL;
218   }
219
220   G_OBJECT_CLASS (parent_class)->finalize (obj);
221 }
222
223 static void
224 gst_gnome_vfs_sink_init (GstGnomeVFSSink * sink, GstGnomeVFSSinkClass * klass)
225 {
226   gst_pad_set_query_function (GST_BASE_SINK_PAD (sink),
227       GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_query));
228
229   sink->uri = NULL;
230   sink->uri_name = NULL;
231   sink->handle = NULL;
232   sink->own_handle = FALSE;
233   sink->current_pos = 0;
234
235   GST_BASE_SINK (sink)->sync = FALSE;
236 }
237
238 static void
239 gst_gnome_vfs_sink_set_property (GObject * object, guint prop_id,
240     const GValue * value, GParamSpec * pspec)
241 {
242   GstGnomeVFSSink *sink;
243   GstState cur_state;
244
245   sink = GST_GNOME_VFS_SINK (object);
246
247   gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0);
248
249   if (cur_state == GST_STATE_PLAYING || cur_state == GST_STATE_PAUSED) {
250     GST_WARNING_OBJECT (sink, "cannot set property when PAUSED or PLAYING");
251     return;
252   }
253
254   GST_OBJECT_LOCK (sink);
255
256   switch (prop_id) {
257     case ARG_LOCATION:{
258       const gchar *new_location;
259
260       if (sink->uri) {
261         gnome_vfs_uri_unref (sink->uri);
262         sink->uri = NULL;
263       }
264       if (sink->uri_name) {
265         g_free (sink->uri_name);
266         sink->uri_name = NULL;
267       }
268
269       new_location = g_value_get_string (value);
270       if (new_location) {
271         sink->uri_name = gst_gnome_vfs_location_to_uri_string (new_location);
272         sink->uri = gnome_vfs_uri_new (sink->uri_name);
273       }
274       break;
275     }
276     case ARG_URI:{
277       if (sink->uri) {
278         gnome_vfs_uri_unref (sink->uri);
279         sink->uri = NULL;
280       }
281       if (sink->uri_name) {
282         g_free (sink->uri_name);
283         sink->uri_name = NULL;
284       }
285       if (g_value_get_boxed (value)) {
286         sink->uri = (GnomeVFSURI *) g_value_dup_boxed (value);
287         sink->uri_name = gnome_vfs_uri_to_string (sink->uri, 0);
288       }
289       break;
290     }
291     case ARG_HANDLE:{
292       if (sink->uri) {
293         gnome_vfs_uri_unref (sink->uri);
294         sink->uri = NULL;
295       }
296       if (sink->uri_name) {
297         g_free (sink->uri_name);
298         sink->uri_name = NULL;
299       }
300       sink->handle = g_value_get_boxed (value);
301       break;
302     }
303     default:
304       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
305       break;
306   }
307
308   GST_OBJECT_UNLOCK (sink);
309 }
310
311 static void
312 gst_gnome_vfs_sink_get_property (GObject * object, guint prop_id,
313     GValue * value, GParamSpec * pspec)
314 {
315   GstGnomeVFSSink *sink;
316
317   sink = GST_GNOME_VFS_SINK (object);
318
319   GST_OBJECT_LOCK (sink);
320
321   switch (prop_id) {
322     case ARG_LOCATION:
323       g_value_set_string (value, sink->uri_name);
324       break;
325     case ARG_URI:
326       g_value_set_boxed (value, sink->uri);
327       break;
328     case ARG_HANDLE:
329       g_value_set_boxed (value, sink->handle);
330       break;
331     default:
332       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
333       break;
334   }
335
336   GST_OBJECT_UNLOCK (sink);
337 }
338
339 static gboolean
340 gst_gnome_vfs_sink_open_file (GstGnomeVFSSink * sink)
341 {
342   GnomeVFSResult result;
343
344   if (sink->uri) {
345     /* open the file, all permissions, umask will apply */
346     result = gnome_vfs_create_uri (&(sink->handle), sink->uri,
347         GNOME_VFS_OPEN_WRITE, TRUE,
348         GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE |
349         GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_WRITE |
350         GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_OTHER_WRITE);
351
352     /* if the file existed and the property says to ask, then ask! */
353     if (result == GNOME_VFS_ERROR_FILE_EXISTS) {
354       gboolean erase_anyway = FALSE;
355
356       g_signal_emit (G_OBJECT (sink),
357           gst_gnome_vfs_sink_signals[SIGNAL_ERASE_ASK], 0, sink->uri,
358           &erase_anyway);
359       if (erase_anyway) {
360         result = gnome_vfs_create_uri (&(sink->handle), sink->uri,
361             GNOME_VFS_OPEN_WRITE, FALSE,
362             GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE |
363             GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_WRITE |
364             GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_OTHER_WRITE);
365       }
366     }
367
368     GST_DEBUG_OBJECT (sink, "open: %s", gnome_vfs_result_to_string (result));
369
370     if (result != GNOME_VFS_OK) {
371       gchar *filename = gnome_vfs_uri_to_string (sink->uri,
372           GNOME_VFS_URI_HIDE_PASSWORD);
373
374       GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
375           (_("Could not open vfs file \"%s\" for writing: %s."),
376               filename, gnome_vfs_result_to_string (result)), GST_ERROR_SYSTEM);
377       g_free (filename);
378       return FALSE;
379     }
380     sink->own_handle = TRUE;
381   } else if (!sink->handle) {
382     GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (_("No filename given")),
383         (NULL));
384     return FALSE;
385   } else {
386     sink->own_handle = FALSE;
387   }
388
389   sink->current_pos = 0;
390
391   return TRUE;
392 }
393
394 static void
395 gst_gnome_vfs_sink_close_file (GstGnomeVFSSink * sink)
396 {
397   GnomeVFSResult result;
398
399   if (sink->own_handle) {
400     /* close the file */
401     result = gnome_vfs_close (sink->handle);
402
403     if (result != GNOME_VFS_OK) {
404       gchar *filename = gnome_vfs_uri_to_string (sink->uri,
405           GNOME_VFS_URI_HIDE_PASSWORD);
406
407       GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE,
408           (_("Could not close vfs file \"%s\"."), filename), GST_ERROR_SYSTEM);
409       g_free (filename);
410     }
411
412     sink->own_handle = FALSE;
413     sink->handle = NULL;
414   }
415 }
416
417 static gboolean
418 gst_gnome_vfs_sink_start (GstBaseSink * basesink)
419 {
420   gboolean ret;
421
422   ret = gst_gnome_vfs_sink_open_file (GST_GNOME_VFS_SINK (basesink));
423
424   return ret;
425 }
426
427 static gboolean
428 gst_gnome_vfs_sink_stop (GstBaseSink * basesink)
429 {
430   GST_DEBUG_OBJECT (basesink, "closing ...");
431   gst_gnome_vfs_sink_close_file (GST_GNOME_VFS_SINK (basesink));
432   return TRUE;
433 }
434
435 static gboolean
436 gst_gnome_vfs_sink_handle_event (GstBaseSink * basesink, GstEvent * event)
437 {
438   GstGnomeVFSSink *sink;
439   gboolean ret = TRUE;
440
441   sink = GST_GNOME_VFS_SINK (basesink);
442
443   GST_DEBUG_OBJECT (sink, "processing %s event", GST_EVENT_TYPE_NAME (event));
444
445   switch (GST_EVENT_TYPE (event)) {
446     case GST_EVENT_NEWSEGMENT:{
447       GnomeVFSResult res;
448       GstFormat format;
449       gint64 offset;
450
451       gst_event_parse_new_segment (event, NULL, NULL, &format, &offset,
452           NULL, NULL);
453
454       if (format != GST_FORMAT_BYTES) {
455         GST_WARNING_OBJECT (sink, "ignored NEWSEGMENT event in %s format",
456             gst_format_get_name (format));
457         break;
458       }
459
460       GST_LOG_OBJECT (sink, "seeking to offset %" G_GINT64_FORMAT, offset);
461       res = gnome_vfs_seek (sink->handle, GNOME_VFS_SEEK_START, offset);
462
463       if (res != GNOME_VFS_OK) {
464         GST_ERROR_OBJECT (sink, "Failed to seek to offset %"
465             G_GINT64_FORMAT ": %s", offset, gnome_vfs_result_to_string (res));
466         ret = FALSE;
467       } else {
468         sink->current_pos = offset;
469       }
470
471       break;
472     }
473
474     case GST_EVENT_FLUSH_START:
475     case GST_EVENT_EOS:{
476       /* No need to flush with GnomeVfs */
477       break;
478     }
479     default:
480       break;
481   }
482
483   return ret;
484 }
485
486 static gboolean
487 gst_gnome_vfs_sink_query (GstPad * pad, GstQuery * query)
488 {
489   GstGnomeVFSSink *sink;
490   GstFormat format;
491
492   sink = GST_GNOME_VFS_SINK (GST_PAD_PARENT (pad));
493
494   switch (GST_QUERY_TYPE (query)) {
495     case GST_QUERY_POSITION:
496       gst_query_parse_position (query, &format, NULL);
497       switch (format) {
498         case GST_FORMAT_DEFAULT:
499         case GST_FORMAT_BYTES:
500           gst_query_set_position (query, GST_FORMAT_BYTES, sink->current_pos);
501           return TRUE;
502         default:
503           return FALSE;
504       }
505
506     case GST_QUERY_FORMATS:
507       gst_query_set_formats (query, 2, GST_FORMAT_DEFAULT, GST_FORMAT_BYTES);
508       return TRUE;
509
510     case GST_QUERY_URI:
511       gst_query_set_uri (query, sink->uri_name);
512       return TRUE;
513
514     default:
515       return gst_pad_query_default (pad, query);
516   }
517 }
518
519 static GstFlowReturn
520 gst_gnome_vfs_sink_render (GstBaseSink * basesink, GstBuffer * buf)
521 {
522   GnomeVFSFileSize written, cur_pos;
523   GstGnomeVFSSink *sink;
524   GnomeVFSResult result;
525   GstFlowReturn ret;
526
527   sink = GST_GNOME_VFS_SINK (basesink);
528
529   if (gnome_vfs_tell (sink->handle, &cur_pos) == GNOME_VFS_OK) {
530     /* bring up to date with current position for proper reporting */
531     sink->current_pos = cur_pos;
532   }
533
534   result = gnome_vfs_write (sink->handle, GST_BUFFER_DATA (buf),
535       GST_BUFFER_SIZE (buf), &written);
536
537   switch (result) {
538     case GNOME_VFS_OK:{
539       GST_DEBUG_OBJECT (sink, "wrote %" G_GINT64_FORMAT " bytes at %"
540           G_GINT64_FORMAT, (gint64) written, (gint64) cur_pos);
541
542       if (written < GST_BUFFER_SIZE (buf)) {
543         /* FIXME: what to do here? (tpm) */
544         g_warning ("%s: %d bytes should be written, only %"
545             G_GUINT64_FORMAT " bytes written", G_STRLOC,
546             GST_BUFFER_SIZE (buf), written);
547       }
548
549       sink->current_pos += GST_BUFFER_SIZE (buf);
550       ret = GST_FLOW_OK;
551       break;
552     }
553     case GNOME_VFS_ERROR_NO_SPACE:{
554       /* TODO: emit signal/send msg on out-of-diskspace and
555        * handle this gracefully (see open bug) (tpm) */
556       GST_ELEMENT_ERROR (sink, RESOURCE, NO_SPACE_LEFT, (NULL),
557           ("bufsize=%u, written=%u", GST_BUFFER_SIZE (buf), (guint) written));
558       ret = GST_FLOW_ERROR;
559       break;
560     }
561     default:{
562       gchar *filename = gnome_vfs_uri_to_string (sink->uri,
563           GNOME_VFS_URI_HIDE_PASSWORD);
564
565       GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
566           (_("Error while writing to file \"%s\"."), filename),
567           ("%s, bufsize=%u, written=%u", gnome_vfs_result_to_string (result),
568               GST_BUFFER_SIZE (buf), (guint) written));
569
570       g_free (filename);
571       ret = GST_FLOW_ERROR;
572       break;
573     }
574   }
575
576   return ret;
577 }
578
579 /*** GSTURIHANDLER INTERFACE *************************************************/
580
581 static GstURIType
582 gst_gnome_vfs_sink_uri_get_type (void)
583 {
584   return GST_URI_SINK;
585 }
586
587 static gchar **
588 gst_gnome_vfs_sink_uri_get_protocols (void)
589 {
590   return gst_gnomevfs_get_supported_uris ();
591 }
592
593 static const gchar *
594 gst_gnome_vfs_sink_uri_get_uri (GstURIHandler * handler)
595 {
596   GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (handler);
597
598   return sink->uri_name;
599 }
600
601 static gboolean
602 gst_gnome_vfs_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri)
603 {
604   GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (handler);
605   GstState cur_state;
606
607   gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0);
608
609   if (cur_state == GST_STATE_PLAYING || cur_state == GST_STATE_PAUSED) {
610     GST_WARNING_OBJECT (sink, "cannot set uri when PAUSED or PLAYING");
611     return FALSE;
612   }
613
614   g_object_set (sink, "location", uri, NULL);
615
616   return TRUE;
617 }
618
619 static void
620 gst_gnome_vfs_sink_uri_handler_init (gpointer g_iface, gpointer iface_data)
621 {
622   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
623
624   iface->get_type = gst_gnome_vfs_sink_uri_get_type;
625   iface->get_protocols = gst_gnome_vfs_sink_uri_get_protocols;
626   iface->get_uri = gst_gnome_vfs_sink_uri_get_uri;
627   iface->set_uri = gst_gnome_vfs_sink_uri_set_uri;
628 }