gstgiosrc.c 10.2 KB
Newer Older
1
2
3
/* GStreamer
 *
 * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
4
 * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * 
 * 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-giosrc
24
 * @see_also: #GstFileSrc, #GstGnomeVFSSrc, #GstGioSink
25
 *
26
27
28
29
 * This plugin reads data from a local or remote location specified
 * by an URI. This location can be specified using any protocol supported by
 * the GIO library or it's VFS backends. Common protocols are 'file', 'http',
 * 'ftp', or 'smb'.
30
 *
31
32
33
34
35
36
37
38
39
40
41
42
 * If an URI or #GFile is not mounted giosrc will post a message of type
 * %GST_MESSAGE_ELEMENT with name "not-mounted" on the bus. The message
 * also contains the #GFile and the corresponding URI.
 * Applications can use the "not-mounted" message to mount the #GFile
 * by calling g_file_mount_enclosing_volume() and then restart the
 * pipeline after the mounting has succeeded. Note that right after the
 * "not-mounted" message a normal error message is posted on the bus which
 * should be ignored if "not-mounted" is handled by the application, for
 * example by calling gst_bus_set_flushing(bus, TRUE) after the "not-mounted"
 * message was received and gst_bus_set_flushing(bus, FALSE) after the
 * mounting was successful.
 *
43
44
45
 * <refsect2>
 * <title>Example launch lines</title>
 * |[
46
 * gst-launch -v giosrc location=file:///home/joe/foo.xyz ! fakesink
47
 * ]| The above pipeline will simply read a local file and do nothing with the
48
49
 * data read. Instead of giosrc, we could just as well have used the
 * filesrc element here.
50
 * |[
51
 * gst-launch -v giosrc location=smb://othercomputer/foo.xyz ! filesink location=/home/joe/foo.xyz
52
 * ]| The above pipeline will copy a file from a remote host to the local file
53
 * system using the Samba protocol.
54
 * |[
55
 * gst-launch -v giosrc location=http://music.foobar.com/demo.mp3 ! mad ! audioconvert ! audioresample ! alsasink
56
 * ]| The above pipeline will read and decode and play an mp3 file from a
57
 * web server using the http protocol.
58
59
60
 * </refsect2>
 */

61
62
63
64
65
66
67
68
/* FIXME: We would like to mount the enclosing volume of an URL
 *        if it isn't mounted yet but this is possible async-only.
 *        Unfortunately this requires a running main loop from the
 *        default context and we can't guarantuee this!
 *
 *        We would also like to do authentication while mounting.
 */

69
70
71
72
73
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "gstgiosrc.h"
74
#include <string.h>
75
76
77
78
79
80

GST_DEBUG_CATEGORY_STATIC (gst_gio_src_debug);
#define GST_CAT_DEFAULT gst_gio_src_debug

enum
{
81
82
83
  PROP_0,
  PROP_LOCATION,
  PROP_FILE
84
85
};

86
87
GST_BOILERPLATE_FULL (GstGioSrc, gst_gio_src, GstGioBaseSrc,
    GST_TYPE_GIO_BASE_SRC, gst_gio_uri_handler_do_init);
88
89

static void gst_gio_src_finalize (GObject * object);
90

91
92
93
94
static void gst_gio_src_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);
static void gst_gio_src_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);
95

96
static GInputStream *gst_gio_src_get_stream (GstGioBaseSrc * bsrc);
97

98
99
static gboolean gst_gio_src_check_get_range (GstBaseSrc * base_src);

100
101
102
103
104
static void
gst_gio_src_base_init (gpointer gclass)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);

105
  GST_DEBUG_CATEGORY_INIT (gst_gio_src_debug, "gio_src", 0, "GIO source");
106

107
108
109
110
  gst_element_class_set_details_simple (element_class, "GIO source",
      "Source/File",
      "Read from any GIO-supported location",
      "Ren\xc3\xa9 Stadler <mail@renestadler.de>, "
111
      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
112
113
114
115
116
}

