Initialize Tizen 2.3
[framework/multimedia/gst-plugins-base0.10.git] / mobile / 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_static_pad_template (element_class, &sinktemplate);
135
136   gst_element_class_set_details_simple (element_class,
137       "GnomeVFS Sink", "Sink/File",
138       "Write a stream to a GnomeVFS URI", "Bastien Nocera <hadess@hadess.net>");
139 }
140
141 static gboolean
142 _gst_boolean_allow_overwrite_accumulator (GSignalInvocationHint * ihint,
143     GValue * return_accu, const GValue * handler_return, gpointer dummy)
144 {
145   gboolean allow_overwrite;
146
147   allow_overwrite = g_value_get_boolean (handler_return);
148   if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
149     g_value_set_boolean (return_accu, allow_overwrite);
150
151   /* stop emission if signal doesn't allow overwriting */
152   return allow_overwrite;
153 }
154
155 static void
156 gst_gnome_vfs_sink_class_init (GstGnomeVFSSinkClass * klass)
157 {
158   GstBaseSinkClass *basesink_class;
159   GObjectClass *gobject_class;
160
161   gobject_class = (GObjectClass *) klass;
162   basesink_class = (GstBaseSinkClass *) klass;
163
164   gobject_class->set_property = gst_gnome_vfs_sink_set_property;
165   gobject_class->get_property = gst_gnome_vfs_sink_get_property;
166   gobject_class->finalize = gst_gnome_vfs_sink_finalize;
167
168   g_object_class_install_property (gobject_class, ARG_LOCATION,
169       g_param_spec_string ("location", "File Location",
170           "Location of the file to write", NULL,
171           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
172   g_object_class_install_property (gobject_class, ARG_URI,
173       g_param_spec_boxed ("uri", "GnomeVFSURI", "URI for GnomeVFS",
174           GST_TYPE_GNOME_VFS_URI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
175   g_object_class_install_property (gobject_class, ARG_HANDLE,
176       g_param_spec_boxed ("handle", "GnomeVFSHandle", "Handle for GnomeVFS",
177           GST_TYPE_GNOME_VFS_HANDLE,
178           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
179
180   /**
181    * GstGnomeVFSSink::allow-overwrite
182    * @sink: the object which received the signal
183    * @uri: the URI to be overwritten
184    *
185    * This signal is fired when gnomevfssink is about to overwrite an
186    * existing resource. The application can connect to this signal and ask
187    * the user if the resource may be overwritten. 
188    *
189    * Returns: A boolean indicating that the resource may be overwritten.
190    */
191   gst_gnome_vfs_sink_signals[SIGNAL_ERASE_ASK] =
192       g_signal_new ("allow-overwrite", G_TYPE_FROM_CLASS (klass),
193       G_SIGNAL_RUN_CLEANUP, G_STRUCT_OFFSET (GstGnomeVFSSinkClass, erase_ask),
194       _gst_boolean_allow_overwrite_accumulator, NULL,
195       gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, GST_TYPE_GNOME_VFS_URI);
196
197   basesink_class->stop = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_stop);
198   basesink_class->start = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_start);
199   basesink_class->event = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_handle_event);
200   basesink_class->render = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_render);
201   basesink_class->get_times = NULL;
202 }
203
204 static void
205 gst_gnome_vfs_sink_finalize (GObject * obj)
206 {
207   GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (obj);
208
209   if (sink->uri) {
210     gnome_vfs_uri_unref (sink->uri);
211     sink->uri = NULL;
212   }
213
214   if (sink->uri_name) {
215     g_free (sink->uri_name);
216     sink->uri_name = NULL;
217   }
218
219   G_OBJECT_CLASS (parent_class)->finalize (obj);
220 }
221
222 static void
223 gst_gnome_vfs_sink_init (GstGnomeVFSSink * sink, GstGnomeVFSSinkClass * klass)
224 {
225   gst_pad_set_query_function (GST_BASE_SINK_PAD (sink),
226       GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_query));
227
228   sink->uri = NULL;
229   sink->uri_name = NULL;
230   sink->handle = NULL;
231   sink->own_handle = FALSE;
232   sink->current_pos = 0;
233
234   GST_BASE_SINK (sink)->sync = FALSE;
235 }
236
237 static void
238 gst_gnome_vfs_sink_set_property (GObject * object, guint prop_id,
239     const GValue * value, GParamSpec * pspec)
240 {
241   GstGnomeVFSSink *sink;
242   GstState cur_state;
243
244   sink = GST_GNOME_VFS_SINK (object);
245
246   gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0);
247
248   if (cur_state == GST_STATE_PLAYING || cur_state == GST_STATE_PAUSED) {
249     GST_WARNING_OBJECT (sink, "cannot set property when PAUSED or PLAYING");
250     return;
251   }
252
253   GST_OBJECT_LOCK (sink);
254
255   switch (prop_id) {
256     case ARG_LOCATION:{
257       const gchar *new_location;
258
259       if (sink->uri) {
260         gnome_vfs_uri_unref (sink->uri);
261         sink->uri = NULL;
262       }
263       if (sink->uri_name) {
264         g_free (sink->uri_name);
265         sink->uri_name = NULL;
266       }
267
268       new_location = g_value_get_string (value);
269       if (new_location) {
270         sink->uri_name = gst_gnome_vfs_location_to_uri_string (new_location);
271         sink->uri = gnome_vfs_uri_new (sink->uri_name);
272       }
273       break;
274     }
275     case ARG_URI:{
276       if (sink->uri) {
277         gnome_vfs_uri_unref (sink->uri);
278         sink->uri = NULL;
279       }
280       if (sink->uri_name) {
281         g_free (sink->uri_name);
282         sink->uri_name = NULL;
283       }
284       if (g_value_get_boxed (value)) {
285         sink->uri = (GnomeVFSURI *) g_value_dup_boxed (value);
286         sink->uri_name = gnome_vfs_uri_to_string (sink->uri, 0);
287       }
288       break;
289     }
290     case ARG_HANDLE:{
291       if (sink->uri) {
292         gnome_vfs_uri_unref (sink->uri);
293         sink->uri = NULL;
294       }
295       if (sink->uri_name) {
296         g_free (sink->uri_name);
297         sink->uri_name = NULL;
298       }
299       sink->handle = g_value_get_boxed (value);
300       break;
301     }
302     default:
303       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
304       break;
305   }
306
307   GST_OBJECT_UNLOCK (sink);
308 }
309
310 static void
311 gst_gnome_vfs_sink_get_property (GObject * object, guint prop_id,
312     GValue * value, GParamSpec * pspec)
313 {
314   GstGnomeVFSSink *sink;
315
316   sink = GST_GNOME_VFS_SINK (object);
317
318   GST_OBJECT_LOCK (sink);
319
320   switch (prop_id) {
321     case ARG_LOCATION:
322       g_value_set_string (value, sink->uri_name);
323       break;
324     case ARG_URI:
325       g_value_set_boxed (value, sink->uri);
326       break;
327     case ARG_HANDLE:
328       g_value_set_boxed (value, sink->handle);
329       break;
330     default:
331       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
332       break;
333   }
334
335   GST_OBJECT_UNLOCK (sink);
336 }
337
338 static gboolean
339 gst_gnome_vfs_sink_open_file (GstGnomeVFSSink * sink)
340 {
341   GnomeVFSResult result;
342
343   if (sink->uri) {
344     /* open the file, all permissions, umask will apply */
345     result = gnome_vfs_create_uri (&(sink->handle), sink->uri,
346         GNOME_VFS_OPEN_WRITE, TRUE,
347         GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE |
348         GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_WRITE |
349         GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_OTHER_WRITE);
350
351     /* if the file existed and the property says to ask, then ask! */
352     if (result == GNOME_VFS_ERROR_FILE_EXISTS) {
353       gboolean erase_anyway = FALSE;
354
355       g_signal_emit (G_OBJECT (sink),
356           gst_gnome_vfs_sink_signals[SIGNAL_ERASE_ASK], 0, sink->uri,
357           &erase_anyway);
358       if (erase_anyway) {
359         result = gnome_vfs_create_uri (&(sink->handle), sink->uri,
360             GNOME_VFS_OPEN_WRITE, FALSE,
361             GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE |
362             GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_WRITE |
363             GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_OTHER_WRITE);
364       }
365     }
366
367     GST_DEBUG_OBJECT (sink, "open: %s", gnome_vfs_result_to_string (result));
368
369     if (result != GNOME_VFS_OK) {
370       gchar *filename = gnome_vfs_uri_to_string (sink->uri,
371           GNOME_VFS_URI_HIDE_PASSWORD);
372
373       GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
374           (_("Could not open vfs file \"%s\" for writing: %s."),
375               filename, gnome_vfs_result_to_string (result)), GST_ERROR_SYSTEM);
376       g_free (filename);
377       return FALSE;
378     }
379     sink->own_handle = TRUE;
380   } else if (!sink->handle) {
381     GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (_("No filename given")),
382         (NULL));
383     return FALSE;
384   } else {
385     sink->own_handle = FALSE;
386   }
387
388   sink->current_pos = 0;
389
390   return TRUE;
391 }
392
393 static void
394 gst_gnome_vfs_sink_close_file (GstGnomeVFSSink * sink)
395 {
396   GnomeVFSResult result;
397
398   if (sink->own_handle) {
399     /* close the file */
400     result = gnome_vfs_close (sink->handle);
401
402     if (result != GNOME_VFS_OK) {
403       gchar *filename = gnome_vfs_uri_to_string (sink->uri,
404           GNOME_VFS_URI_HIDE_PASSWORD);
405
406       GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE,
407           (_("Could not close vfs file \"%s\"."), filename), GST_ERROR_SYSTEM);
408       g_free (filename);
409     }
410
411     sink->own_handle = FALSE;
412     sink->handle = NULL;
413   }
414 }
415
416 static gboolean
417 gst_gnome_vfs_sink_start (GstBaseSink * basesink)
418 {
419   gboolean ret;
420
421   ret = gst_gnome_vfs_sink_open_file (GST_GNOME_VFS_SINK (basesink));
422
423   return ret;
424 }
425
426 static gboolean
427 gst_gnome_vfs_sink_stop (GstBaseSink * basesink)
428 {
429   GST_DEBUG_OBJECT (basesink, "closing ...");
430   gst_gnome_vfs_sink_close_file (GST_GNOME_VFS_SINK (basesink));
431   return TRUE;
432 }
433
434 static gboolean
435 gst_gnome_vfs_sink_handle_event (GstBaseSink * basesink, GstEvent * event)
436 {
437   GstGnomeVFSSink *sink;
438   gboolean ret = TRUE;
439
440   sink = GST_GNOME_VFS_SINK (basesink);
441
442   GST_DEBUG_OBJECT (sink, "processing %s event", GST_EVENT_TYPE_NAME (event));
443
444   switch (GST_EVENT_TYPE (event)) {
445     case GST_EVENT_NEWSEGMENT:{
446       GnomeVFSResult res;
447       GstFormat format;
448       gint64 offset;
449
450       gst_event_parse_new_segment (event, NULL, NULL, &format, &offset,
451           NULL, NULL);
452
453       if (format != GST_FORMAT_BYTES) {
454         GST_WARNING_OBJECT (sink, "ignored NEWSEGMENT event in %s format",
455             gst_format_get_name (format));
456         break;
457       }
458
459       GST_LOG_OBJECT (sink, "seeking to offset %" G_GINT64_FORMAT, offset);
460       res = gnome_vfs_seek (sink->handle, GNOME_VFS_SEEK_START, offset);
461
462       if (res != GNOME_VFS_OK) {
463         GST_ERROR_OBJECT (sink, "Failed to seek to offset %"
464             G_GINT64_FORMAT ": %s", offset, gnome_vfs_result_to_string (res));
465         ret = FALSE;
466       } else {
467         sink->current_pos = offset;
468       }
469
470       break;
471     }
472
473     case GST_EVENT_FLUSH_START:
474     case GST_EVENT_EOS:{
475       /* No need to flush with GnomeVfs */
476       break;
477     }
478     default:
479       break;
480   }
481
482   return ret;
483 }
484
485 static gboolean
486 gst_gnome_vfs_sink_query (GstPad * pad, GstQuery * query)
487 {
488   GstGnomeVFSSink *sink;
489   GstFormat format;
490
491   sink = GST_GNOME_VFS_SINK (GST_PAD_PARENT (pad));
492
493   switch (GST_QUERY_TYPE (query)) {
494     case GST_QUERY_POSITION:
495       gst_query_parse_position (query, &format, NULL);
496       switch (format) {
497         case GST_FORMAT_DEFAULT:
498         case GST_FORMAT_BYTES:
499           gst_query_set_position (query, GST_FORMAT_BYTES, sink->current_pos);
500           return TRUE;
501         default:
502           return FALSE;
503       }
504
505     case GST_QUERY_FORMATS:
506       gst_query_set_formats (query, 2, GST_FORMAT_DEFAULT, GST_FORMAT_BYTES);
507       return TRUE;
508
509     case GST_QUERY_URI:
510       gst_query_set_uri (query, sink->uri_name);
511       return TRUE;
512
513     default:
514       return gst_pad_query_default (pad, query);
515   }
516 }
517
518 static GstFlowReturn
519 gst_gnome_vfs_sink_render (GstBaseSink * basesink, GstBuffer * buf)
520 {
521   GnomeVFSFileSize written, cur_pos;
522   GstGnomeVFSSink *sink;
523   GnomeVFSResult result;
524   GstFlowReturn ret;
525
526   sink = GST_GNOME_VFS_SINK (basesink);
527
528   if (gnome_vfs_tell (sink->handle, &cur_pos) == GNOME_VFS_OK) {
529     /* bring up to date with current position for proper reporting */
530     sink->current_pos = cur_pos;
531   }
532
533   result = gnome_vfs_write (sink->handle, GST_BUFFER_DATA (buf),
534       GST_BUFFER_SIZE (buf), &written);
535
536   switch (result) {
537     case GNOME_VFS_OK:{
538       GST_DEBUG_OBJECT (sink, "wrote %" G_GINT64_FORMAT " bytes at %"
539           G_GINT64_FORMAT, (gint64) written, (gint64) cur_pos);
540
541       if (written < GST_BUFFER_SIZE (buf)) {
542         /* FIXME: what to do here? (tpm) */
543         g_warning ("%s: %d bytes should be written, only %"
544             G_GUINT64_FORMAT " bytes written", G_STRLOC,
545             GST_BUFFER_SIZE (buf), written);
546       }
547
548       sink->current_pos += GST_BUFFER_SIZE (buf);
549       ret = GST_FLOW_OK;
550       break;
551     }
552     case GNOME_VFS_ERROR_NO_SPACE:{
553       /* TODO: emit signal/send msg on out-of-diskspace and
554        * handle this gracefully (see open bug) (tpm) */
555       GST_ELEMENT_ERROR (sink, RESOURCE, NO_SPACE_LEFT, (NULL),
556           ("bufsize=%u, written=%u", GST_BUFFER_SIZE (buf), (guint) written));
557       ret = GST_FLOW_ERROR;
558       break;
559     }
560     default:{
561       gchar *filename = gnome_vfs_uri_to_string (sink->uri,
562           GNOME_VFS_URI_HIDE_PASSWORD);
563
564       GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
565           (_("Error while writing to file \"%s\"."), filename),
566           ("%s, bufsize=%u, written=%u", gnome_vfs_result_to_string (result),
567               GST_BUFFER_SIZE (buf), (guint) written));
568
569       g_free (filename);
570       ret = GST_FLOW_ERROR;
571       break;
572     }
573   }
574
575   return ret;
576 }
577
578 /*** GSTURIHANDLER INTERFACE *************************************************/
579
580 static GstURIType
581 gst_gnome_vfs_sink_uri_get_type (void)
582 {
583   return GST_URI_SINK;
584 }
585
586 static gchar **
587 gst_gnome_vfs_sink_uri_get_protocols (void)
588 {
589   return gst_gnomevfs_get_supported_uris ();
590 }
591
592 static const gchar *
593 gst_gnome_vfs_sink_uri_get_uri (GstURIHandler * handler)
594 {
595   GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (handler);
596
597   return sink->uri_name;
598 }
599
600 static gboolean
601 gst_gnome_vfs_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri)
602 {
603   GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (handler);
604   GstState cur_state;
605
606   gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0);
607
608   if (cur_state == GST_STATE_PLAYING || cur_state == GST_STATE_PAUSED) {
609     GST_WARNING_OBJECT (sink, "cannot set uri when PAUSED or PLAYING");
610     return FALSE;
611   }
612
613   g_object_set (sink, "location", uri, NULL);
614
615   return TRUE;
616 }
617
618 static void
619 gst_gnome_vfs_sink_uri_handler_init (gpointer g_iface, gpointer iface_data)
620 {
621   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
622
623   iface->get_type = gst_gnome_vfs_sink_uri_get_type;
624   iface->get_protocols = gst_gnome_vfs_sink_uri_get_protocols;
625   iface->get_uri = gst_gnome_vfs_sink_uri_get_uri;
626   iface->set_uri = gst_gnome_vfs_sink_uri_set_uri;
627 }