gst_plugins_base/ext/gio/gstgiosink.c
branchRCL_3
changeset 30 7e817e7e631c
parent 0 0e761a78d257
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
       
     1 /* GStreamer
       
     2  *
       
     3  * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
       
     4  * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
       
     5  * 
       
     6  * This library is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU Library General Public
       
     8  * License as published by the Free Software Foundation; either
       
     9  * version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This library is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14  * Library General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU Library General Public
       
    17  * License along with this library; if not, write to the
       
    18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    19  * Boston, MA 02111-1307, USA.
       
    20  */
       
    21 
       
    22 /**
       
    23  * SECTION:element-giosink
       
    24  * @short_description: Write a stream to any GIO-supported location
       
    25  * @see_also: #GstFileSink, #GstGnomeVFSSink, #GstGioSrc
       
    26  *
       
    27  * <refsect2>
       
    28  * <para>
       
    29  * This plugin writes incoming data to a local or remote location specified
       
    30  * by an URI. This location can be specified using any protocol supported by
       
    31  * the GIO library or it's VFS backends. Common protocols are 'file', 'ftp',
       
    32  * or 'smb'.
       
    33  * </para>
       
    34  * <para>
       
    35  * Example pipeline:
       
    36  * <programlisting>
       
    37  * gst-launch -v filesrc location=input.xyz ! giosink location=file:///home/joe/out.xyz
       
    38  * </programlisting>
       
    39  * The above pipeline will simply copy a local file. Instead of giosink,
       
    40  * we could just as well have used the filesink element here.
       
    41  * </para>
       
    42  * <para>
       
    43  * Another example pipeline:
       
    44  * <programlisting>
       
    45  * gst-launch -v filesrc location=foo.mp3 ! mad ! flacenc ! giosink location=smb://othercomputer/foo.flac
       
    46  * </programlisting>
       
    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  * </para>
       
    50  * <para>
       
    51  * Another example pipeline:
       
    52  * <programlisting>
       
    53  * gst-launch -v audiotestsrc num-buffers=100 ! vorbisenc ! oggmux ! giosink location=file:///home/foo/bar.ogg
       
    54  * </programlisting>
       
    55  * The above pipeline will encode a 440Hz sine wave to Ogg Vorbis and stores
       
    56  * it in the home directory of user foo.
       
    57  * </para>
       
    58  * </refsect2>
       
    59  */
       
    60 
       
    61 /* FIXME: We would like to mount the enclosing volume of an URL
       
    62  *        if it isn't mounted yet but this is possible async-only.
       
    63  *        Unfortunately this requires a running main loop from the
       
    64  *        default context and we can't guarantuee this!
       
    65  *
       
    66  *        We would also like to do authentication while mounting.
       
    67  */
       
    68 
       
    69 #ifdef HAVE_CONFIG_H
       
    70 #include <config.h>
       
    71 #endif
       
    72 
       
    73 #include "gstgiosink.h"
       
    74 
       
    75 GST_DEBUG_CATEGORY_STATIC (gst_gio_sink_debug);
       
    76 #define GST_CAT_DEFAULT gst_gio_sink_debug
       
    77 
       
    78 /* Filter signals and args */
       
    79 enum
       
    80 {
       
    81   LAST_SIGNAL
       
    82 };
       
    83 
       
    84 enum
       
    85 {
       
    86   ARG_0,
       
    87   ARG_LOCATION
       
    88 };
       
    89 
       
    90 GST_BOILERPLATE_FULL (GstGioSink, gst_gio_sink, GstGioBaseSink,
       
    91     GST_TYPE_GIO_BASE_SINK, gst_gio_uri_handler_do_init);
       
    92 
       
    93 static void gst_gio_sink_finalize (GObject * object);
       
    94 static void gst_gio_sink_set_property (GObject * object, guint prop_id,
       
    95     const GValue * value, GParamSpec * pspec);
       
    96 static void gst_gio_sink_get_property (GObject * object, guint prop_id,
       
    97     GValue * value, GParamSpec * pspec);
       
    98 static gboolean gst_gio_sink_start (GstBaseSink * base_sink);
       
    99 
       
   100 static void
       
   101 gst_gio_sink_base_init (gpointer gclass)
       
   102 {
       
   103   static GstElementDetails element_details = {
       
   104     "GIO sink",
       
   105     "Sink/File",
       
   106     "Write to any GIO-supported location",
       
   107     "Ren\xc3\xa9 Stadler <mail@renestadler.de>, "
       
   108         "Sebastian Dröge <slomo@circular-chaos.org>"
       
   109   };
       
   110   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
       
   111 
       
   112   GST_DEBUG_CATEGORY_INIT (gst_gio_sink_debug, "gio_sink", 0, "GIO sink");
       
   113 
       
   114   gst_element_class_set_details (element_class, &element_details);
       
   115 }
       
   116 
       
   117 static void
       
   118 gst_gio_sink_class_init (GstGioSinkClass * klass)
       
   119 {
       
   120   GObjectClass *gobject_class;
       
   121   GstElementClass *gstelement_class;
       
   122   GstBaseSinkClass *gstbasesink_class;
       
   123 
       
   124   gobject_class = (GObjectClass *) klass;
       
   125   gstelement_class = (GstElementClass *) klass;
       
   126   gstbasesink_class = (GstBaseSinkClass *) klass;
       
   127 
       
   128   gobject_class->finalize = gst_gio_sink_finalize;
       
   129   gobject_class->set_property = gst_gio_sink_set_property;
       
   130   gobject_class->get_property = gst_gio_sink_get_property;
       
   131 
       
   132   g_object_class_install_property (gobject_class, ARG_LOCATION,
       
   133       g_param_spec_string ("location", "Location", "URI location to write to",
       
   134           NULL, G_PARAM_READWRITE));
       
   135 
       
   136   gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_gio_sink_start);
       
   137 }
       
   138 
       
   139 static void
       
   140 gst_gio_sink_init (GstGioSink * sink, GstGioSinkClass * gclass)
       
   141 {
       
   142 }
       
   143 
       
   144 static void
       
   145 gst_gio_sink_finalize (GObject * object)
       
   146 {
       
   147   GstGioSink *sink = GST_GIO_SINK (object);
       
   148 
       
   149   if (sink->location) {
       
   150     g_free (sink->location);
       
   151     sink->location = NULL;
       
   152   }
       
   153 
       
   154   GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
       
   155 }
       
   156 
       
   157 static void
       
   158 gst_gio_sink_set_property (GObject * object, guint prop_id,
       
   159     const GValue * value, GParamSpec * pspec)
       
   160 {
       
   161   GstGioSink *sink = GST_GIO_SINK (object);
       
   162 
       
   163   switch (prop_id) {
       
   164     case ARG_LOCATION:
       
   165       if (GST_STATE (sink) == GST_STATE_PLAYING ||
       
   166           GST_STATE (sink) == GST_STATE_PAUSED)
       
   167         break;
       
   168 
       
   169       g_free (sink->location);
       
   170       sink->location = g_strdup (g_value_get_string (value));
       
   171       break;
       
   172     default:
       
   173       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   174       break;
       
   175   }
       
   176 }
       
   177 
       
   178 static void
       
   179 gst_gio_sink_get_property (GObject * object, guint prop_id,
       
   180     GValue * value, GParamSpec * pspec)
       
   181 {
       
   182   GstGioSink *sink = GST_GIO_SINK (object);
       
   183 
       
   184   switch (prop_id) {
       
   185     case ARG_LOCATION:
       
   186       g_value_set_string (value, sink->location);
       
   187       break;
       
   188     default:
       
   189       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   190       break;
       
   191   }
       
   192 }
       
   193 
       
   194 static gboolean
       
   195 gst_gio_sink_start (GstBaseSink * base_sink)
       
   196 {
       
   197   GstGioSink *sink = GST_GIO_SINK (base_sink);
       
   198   GFile *file;
       
   199   GOutputStream *stream;
       
   200   GCancellable *cancel = GST_GIO_BASE_SINK (sink)->cancel;
       
   201   gboolean success;
       
   202   GError *err = NULL;
       
   203 
       
   204   if (sink->location == NULL) {
       
   205     GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL),
       
   206         ("No location given"));
       
   207     return FALSE;
       
   208   }
       
   209 
       
   210   file = g_file_new_for_uri (sink->location);
       
   211 
       
   212   if (file == NULL) {
       
   213     GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL),
       
   214         ("Malformed URI or protocol not supported (%s)", sink->location));
       
   215     return FALSE;
       
   216   }
       
   217 
       
   218   stream =
       
   219       G_OUTPUT_STREAM (g_file_create (file, G_FILE_CREATE_NONE, cancel, &err));
       
   220 
       
   221   success = (stream != NULL);
       
   222 
       
   223   g_object_unref (file);
       
   224 
       
   225   if (!success && !gst_gio_error (sink, "g_file_create", &err, NULL)) {
       
   226 
       
   227     /*if (GST_GIO_ERROR_MATCHES (err, EXISTS)) */
       
   228     /* FIXME: Retry with replace if overwrite == TRUE! */
       
   229 
       
   230     if (GST_GIO_ERROR_MATCHES (err, NOT_FOUND))
       
   231       GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND, (NULL),
       
   232           ("Could not open location %s for writing: %s",
       
   233               sink->location, err->message));
       
   234     else
       
   235       GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_READ, (NULL),
       
   236           ("Could not open location %s for writing: %s",
       
   237               sink->location, err->message));
       
   238 
       
   239     g_clear_error (&err);
       
   240   }
       
   241 
       
   242   if (!success)
       
   243     return FALSE;
       
   244 
       
   245   GST_DEBUG_OBJECT (sink, "opened location %s", sink->location);
       
   246 
       
   247   gst_gio_base_sink_set_stream (GST_GIO_BASE_SINK (sink), stream);
       
   248 
       
   249   return GST_BASE_SINK_CLASS (parent_class)->start (base_sink);
       
   250 }