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