dataurisrc: Fix crash when semicolon is aprt of data
[platform/upstream/gstreamer.git] / plugins / elements / gstfdsrc.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *                    2005 Philippe Khalaf <burger@speedy.org>
5  *
6  * gstfdsrc.c:
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 /**
24  * SECTION:element-fdsrc
25  * @title: fdsrc
26  * @see_also: #GstFdSink
27  *
28  * Read data from a unix file descriptor.
29  *
30  * To generate data, enter some data on the console followed by enter.
31  * The above mentioned pipeline should dump data packets to the console.
32  *
33  * If the #GstFdSrc:timeout property is set to a value bigger than 0, fdsrc will
34  * generate an element message named <classname>&quot;GstFdSrcTimeout&quot;</classname>
35  * if no data was received in the given timeout.
36  *
37  * The message's structure contains one field:
38  *
39  * * #guint64 `timeout`: the timeout in microseconds that
40  *   expired when waiting for data.
41  *
42  * ## Example launch line
43  * |[
44  * echo "Hello GStreamer" | gst-launch-1.0 -v fdsrc ! fakesink dump=true
45  * ]| A simple pipeline to read from the standard input and dump the data
46  * with a fakesink as hex ascii block.
47  *
48  */
49
50 #ifdef HAVE_CONFIG_H
51 #  include "config.h"
52 #endif
53 #include "gst/gst_private.h"
54
55 #include <sys/types.h>
56
57 #ifdef G_OS_WIN32
58 #include <io.h>                 /* lseek, open, close, read */
59 #undef lseek
60 #define lseek _lseeki64
61 #endif
62
63 #include <sys/stat.h>
64 #ifdef HAVE_SYS_SOCKET_H
65 #include <sys/socket.h>
66 #endif
67 #include <fcntl.h>
68 #include <stdio.h>
69 #ifdef HAVE_UNISTD_H
70 #include <unistd.h>
71 #endif
72 #ifdef _MSC_VER
73 #undef stat
74 #define stat _stat
75 #define fstat _fstat
76 #define S_ISREG(m)      (((m)&S_IFREG)==S_IFREG)
77 #endif
78 #include <stdlib.h>
79 #include <errno.h>
80
81 #include "gstfdsrc.h"
82
83 #ifdef __BIONIC__               /* Android */
84 #if defined(__ANDROID_API__) && __ANDROID_API__ >= 21
85 #undef fstat
86 #define fstat fstat64
87 #endif
88 #endif
89
90 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
91     GST_PAD_SRC,
92     GST_PAD_ALWAYS,
93     GST_STATIC_CAPS_ANY);
94
95 GST_DEBUG_CATEGORY_STATIC (gst_fd_src_debug);
96 #define GST_CAT_DEFAULT gst_fd_src_debug
97
98 #define DEFAULT_FD              0
99 #define DEFAULT_TIMEOUT         0
100
101 enum
102 {
103   PROP_0,
104
105   PROP_FD,
106   PROP_TIMEOUT,
107
108   PROP_LAST
109 };
110
111 static void gst_fd_src_uri_handler_init (gpointer g_iface, gpointer iface_data);
112
113 #define _do_init \
114   G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_fd_src_uri_handler_init); \
115   GST_DEBUG_CATEGORY_INIT (gst_fd_src_debug, "fdsrc", 0, "fdsrc element");
116 #define gst_fd_src_parent_class parent_class
117 G_DEFINE_TYPE_WITH_CODE (GstFdSrc, gst_fd_src, GST_TYPE_PUSH_SRC, _do_init);
118
119 static void gst_fd_src_set_property (GObject * object, guint prop_id,
120     const GValue * value, GParamSpec * pspec);
121 static void gst_fd_src_get_property (GObject * object, guint prop_id,
122     GValue * value, GParamSpec * pspec);
123 static void gst_fd_src_dispose (GObject * obj);
124
125 static gboolean gst_fd_src_start (GstBaseSrc * bsrc);
126 static gboolean gst_fd_src_stop (GstBaseSrc * bsrc);
127 static gboolean gst_fd_src_unlock (GstBaseSrc * bsrc);
128 static gboolean gst_fd_src_unlock_stop (GstBaseSrc * bsrc);
129 static gboolean gst_fd_src_is_seekable (GstBaseSrc * bsrc);
130 static gboolean gst_fd_src_get_size (GstBaseSrc * src, guint64 * size);
131 static gboolean gst_fd_src_do_seek (GstBaseSrc * src, GstSegment * segment);
132 static gboolean gst_fd_src_query (GstBaseSrc * src, GstQuery * query);
133
134 static GstFlowReturn gst_fd_src_create (GstPushSrc * psrc, GstBuffer ** outbuf);
135
136 static void
137 gst_fd_src_class_init (GstFdSrcClass * klass)
138 {
139   GObjectClass *gobject_class;
140   GstElementClass *gstelement_class;
141   GstBaseSrcClass *gstbasesrc_class;
142   GstPushSrcClass *gstpush_src_class;
143
144   gobject_class = G_OBJECT_CLASS (klass);
145   gstelement_class = GST_ELEMENT_CLASS (klass);
146   gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
147   gstpush_src_class = GST_PUSH_SRC_CLASS (klass);
148
149   gobject_class->set_property = gst_fd_src_set_property;
150   gobject_class->get_property = gst_fd_src_get_property;
151   gobject_class->dispose = gst_fd_src_dispose;
152
153   g_object_class_install_property (gobject_class, PROP_FD,
154       g_param_spec_int ("fd", "fd", "An open file descriptor to read from",
155           0, G_MAXINT, DEFAULT_FD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
156   /**
157    * GstFdSrc:timeout
158    *
159    * Post a message after timeout microseconds
160    */
161   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMEOUT,
162       g_param_spec_uint64 ("timeout", "Timeout",
163           "Post a message after timeout microseconds (0 = disabled)", 0,
164           G_MAXUINT64, DEFAULT_TIMEOUT,
165           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
166
167   gst_element_class_set_static_metadata (gstelement_class,
168       "Filedescriptor Source",
169       "Source/File",
170       "Read from a file descriptor", "Erik Walthinsen <omega@cse.ogi.edu>");
171   gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
172
173   gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_fd_src_start);
174   gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_fd_src_stop);
175   gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_fd_src_unlock);
176   gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_fd_src_unlock_stop);
177   gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_fd_src_is_seekable);
178   gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_fd_src_get_size);
179   gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_fd_src_do_seek);
180   gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_fd_src_query);
181
182   gstpush_src_class->create = GST_DEBUG_FUNCPTR (gst_fd_src_create);
183 }
184
185 static void
186 gst_fd_src_init (GstFdSrc * fdsrc)
187 {
188   fdsrc->new_fd = DEFAULT_FD;
189   fdsrc->seekable_fd = FALSE;
190   fdsrc->fd = -1;
191   fdsrc->size = -1;
192   fdsrc->timeout = DEFAULT_TIMEOUT;
193   fdsrc->uri = g_strdup_printf ("fd://0");
194   fdsrc->curoffset = 0;
195 }
196
197 static void
198 gst_fd_src_dispose (GObject * obj)
199 {
200   GstFdSrc *src = GST_FD_SRC (obj);
201
202   g_free (src->uri);
203   src->uri = NULL;
204
205   G_OBJECT_CLASS (parent_class)->dispose (obj);
206 }
207
208 static void
209 gst_fd_src_update_fd (GstFdSrc * src, guint64 size)
210 {
211   struct stat stat_results;
212
213   GST_DEBUG_OBJECT (src, "fdset %p, old_fd %d, new_fd %d", src->fdset, src->fd,
214       src->new_fd);
215
216   /* we need to always update the fdset since it may not have existed when
217    * gst_fd_src_update_fd () was called earlier */
218   if (src->fdset != NULL) {
219     GstPollFD fd = GST_POLL_FD_INIT;
220
221     if (src->fd >= 0) {
222       fd.fd = src->fd;
223       /* this will log a harmless warning, if it was never added */
224       gst_poll_remove_fd (src->fdset, &fd);
225     }
226
227     fd.fd = src->new_fd;
228     gst_poll_add_fd (src->fdset, &fd);
229     gst_poll_fd_ctl_read (src->fdset, &fd, TRUE);
230   }
231
232
233   if (src->fd != src->new_fd) {
234     GST_INFO_OBJECT (src, "Updating to fd %d", src->new_fd);
235
236     src->fd = src->new_fd;
237
238     GST_INFO_OBJECT (src, "Setting size to fd %" G_GUINT64_FORMAT, size);
239     src->size = size;
240
241     g_free (src->uri);
242     src->uri = g_strdup_printf ("fd://%d", src->fd);
243
244     if (fstat (src->fd, &stat_results) < 0)
245       goto not_seekable;
246
247     if (!S_ISREG (stat_results.st_mode))
248       goto not_seekable;
249
250     /* Try a seek of 0 bytes offset to check for seekability */
251     if (lseek (src->fd, 0, SEEK_CUR) < 0)
252       goto not_seekable;
253
254     GST_INFO_OBJECT (src, "marking fd %d as seekable", src->fd);
255     src->seekable_fd = TRUE;
256
257     gst_base_src_set_dynamic_size (GST_BASE_SRC (src), TRUE);
258   }
259   return;
260
261 not_seekable:
262   {
263     GST_INFO_OBJECT (src, "marking fd %d as NOT seekable", src->fd);
264     src->seekable_fd = FALSE;
265     gst_base_src_set_dynamic_size (GST_BASE_SRC (src), FALSE);
266   }
267 }
268
269 static gboolean
270 gst_fd_src_start (GstBaseSrc * bsrc)
271 {
272   GstFdSrc *src = GST_FD_SRC (bsrc);
273
274   src->curoffset = 0;
275
276   if ((src->fdset = gst_poll_new (TRUE)) == NULL)
277     goto socket_pair;
278
279   gst_fd_src_update_fd (src, -1);
280
281   return TRUE;
282
283   /* ERRORS */
284 socket_pair:
285   {
286     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
287         GST_ERROR_SYSTEM);
288     return FALSE;
289   }
290 }
291
292 static gboolean
293 gst_fd_src_stop (GstBaseSrc * bsrc)
294 {
295   GstFdSrc *src = GST_FD_SRC (bsrc);
296
297   if (src->fdset) {
298     gst_poll_free (src->fdset);
299     src->fdset = NULL;
300   }
301
302   return TRUE;
303 }
304
305 static gboolean
306 gst_fd_src_unlock (GstBaseSrc * bsrc)
307 {
308   GstFdSrc *src = GST_FD_SRC (bsrc);
309
310   GST_LOG_OBJECT (src, "Flushing");
311   GST_OBJECT_LOCK (src);
312   gst_poll_set_flushing (src->fdset, TRUE);
313   GST_OBJECT_UNLOCK (src);
314
315   return TRUE;
316 }
317
318 static gboolean
319 gst_fd_src_unlock_stop (GstBaseSrc * bsrc)
320 {
321   GstFdSrc *src = GST_FD_SRC (bsrc);
322
323   GST_LOG_OBJECT (src, "No longer flushing");
324   GST_OBJECT_LOCK (src);
325   gst_poll_set_flushing (src->fdset, FALSE);
326   GST_OBJECT_UNLOCK (src);
327
328   return TRUE;
329 }
330
331 static void
332 gst_fd_src_set_property (GObject * object, guint prop_id, const GValue * value,
333     GParamSpec * pspec)
334 {
335   GstFdSrc *src = GST_FD_SRC (object);
336
337   switch (prop_id) {
338     case PROP_FD:
339       src->new_fd = g_value_get_int (value);
340
341       /* If state is ready or below, update the current fd immediately
342        * so it is reflected in get_properties and uri */
343       GST_OBJECT_LOCK (object);
344       if (GST_STATE (GST_ELEMENT (src)) <= GST_STATE_READY) {
345         GST_DEBUG_OBJECT (src, "state ready or lower, updating to use new fd");
346         gst_fd_src_update_fd (src, -1);
347       } else {
348         GST_DEBUG_OBJECT (src, "state above ready, not updating to new fd yet");
349       }
350       GST_OBJECT_UNLOCK (object);
351       break;
352     case PROP_TIMEOUT:
353       src->timeout = g_value_get_uint64 (value);
354       GST_DEBUG_OBJECT (src, "poll timeout set to %" GST_TIME_FORMAT,
355           GST_TIME_ARGS (src->timeout));
356       break;
357     default:
358       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
359       break;
360   }
361 }
362
363 static void
364 gst_fd_src_get_property (GObject * object, guint prop_id, GValue * value,
365     GParamSpec * pspec)
366 {
367   GstFdSrc *src = GST_FD_SRC (object);
368
369   switch (prop_id) {
370     case PROP_FD:
371       g_value_set_int (value, src->fd);
372       break;
373     case PROP_TIMEOUT:
374       g_value_set_uint64 (value, src->timeout);
375       break;
376     default:
377       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
378       break;
379   }
380 }
381
382 static GstFlowReturn
383 gst_fd_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
384 {
385   GstFdSrc *src;
386   GstBuffer *buf;
387   gssize readbytes;
388   guint blocksize;
389   GstMapInfo info;
390
391 #ifndef HAVE_WIN32
392   GstClockTime timeout;
393   gboolean try_again;
394   gint retval;
395 #endif
396
397   src = GST_FD_SRC (psrc);
398
399 #ifndef HAVE_WIN32
400   if (src->timeout > 0) {
401     timeout = src->timeout * GST_USECOND;
402   } else {
403     timeout = GST_CLOCK_TIME_NONE;
404   }
405
406   do {
407     try_again = FALSE;
408
409     GST_LOG_OBJECT (src, "doing poll, timeout %" GST_TIME_FORMAT,
410         GST_TIME_ARGS (src->timeout));
411
412     retval = gst_poll_wait (src->fdset, timeout);
413     GST_LOG_OBJECT (src, "poll returned %d", retval);
414
415     if (G_UNLIKELY (retval == -1)) {
416       if (errno == EINTR || errno == EAGAIN) {
417         /* retry if interrupted */
418         try_again = TRUE;
419       } else if (errno == EBUSY) {
420         goto stopped;
421       } else {
422         goto poll_error;
423       }
424     } else if (G_UNLIKELY (retval == 0)) {
425       try_again = TRUE;
426       /* timeout, post element message */
427       gst_element_post_message (GST_ELEMENT_CAST (src),
428           gst_message_new_element (GST_OBJECT_CAST (src),
429               gst_structure_new ("GstFdSrcTimeout",
430                   "timeout", G_TYPE_UINT64, src->timeout, NULL)));
431     }
432   } while (G_UNLIKELY (try_again));     /* retry if interrupted or timeout */
433 #endif
434
435   blocksize = GST_BASE_SRC (src)->blocksize;
436
437   /* create the buffer */
438   buf = gst_buffer_new_allocate (NULL, blocksize, NULL);
439   if (G_UNLIKELY (buf == NULL))
440     goto alloc_failed;
441
442   if (!gst_buffer_map (buf, &info, GST_MAP_WRITE))
443     goto buffer_read_error;
444
445   do {
446     readbytes = read (src->fd, info.data, blocksize);
447     GST_LOG_OBJECT (src, "read %" G_GSSIZE_FORMAT, readbytes);
448   } while (readbytes == -1 && errno == EINTR);  /* retry if interrupted */
449
450   if (readbytes < 0)
451     goto read_error;
452
453   gst_buffer_unmap (buf, &info);
454   gst_buffer_resize (buf, 0, readbytes);
455
456   if (readbytes == 0)
457     goto eos;
458
459   GST_BUFFER_OFFSET (buf) = src->curoffset;
460   GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
461   src->curoffset += readbytes;
462
463   GST_LOG_OBJECT (psrc, "Read buffer of size %" G_GSSIZE_FORMAT, readbytes);
464
465   /* we're done, return the buffer */
466   *outbuf = buf;
467
468   return GST_FLOW_OK;
469
470   /* ERRORS */
471 #ifndef HAVE_WIN32
472 poll_error:
473   {
474     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
475         ("poll on file descriptor: %s.", g_strerror (errno)));
476     GST_DEBUG_OBJECT (psrc, "Error during poll");
477     return GST_FLOW_ERROR;
478   }
479 stopped:
480   {
481     GST_DEBUG_OBJECT (psrc, "Poll stopped");
482     return GST_FLOW_FLUSHING;
483   }
484 #endif
485 alloc_failed:
486   {
487     GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", blocksize);
488     return GST_FLOW_ERROR;
489   }
490 eos:
491   {
492     GST_DEBUG_OBJECT (psrc, "Read 0 bytes. EOS.");
493     gst_buffer_unref (buf);
494     return GST_FLOW_EOS;
495   }
496 read_error:
497   {
498     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
499         ("read on file descriptor: %s.", g_strerror (errno)));
500     GST_DEBUG_OBJECT (psrc, "Error reading from fd");
501     gst_buffer_unmap (buf, &info);
502     gst_buffer_unref (buf);
503     return GST_FLOW_ERROR;
504   }
505 buffer_read_error:
506   {
507     GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL), ("Can't write to buffer"));
508     gst_buffer_unref (buf);
509     return GST_FLOW_ERROR;
510   }
511 }
512
513 static gboolean
514 gst_fd_src_query (GstBaseSrc * basesrc, GstQuery * query)
515 {
516   gboolean ret = FALSE;
517   GstFdSrc *src = GST_FD_SRC (basesrc);
518
519   switch (GST_QUERY_TYPE (query)) {
520     case GST_QUERY_URI:
521       gst_query_set_uri (query, src->uri);
522       ret = TRUE;
523       break;
524     default:
525       ret = FALSE;
526       break;
527   }
528
529   if (!ret)
530     ret = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
531
532   return ret;
533 }
534
535 static gboolean
536 gst_fd_src_is_seekable (GstBaseSrc * bsrc)
537 {
538   GstFdSrc *src = GST_FD_SRC (bsrc);
539
540   return src->seekable_fd;
541 }
542
543 static gboolean
544 gst_fd_src_get_size (GstBaseSrc * bsrc, guint64 * size)
545 {
546   GstFdSrc *src = GST_FD_SRC (bsrc);
547   struct stat stat_results;
548
549   if (src->size != -1) {
550     *size = src->size;
551     return TRUE;
552   }
553
554   if (!src->seekable_fd) {
555     /* If it isn't seekable, we won't know the length (but fstat will still
556      * succeed, and wrongly say our length is zero. */
557     return FALSE;
558   }
559
560   if (fstat (src->fd, &stat_results) < 0)
561     goto could_not_stat;
562
563   *size = stat_results.st_size;
564
565   return TRUE;
566
567   /* ERROR */
568 could_not_stat:
569   {
570     return FALSE;
571   }
572 }
573
574 static gboolean
575 gst_fd_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment)
576 {
577   gint res;
578   gint64 offset;
579   GstFdSrc *src = GST_FD_SRC (bsrc);
580
581   offset = segment->start;
582
583   /* No need to seek to the current position */
584   if (offset == src->curoffset)
585     return TRUE;
586
587   res = lseek (src->fd, offset, SEEK_SET);
588   if (G_UNLIKELY (res < 0 || res != offset))
589     goto seek_failed;
590
591   segment->position = segment->start;
592   segment->time = segment->start;
593
594   return TRUE;
595
596 seek_failed:
597   GST_DEBUG_OBJECT (src, "lseek returned %" G_GINT64_FORMAT, offset);
598   return FALSE;
599 }
600
601 /*** GSTURIHANDLER INTERFACE *************************************************/
602
603 static GstURIType
604 gst_fd_src_uri_get_type (GType type)
605 {
606   return GST_URI_SRC;
607 }
608
609 static const gchar *const *
610 gst_fd_src_uri_get_protocols (GType type)
611 {
612   static const gchar *protocols[] = { "fd", NULL };
613
614   return protocols;
615 }
616
617 static gchar *
618 gst_fd_src_uri_get_uri (GstURIHandler * handler)
619 {
620   GstFdSrc *src = GST_FD_SRC (handler);
621
622   /* FIXME: make thread-safe */
623   return g_strdup (src->uri);
624 }
625
626 static gboolean
627 gst_fd_src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
628     GError ** err)
629 {
630   gchar *protocol, *q;
631   GstFdSrc *src = GST_FD_SRC (handler);
632   gint fd;
633   guint64 size = (guint64) - 1;
634
635   GST_INFO_OBJECT (src, "checking uri %s", uri);
636
637   protocol = gst_uri_get_protocol (uri);
638   if (strcmp (protocol, "fd") != 0) {
639     g_set_error (err, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
640         "Wrong protocol for fdsrc in uri: '%s'", uri);
641     g_free (protocol);
642     return FALSE;
643   }
644   g_free (protocol);
645
646   if (sscanf (uri, "fd://%d", &fd) != 1 || fd < 0) {
647     g_set_error (err, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
648         "Bad file descriptor number in uri: '%s'", uri);
649     return FALSE;
650   }
651
652   if ((q = g_strstr_len (uri, -1, "?"))) {
653     gchar *sp, *end = NULL;
654
655     GST_INFO_OBJECT (src, "found ?");
656
657     if ((sp = g_strstr_len (q, -1, "size="))) {
658       sp += strlen ("size=");
659       size = g_ascii_strtoull (sp, &end, 10);
660       if ((size == 0 && errno == EINVAL) || size == G_MAXUINT64 || end == sp) {
661         GST_INFO_OBJECT (src, "parsing size failed");
662         size = -1;
663       } else {
664         GST_INFO_OBJECT (src, "found size %" G_GUINT64_FORMAT, size);
665       }
666     }
667   }
668
669   src->new_fd = fd;
670
671   GST_OBJECT_LOCK (src);
672   if (GST_STATE (GST_ELEMENT (src)) <= GST_STATE_READY) {
673     gst_fd_src_update_fd (src, size);
674   }
675   GST_OBJECT_UNLOCK (src);
676
677   return TRUE;
678 }
679
680 static void
681 gst_fd_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
682 {
683   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
684
685   iface->get_type = gst_fd_src_uri_get_type;
686   iface->get_protocols = gst_fd_src_uri_get_protocols;
687   iface->get_uri = gst_fd_src_uri_get_uri;
688   iface->set_uri = gst_fd_src_uri_set_uri;
689 }