static void
gst_gio_src_class_init (GstGioSrcClass * klass)
{
117
118
119
  GObjectClass *gobject_class = (GObjectClass *) klass;
  GstBaseSrcClass *gstbasesrc_class = (GstBaseSrcClass *) klass;
  GstGioBaseSrcClass *gstgiobasesrc_class = (GstGioBaseSrcClass *) klass;
120
121
122
123
124

  gobject_class->finalize = gst_gio_src_finalize;
  gobject_class->set_property = gst_gio_src_set_property;
  gobject_class->get_property = gst_gio_src_get_property;

125
  g_object_class_install_property (gobject_class, PROP_LOCATION,
126
      g_param_spec_string ("location", "Location", "URI location to read from",
127
          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
128

129
130
131
132
133
134
135
  /**
   * GstGioSrc:file
   * 
   * %GFile to read from.
   * 
   * Since: 0.10.20
   **/
136
  g_object_class_install_property (gobject_class, PROP_FILE,
137
138
139
      g_param_spec_object ("file", "File", "GFile to read from",
          G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

140
141
  gstbasesrc_class->check_get_range =
      GST_DEBUG_FUNCPTR (gst_gio_src_check_get_range);
142
143

  gstgiobasesrc_class->get_stream = GST_DEBUG_FUNCPTR (gst_gio_src_get_stream);
144
  gstgiobasesrc_class->close_on_stop = TRUE;
145
146
147
148
149
150
151
152
153
154
155
156
}

static void
gst_gio_src_init (GstGioSrc * src, GstGioSrcClass * gclass)
{
}

static void
gst_gio_src_finalize (GObject * object)
{
  GstGioSrc *src = GST_GIO_SRC (object);

157
158
159
  if (src->file) {
    g_object_unref (src->file);
    src->file = NULL;
160
  }
161
162
163
164
165
166
167
168
169
170
171

  GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
}

static void
gst_gio_src_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstGioSrc *src = GST_GIO_SRC (object);

  switch (prop_id) {
172
    case PROP_LOCATION:{
173
174
      const gchar *uri = NULL;

175
      if (GST_STATE (src) == GST_STATE_PLAYING ||
176
177
178
          GST_STATE (src) == GST_STATE_PAUSED) {
        GST_WARNING
            ("Setting a new location or GFile not supported in PLAYING or PAUSED state");
179
        break;
180
181
182
183
184
185
186
187
188
189
      }

      GST_OBJECT_LOCK (GST_OBJECT (src));
      if (src->file)
        g_object_unref (src->file);

      uri = g_value_get_string (value);

      if (uri) {
        src->file = g_file_new_for_uri (uri);
190

191
192
193
194
195
196
197
198
199
        if (!src->file) {
          GST_ERROR ("Could not create GFile for URI '%s'", uri);
        }
      } else {
        src->file = NULL;
      }
      GST_OBJECT_UNLOCK (GST_OBJECT (src));
      break;
    }
200
    case PROP_FILE:
201
202
203
204
205
206
207
208
209
210
211
212
213
214
      if (GST_STATE (src) == GST_STATE_PLAYING ||
          GST_STATE (src) == GST_STATE_PAUSED) {
        GST_WARNING
            ("Setting a new location or GFile not supported in PLAYING or PAUSED state");
        break;
      }

      GST_OBJECT_LOCK (GST_OBJECT (src));
      if (src->file)
        g_object_unref (src->file);

      src->file = g_value_dup_object (value);

      GST_OBJECT_UNLOCK (GST_OBJECT (src));
215
216
217
218
219
220
221
222
223
224
225
226
227
228
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
gst_gio_src_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstGioSrc *src = GST_GIO_SRC (object);

  switch (prop_id) {
229
    case PROP_LOCATION:{
230
231
232
233
234
235
236
237
238
239
240
241
242
      gchar *uri;

      GST_OBJECT_LOCK (GST_OBJECT (src));
      if (src->file) {
        uri = g_file_get_uri (src->file);
        g_value_set_string (value, uri);
        g_free (uri);
      } else {
        g_value_set_string (value, NULL);
      }
      GST_OBJECT_UNLOCK (GST_OBJECT (src));
      break;
    }
243
    case PROP_FILE:
244
245
246
      GST_OBJECT_LOCK (GST_OBJECT (src));
      g_value_set_object (value, src->file);
      GST_OBJECT_UNLOCK (GST_OBJECT (src));
247
248
249
250
251
252
253
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
static gboolean
gst_gio_src_check_get_range (GstBaseSrc * base_src)
{
  GstGioSrc *src = GST_GIO_SRC (base_src);
  gchar *scheme;

  if (src->file == NULL)
    goto done;

  scheme = g_file_get_uri_scheme (src->file);
  if (scheme == NULL)
    goto done;

  if (strcmp (scheme, "file") == 0) {
    GST_LOG_OBJECT (src, "local URI, assuming random access is possible");
    g_free (scheme);
    return TRUE;
  } else if (strcmp (scheme, "http") == 0 || strcmp (scheme, "https") == 0) {
    GST_LOG_OBJECT (src, "blacklisted protocol '%s', "
        "no random access possible", scheme);
    g_free (scheme);
    return FALSE;
  }

  g_free (scheme);

done:

  GST_DEBUG_OBJECT (src, "undecided about random access, asking base class");

  return GST_CALL_PARENT_WITH_DEFAULT (GST_BASE_SRC_CLASS,
      check_get_range, (base_src), FALSE);
}


289
290
static GInputStream *
gst_gio_src_get_stream (GstGioBaseSrc * bsrc)
291
{
292
  GstGioSrc *src = GST_GIO_SRC (bsrc);
293
  GError *err = NULL;
294
  GInputStream *stream;
295
  GCancellable *cancel = bsrc->cancel;
296
  gchar *uri = NULL;
297

298
  if (src->file == NULL) {
299
    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
300
        ("No location or GFile given"));
301
    return NULL;
302
303
  }

304
305
306
  uri = g_file_get_uri (src->file);
  if (!uri)
    uri = g_strdup ("(null)");
307

308
  stream = G_INPUT_STREAM (g_file_read (src->file, cancel, &err));
309

310
  if (stream == NULL && !gst_gio_error (src, "g_file_read", &err, NULL)) {
311
    if (GST_GIO_ERROR_MATCHES (err, NOT_FOUND)) {
312
      GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
313
          ("Could not open location %s for reading: %s", uri, err->message));
314
315
316
317
318
319
    } else if (GST_GIO_ERROR_MATCHES (err, NOT_MOUNTED)) {
      gst_element_post_message (GST_ELEMENT_CAST (src),
          gst_message_new_element (GST_OBJECT_CAST (src),
              gst_structure_new ("not-mounted", "file", G_TYPE_FILE, src->file,
                  "uri", G_TYPE_STRING, uri, NULL)));

320
      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
321
          ("Location %s not mounted: %s", uri, err->message));
322
    } else {
323
      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
324
          ("Could not open location %s for reading: %s", uri, err->message));
325
    }
326

327
    g_free (uri);
328
    g_clear_error (&err);
329
    return NULL;
330
  } else if (stream == NULL) {
331
    g_free (uri);
332
    return NULL;
333
  }
334

335
336
  GST_DEBUG_OBJECT (src, "opened location %s", uri);
  g_free (uri);
337

338
  return stream;
339
}