"Fossies" - the Fresh Open Source Software Archive

Member "gstreamer-1.16.1/plugins/elements/gstfdsrc.c" (19 Apr 2019, 17971 Bytes) of package /linux/misc/gstreamer-1.16.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gstfdsrc.c" see the Fossies "Dox" file reference documentation.

    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 }