gstreamer_core/plugins/elements/gstfilesrc.c
changeset 0 0e761a78d257
child 8 4a7fac7dd34a
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     1 /* GStreamer
       
     2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
       
     3  *               2000,2005 Wim Taymans <wim@fluendo.com>
       
     4  *
       
     5  * gstfilesrc.c:
       
     6  *
       
     7  * This library is free software; you can redistribute it and/or
       
     8  * modify it under the terms of the GNU Library General Public
       
     9  * License as published by the Free Software Foundation; either
       
    10  * version 2 of the License, or (at your option) any later version.
       
    11  *
       
    12  * This library is distributed in the hope that it will be useful,
       
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    15  * Library General Public License for more details.
       
    16  *
       
    17  * You should have received a copy of the GNU Library General Public
       
    18  * License along with this library; if not, write to the
       
    19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    20  * Boston, MA 02111-1307, USA.
       
    21  */
       
    22 /**
       
    23  * SECTION:element-filesrc
       
    24  * @short_description: read from arbitrary point in a file
       
    25  * @see_also: #GstFileSrc
       
    26  *
       
    27  * Read data from a file in the local file system.
       
    28  */
       
    29 
       
    30 #ifdef HAVE_CONFIG_H
       
    31 #  include "config.h"
       
    32 #endif
       
    33 #ifdef __SYMBIAN32__
       
    34 #include <gst_global.h>
       
    35 #endif
       
    36 
       
    37 #include <gst/gst.h>
       
    38 #include "gstfilesrc.h"
       
    39 
       
    40 #include <stdio.h>
       
    41 #include <sys/types.h>
       
    42 #include <sys/stat.h>
       
    43 #include <fcntl.h>
       
    44 
       
    45 #ifdef __SYMBIAN32__
       
    46 #include <glib_global.h>
       
    47 #include <gobject_global.h>
       
    48 #endif
       
    49 
       
    50 #ifdef HAVE_UNISTD_H
       
    51 #  include <unistd.h>
       
    52 #endif
       
    53 
       
    54 #ifdef HAVE_MMAP
       
    55 # include <sys/mman.h>
       
    56 #endif
       
    57 
       
    58 #ifdef HAVE_WIN32
       
    59 #  include <io.h>               /* lseek, open, close, read */
       
    60 #endif
       
    61 
       
    62 #include <errno.h>
       
    63 #include <string.h>
       
    64 
       
    65 #include "../../gst/gst-i18n-lib.h"
       
    66 #include <gstelement.h>
       
    67 
       
    68 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
       
    69     GST_PAD_SRC,
       
    70     GST_PAD_ALWAYS,
       
    71     GST_STATIC_CAPS_ANY);
       
    72 
       
    73 /* FIXME we should be using glib for this */
       
    74 #ifndef S_ISREG
       
    75 #define S_ISREG(mode) ((mode)&_S_IFREG)
       
    76 #endif
       
    77 #ifndef S_ISDIR
       
    78 #define S_ISDIR(mode) ((mode)&_S_IFDIR)
       
    79 #endif
       
    80 #ifndef S_ISSOCK
       
    81 #define S_ISSOCK(x) (0)
       
    82 #endif
       
    83 #ifndef O_BINARY
       
    84 #define O_BINARY (0)
       
    85 #endif
       
    86 
       
    87 
       
    88 /**********************************************************************
       
    89  * GStreamer Default File Source
       
    90  * Theory of Operation
       
    91  *
       
    92  * Update: see GstFileSrc:use-mmap property documentation below
       
    93  *         for why use of mmap() is disabled by default.
       
    94  *
       
    95  * This source uses mmap(2) to efficiently load data from a file.
       
    96  * To do this without seriously polluting the applications' memory
       
    97  * space, it must do so in smaller chunks, say 1-4MB at a time.
       
    98  * Buffers are then subdivided from these mmap'd chunks, to directly
       
    99  * make use of the mmap.
       
   100  *
       
   101  * To handle refcounting so that the mmap can be freed at the appropriate
       
   102  * time, a buffer will be created for each mmap'd region, and all new
       
   103  * buffers will be sub-buffers of this top-level buffer.  As they are
       
   104  * freed, the refcount goes down on the mmap'd buffer and its free()
       
   105  * function is called, which will call munmap(2) on itself.
       
   106  *
       
   107  * If a buffer happens to cross the boundaries of an mmap'd region, we
       
   108  * have to decide whether it's more efficient to copy the data into a
       
   109  * new buffer, or mmap() just that buffer.  There will have to be a
       
   110  * breakpoint size to determine which will be done.  The mmap() size
       
   111  * has a lot to do with this as well, because you end up in double-
       
   112  * jeopardy: the larger the outgoing buffer, the more data to copy when
       
   113  * it overlaps, *and* the more frequently you'll have buffers that *do*
       
   114  * overlap.
       
   115  *
       
   116  * Seeking is another tricky aspect to do efficiently.  The initial
       
   117  * implementation of this source won't make use of these features, however.
       
   118  * The issue is that if an application seeks backwards in a file, *and*
       
   119  * that region of the file is covered by an mmap that hasn't been fully
       
   120  * deallocated, we really should re-use it.  But keeping track of these
       
   121  * regions is tricky because we have to lock the structure that holds
       
   122  * them.  We need to settle on a locking primitive (GMutex seems to be
       
   123  * a really good option...), then we can do that.
       
   124  */
       
   125 
       
   126 
       
   127 GST_DEBUG_CATEGORY_STATIC (gst_file_src_debug);
       
   128 #define GST_CAT_DEFAULT gst_file_src_debug
       
   129 
       
   130 /* FileSrc signals and args */
       
   131 enum
       
   132 {
       
   133   /* FILL ME */
       
   134   LAST_SIGNAL
       
   135 };
       
   136 
       
   137 #define DEFAULT_BLOCKSIZE       4*1024
       
   138 #define DEFAULT_MMAPSIZE        4*1024*1024
       
   139 #define DEFAULT_TOUCH           TRUE
       
   140 #define DEFAULT_USEMMAP         FALSE
       
   141 #define DEFAULT_SEQUENTIAL      FALSE
       
   142 
       
   143 enum
       
   144 {
       
   145   ARG_0,
       
   146   ARG_LOCATION,
       
   147   ARG_FD,
       
   148   ARG_MMAPSIZE,
       
   149   ARG_SEQUENTIAL,
       
   150   ARG_TOUCH,
       
   151   ARG_USEMMAP
       
   152 };
       
   153 
       
   154 static void gst_file_src_finalize (GObject * object);
       
   155 
       
   156 static void gst_file_src_set_property (GObject * object, guint prop_id,
       
   157     const GValue * value, GParamSpec * pspec);
       
   158 static void gst_file_src_get_property (GObject * object, guint prop_id,
       
   159     GValue * value, GParamSpec * pspec);
       
   160 
       
   161 static gboolean gst_file_src_start (GstBaseSrc * basesrc);
       
   162 static gboolean gst_file_src_stop (GstBaseSrc * basesrc);
       
   163 
       
   164 static gboolean gst_file_src_is_seekable (GstBaseSrc * src);
       
   165 static gboolean gst_file_src_get_size (GstBaseSrc * src, guint64 * size);
       
   166 static GstFlowReturn gst_file_src_create (GstBaseSrc * src, guint64 offset,
       
   167     guint length, GstBuffer ** buffer);
       
   168 
       
   169 static void gst_file_src_uri_handler_init (gpointer g_iface,
       
   170     gpointer iface_data);
       
   171 
       
   172 static void
       
   173 _do_init (GType filesrc_type)
       
   174 {
       
   175   static const GInterfaceInfo urihandler_info = {
       
   176     gst_file_src_uri_handler_init,
       
   177     NULL,
       
   178     NULL
       
   179   };
       
   180 
       
   181   g_type_add_interface_static (filesrc_type, GST_TYPE_URI_HANDLER,
       
   182       &urihandler_info);
       
   183   GST_DEBUG_CATEGORY_INIT (gst_file_src_debug, "filesrc", 0, "filesrc element");
       
   184 }
       
   185 
       
   186 GST_BOILERPLATE_FULL (GstFileSrc, gst_file_src, GstBaseSrc, GST_TYPE_BASE_SRC,
       
   187     _do_init);
       
   188 
       
   189 static void
       
   190 gst_file_src_base_init (gpointer g_class)
       
   191 {
       
   192   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
       
   193 
       
   194   gst_element_class_set_details_simple (gstelement_class,
       
   195       "File Source",
       
   196       "Source/File",
       
   197       "Read from arbitrary point in a file",
       
   198       "Erik Walthinsen <omega@cse.ogi.edu>");
       
   199   gst_element_class_add_pad_template (gstelement_class,
       
   200       gst_static_pad_template_get (&srctemplate));
       
   201 }
       
   202 
       
   203 static void
       
   204 gst_file_src_class_init (GstFileSrcClass * klass)
       
   205 {
       
   206   GObjectClass *gobject_class;
       
   207   GstElementClass *gstelement_class;
       
   208   GstBaseSrcClass *gstbasesrc_class;
       
   209 
       
   210   gobject_class = G_OBJECT_CLASS (klass);
       
   211   gstelement_class = GST_ELEMENT_CLASS (klass);
       
   212   gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
       
   213 
       
   214   gobject_class->set_property = gst_file_src_set_property;
       
   215   gobject_class->get_property = gst_file_src_get_property;
       
   216 
       
   217   g_object_class_install_property (gobject_class, ARG_FD,
       
   218       g_param_spec_int ("fd", "File-descriptor",
       
   219           "File-descriptor for the file being mmap()d", 0, G_MAXINT, 0,
       
   220           G_PARAM_READABLE));
       
   221   g_object_class_install_property (gobject_class, ARG_LOCATION,
       
   222       g_param_spec_string ("location", "File Location",
       
   223           "Location of the file to read", NULL, G_PARAM_READWRITE));
       
   224   g_object_class_install_property (gobject_class, ARG_MMAPSIZE,
       
   225       g_param_spec_ulong ("mmapsize", "mmap() Block Size",
       
   226           "Size in bytes of mmap()d regions", 0, G_MAXULONG, DEFAULT_MMAPSIZE,
       
   227           G_PARAM_READWRITE));
       
   228   g_object_class_install_property (gobject_class, ARG_TOUCH,
       
   229       g_param_spec_boolean ("touch", "Touch mapped region read data",
       
   230           "Touch mmapped data regions to force them to be read from disk",
       
   231           DEFAULT_TOUCH, G_PARAM_READWRITE));
       
   232   /**
       
   233    * GstFileSrc:use-mmap
       
   234    *
       
   235    * Whether to use mmap(). Set to TRUE to force use of mmap() instead of
       
   236    * read() for reading data.
       
   237    *
       
   238    * Use of mmap() is disabled by default since with mmap() there are a
       
   239    * number of occasions where the process/application will be notified of
       
   240    * read errors via a SIGBUS signal from the kernel, which will lead to
       
   241    * the application being killed if not handled by the application. This
       
   242    * is something that is difficult to work around for a library like
       
   243    * GStreamer, hence use of mmap() is disabled by default. Said errors
       
   244    * can occur for example when an external device (e.g. an external hard
       
   245    * drive or a portable music player) are unplugged while in use, or when
       
   246    * a CD/DVD medium cannot be be read because the medium is scratched or
       
   247    * otherwise damaged.
       
   248    *
       
   249    **/
       
   250   g_object_class_install_property (gobject_class, ARG_USEMMAP,
       
   251       g_param_spec_boolean ("use-mmap", "Use mmap to read data",
       
   252           "Whether to use mmap() instead of read()",
       
   253           DEFAULT_USEMMAP, G_PARAM_READWRITE));
       
   254   g_object_class_install_property (gobject_class, ARG_SEQUENTIAL,
       
   255       g_param_spec_boolean ("sequential", "Optimise for sequential mmap access",
       
   256           "Whether to use madvise to hint to the kernel that access to "
       
   257           "mmap pages will be sequential",
       
   258           DEFAULT_SEQUENTIAL, G_PARAM_READWRITE));
       
   259 
       
   260   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_file_src_finalize);
       
   261 
       
   262   gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_file_src_start);
       
   263   gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_file_src_stop);
       
   264   gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_file_src_is_seekable);
       
   265   gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_file_src_get_size);
       
   266   gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_file_src_create);
       
   267 
       
   268   if (sizeof (off_t) < 8) {
       
   269     GST_LOG ("No large file support, sizeof (off_t) = %" G_GSIZE_FORMAT "!",
       
   270         sizeof (off_t));
       
   271   }
       
   272 }
       
   273 
       
   274 static void
       
   275 gst_file_src_init (GstFileSrc * src, GstFileSrcClass * g_class)
       
   276 {
       
   277 #ifdef HAVE_MMAP
       
   278   src->pagesize = getpagesize ();
       
   279 #endif
       
   280 
       
   281   src->filename = NULL;
       
   282   src->fd = 0;
       
   283   src->uri = NULL;
       
   284 
       
   285   src->touch = DEFAULT_TOUCH;
       
   286 
       
   287   src->mapbuf = NULL;
       
   288   src->mapsize = DEFAULT_MMAPSIZE;      /* default is 4MB */
       
   289   src->use_mmap = DEFAULT_USEMMAP;
       
   290   src->sequential = DEFAULT_SEQUENTIAL;
       
   291 
       
   292   src->is_regular = FALSE;
       
   293 }
       
   294 
       
   295 static void
       
   296 gst_file_src_finalize (GObject * object)
       
   297 {
       
   298   GstFileSrc *src;
       
   299 
       
   300   src = GST_FILE_SRC (object);
       
   301 
       
   302   g_free (src->filename);
       
   303   g_free (src->uri);
       
   304 
       
   305   G_OBJECT_CLASS (parent_class)->finalize (object);
       
   306 }
       
   307 
       
   308 static gboolean
       
   309 gst_file_src_set_location (GstFileSrc * src, const gchar * location)
       
   310 {
       
   311   GstState state;
       
   312 
       
   313   /* the element must be stopped in order to do this */
       
   314   GST_OBJECT_LOCK (src);
       
   315   state = GST_STATE (src);
       
   316   if (state != GST_STATE_READY && state != GST_STATE_NULL)
       
   317     goto wrong_state;
       
   318   GST_OBJECT_UNLOCK (src);
       
   319 
       
   320   g_free (src->filename);
       
   321   g_free (src->uri);
       
   322 
       
   323   /* clear the filename if we get a NULL (is that possible?) */
       
   324   if (location == NULL) {
       
   325     src->filename = NULL;
       
   326     src->uri = NULL;
       
   327   } else {
       
   328     src->filename = g_strdup (location);
       
   329     src->uri = gst_uri_construct ("file", src->filename);
       
   330   }
       
   331   g_object_notify (G_OBJECT (src), "location");
       
   332   gst_uri_handler_new_uri (GST_URI_HANDLER (src), src->uri);
       
   333 
       
   334   return TRUE;
       
   335 
       
   336   /* ERROR */
       
   337 wrong_state:
       
   338   {
       
   339     GST_DEBUG_OBJECT (src, "setting location in wrong state");
       
   340     GST_OBJECT_UNLOCK (src);
       
   341     return FALSE;
       
   342   }
       
   343 }
       
   344 
       
   345 static void
       
   346 gst_file_src_set_property (GObject * object, guint prop_id,
       
   347     const GValue * value, GParamSpec * pspec)
       
   348 {
       
   349   GstFileSrc *src;
       
   350 
       
   351   g_return_if_fail (GST_IS_FILE_SRC (object));
       
   352 
       
   353   src = GST_FILE_SRC (object);
       
   354 
       
   355   switch (prop_id) {
       
   356     case ARG_LOCATION:
       
   357       gst_file_src_set_location (src, g_value_get_string (value));
       
   358       break;
       
   359     case ARG_MMAPSIZE:
       
   360       if ((src->mapsize % src->pagesize) == 0) {
       
   361         src->mapsize = g_value_get_ulong (value);
       
   362       } else {
       
   363         GST_INFO_OBJECT (src,
       
   364             "invalid mapsize, must be a multiple of pagesize, which is %d",
       
   365             src->pagesize);
       
   366       }
       
   367       break;
       
   368     case ARG_TOUCH:
       
   369       src->touch = g_value_get_boolean (value);
       
   370       break;
       
   371     case ARG_SEQUENTIAL:
       
   372       src->sequential = g_value_get_boolean (value);
       
   373       break;
       
   374     case ARG_USEMMAP:
       
   375       src->use_mmap = g_value_get_boolean (value);
       
   376       break;
       
   377     default:
       
   378       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   379       break;
       
   380   }
       
   381 }
       
   382 
       
   383 static void
       
   384 gst_file_src_get_property (GObject * object, guint prop_id, GValue * value,
       
   385     GParamSpec * pspec)
       
   386 {
       
   387   GstFileSrc *src;
       
   388 
       
   389   g_return_if_fail (GST_IS_FILE_SRC (object));
       
   390 
       
   391   src = GST_FILE_SRC (object);
       
   392 
       
   393   switch (prop_id) {
       
   394     case ARG_LOCATION:
       
   395       g_value_set_string (value, src->filename);
       
   396       break;
       
   397     case ARG_FD:
       
   398       g_value_set_int (value, src->fd);
       
   399       break;
       
   400     case ARG_MMAPSIZE:
       
   401       g_value_set_ulong (value, src->mapsize);
       
   402       break;
       
   403     case ARG_TOUCH:
       
   404       g_value_set_boolean (value, src->touch);
       
   405       break;
       
   406     case ARG_SEQUENTIAL:
       
   407       g_value_set_boolean (value, src->sequential);
       
   408       break;
       
   409     case ARG_USEMMAP:
       
   410       g_value_set_boolean (value, src->use_mmap);
       
   411       break;
       
   412     default:
       
   413       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   414       break;
       
   415   }
       
   416 }
       
   417 
       
   418 /***
       
   419  * mmap code below
       
   420  */
       
   421 
       
   422 #ifdef HAVE_MMAP
       
   423 
       
   424 /* GstMmapBuffer */
       
   425 
       
   426 typedef struct _GstMmapBuffer GstMmapBuffer;
       
   427 typedef struct _GstMmapBufferClass GstMmapBufferClass;
       
   428 
       
   429 #define GST_TYPE_MMAP_BUFFER                         (gst_mmap_buffer_get_type())
       
   430 
       
   431 #define GST_IS_MMAP_BUFFER(obj)  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MMAP_BUFFER))
       
   432 #define GST_IS_MMAP_BUFFER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MMAP_BUFFER))
       
   433 #define GST_MMAP_BUFFER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MMAP_BUFFER, GstMmapBufferClass))
       
   434 #define GST_MMAP_BUFFER(obj)     (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MMAP_BUFFER, GstMmapBuffer))
       
   435 #define GST_MMAP_BUFFER_CLASS(klass)  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MMAP_BUFFER, GstMmapBufferClass))
       
   436 
       
   437 
       
   438 
       
   439 struct _GstMmapBuffer
       
   440 {
       
   441   GstBuffer buffer;
       
   442 
       
   443   GstFileSrc *filesrc;
       
   444 };
       
   445 
       
   446 struct _GstMmapBufferClass
       
   447 {
       
   448   GstBufferClass buffer_class;
       
   449 };
       
   450 
       
   451 static void gst_mmap_buffer_init (GTypeInstance * instance, gpointer g_class);
       
   452 static void gst_mmap_buffer_class_init (gpointer g_class, gpointer class_data);
       
   453 static void gst_mmap_buffer_finalize (GstMmapBuffer * mmap_buffer);
       
   454 static GstBufferClass *mmap_buffer_parent_class = NULL;
       
   455 
       
   456 static GType
       
   457 gst_mmap_buffer_get_type (void)
       
   458 {
       
   459   static GType _gst_mmap_buffer_type;
       
   460 
       
   461   if (G_UNLIKELY (_gst_mmap_buffer_type == 0)) {
       
   462     static const GTypeInfo mmap_buffer_info = {
       
   463       sizeof (GstMmapBufferClass),
       
   464       NULL,
       
   465       NULL,
       
   466       gst_mmap_buffer_class_init,
       
   467       NULL,
       
   468       NULL,
       
   469       sizeof (GstMmapBuffer),
       
   470       0,
       
   471       gst_mmap_buffer_init,
       
   472       NULL
       
   473     };
       
   474 
       
   475     _gst_mmap_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
       
   476         "GstMmapBuffer", &mmap_buffer_info, 0);
       
   477   }
       
   478   return _gst_mmap_buffer_type;
       
   479 }
       
   480 
       
   481 static void
       
   482 gst_mmap_buffer_class_init (gpointer g_class, gpointer class_data)
       
   483 {
       
   484   GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
       
   485 
       
   486   mmap_buffer_parent_class = g_type_class_peek_parent (g_class);
       
   487 
       
   488   mini_object_class->finalize =
       
   489       (GstMiniObjectFinalizeFunction) gst_mmap_buffer_finalize;
       
   490 }
       
   491 
       
   492 static void
       
   493 gst_mmap_buffer_init (GTypeInstance * instance, gpointer g_class)
       
   494 {
       
   495   GstBuffer *buf = (GstBuffer *) instance;
       
   496 
       
   497   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY);
       
   498   /* before we re-enable this flag, we probably need to fix _copy()
       
   499    * _make_writable(), etc. in GstMiniObject/GstBuffer as well */
       
   500   /* GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_ORIGINAL); */
       
   501 }
       
   502 
       
   503 static void
       
   504 gst_mmap_buffer_finalize (GstMmapBuffer * mmap_buffer)
       
   505 {
       
   506   guint size;
       
   507   gpointer data;
       
   508   guint64 offset;
       
   509   GstFileSrc *src;
       
   510   GstBuffer *buffer = GST_BUFFER (mmap_buffer);
       
   511 
       
   512   /* get info */
       
   513   size = GST_BUFFER_SIZE (buffer);
       
   514   offset = GST_BUFFER_OFFSET (buffer);
       
   515   data = GST_BUFFER_DATA (buffer);
       
   516   src = mmap_buffer->filesrc;
       
   517 
       
   518   GST_LOG ("freeing mmap()d buffer at %" G_GUINT64_FORMAT "+%u", offset, size);
       
   519 
       
   520 #ifdef MADV_DONTNEED
       
   521   /* madvise to tell the kernel what to do with it */
       
   522   if (madvise (data, size, MADV_DONTNEED) < 0) {
       
   523     GST_WARNING_OBJECT (src, "warning: madvise failed: %s", g_strerror (errno));
       
   524   }
       
   525 #endif
       
   526 
       
   527   /* now unmap the memory */
       
   528   if (munmap (data, size) < 0) {
       
   529     GST_WARNING_OBJECT (src, "warning: munmap failed: %s", g_strerror (errno));
       
   530   }
       
   531 
       
   532   /* cast to unsigned long, since there's no gportable way to print
       
   533    * guint64 as hex */
       
   534   GST_LOG ("unmapped region %08lx+%08lx at %p",
       
   535       (gulong) offset, (gulong) size, data);
       
   536 
       
   537   GST_MINI_OBJECT_CLASS (mmap_buffer_parent_class)->
       
   538       finalize (GST_MINI_OBJECT (mmap_buffer));
       
   539 }
       
   540 
       
   541 static GstBuffer *
       
   542 gst_file_src_map_region (GstFileSrc * src, off_t offset, gsize size,
       
   543     gboolean testonly)
       
   544 {
       
   545   GstBuffer *buf;
       
   546   void *mmapregion;
       
   547 
       
   548   g_return_val_if_fail (offset >= 0, NULL);
       
   549 
       
   550   GST_LOG_OBJECT (src, "mapping region %08llx+%08lx from file into memory",
       
   551       offset, (gulong) size);
       
   552 
       
   553   mmapregion = mmap (NULL, size, PROT_READ, MAP_SHARED, src->fd, offset);
       
   554 
       
   555   if (mmapregion == NULL || mmapregion == MAP_FAILED)
       
   556     goto mmap_failed;
       
   557 
       
   558   GST_LOG_OBJECT (src, "mapped region %08lx+%08lx from file into memory at %p",
       
   559       (gulong) offset, (gulong) size, mmapregion);
       
   560 
       
   561   /* time to allocate a new mapbuf */
       
   562   buf = (GstBuffer *) gst_mini_object_new (GST_TYPE_MMAP_BUFFER);
       
   563   /* mmap() the data into this new buffer */
       
   564   GST_BUFFER_DATA (buf) = mmapregion;
       
   565   GST_MMAP_BUFFER (buf)->filesrc = src;
       
   566 
       
   567 #ifdef MADV_SEQUENTIAL
       
   568   if (src->sequential) {
       
   569     /* madvise to tell the kernel what to do with it */
       
   570   #ifndef __SYMBIAN32__
       
   571     if (madvise (mmapregion, size, MADV_SEQUENTIAL) < 0) {
       
   572       GST_WARNING_OBJECT (src, "warning: madvise failed: %s",
       
   573           g_strerror (errno));
       
   574     }
       
   575   #endif
       
   576 #endif
       
   577 
       
   578   /* fill in the rest of the fields */
       
   579   GST_BUFFER_SIZE (buf) = size;
       
   580   GST_BUFFER_OFFSET (buf) = offset;
       
   581   GST_BUFFER_OFFSET_END (buf) = offset + size;
       
   582   GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
       
   583 
       
   584   return buf;
       
   585 
       
   586   /* ERROR */
       
   587 mmap_failed:
       
   588   {
       
   589     if (!testonly) {
       
   590       GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
       
   591           ("mmap (0x%08lx, %d, 0x%" G_GINT64_MODIFIER "x) failed: %s",
       
   592               (gulong) size, src->fd, (guint64) offset, g_strerror (errno)));
       
   593     }
       
   594     return NULL;
       
   595   }
       
   596 }
       
   597 
       
   598 static GstBuffer *
       
   599 gst_file_src_map_small_region (GstFileSrc * src, off_t offset, gsize size)
       
   600 {
       
   601   GstBuffer *ret;
       
   602   off_t mod;
       
   603   guint pagesize;
       
   604 
       
   605   GST_LOG_OBJECT (src,
       
   606       "attempting to map a small buffer at %" G_GUINT64_FORMAT "+%d",
       
   607       (guint64) offset, (gint) size);
       
   608 
       
   609   pagesize = src->pagesize;
       
   610 
       
   611   mod = offset % pagesize;
       
   612 
       
   613   /* if the offset starts at a non-page boundary, we have to special case */
       
   614   if (mod != 0) {
       
   615     gsize mapsize;
       
   616     off_t mapbase;
       
   617     GstBuffer *map;
       
   618 
       
   619     mapbase = offset - mod;
       
   620     mapsize = ((size + mod + pagesize - 1) / pagesize) * pagesize;
       
   621 
       
   622     GST_LOG_OBJECT (src,
       
   623         "not on page boundaries, resizing to map to %" G_GUINT64_FORMAT "+%d",
       
   624         (guint64) mapbase, (gint) mapsize);
       
   625 
       
   626     map = gst_file_src_map_region (src, mapbase, mapsize, FALSE);
       
   627     if (map == NULL)
       
   628       return NULL;
       
   629 
       
   630     ret = gst_buffer_create_sub (map, offset - mapbase, size);
       
   631     GST_BUFFER_OFFSET (ret) = GST_BUFFER_OFFSET (map) + offset - mapbase;
       
   632 
       
   633     gst_buffer_unref (map);
       
   634   } else {
       
   635     ret = gst_file_src_map_region (src, offset, size, FALSE);
       
   636   }
       
   637 
       
   638   return ret;
       
   639 }
       
   640 
       
   641 static GstFlowReturn
       
   642 gst_file_src_create_mmap (GstFileSrc * src, guint64 offset, guint length,
       
   643     GstBuffer ** buffer)
       
   644 {
       
   645   GstBuffer *buf = NULL;
       
   646   gsize readsize, mapsize;
       
   647   off_t readend, mapstart, mapend;
       
   648   int i;
       
   649 
       
   650   /* calculate end pointers so we don't have to do so repeatedly later */
       
   651   readsize = length;
       
   652   readend = offset + readsize;  /* note this is the byte *after* the read */
       
   653 
       
   654   mapstart = GST_BUFFER_OFFSET (src->mapbuf);
       
   655   mapsize = GST_BUFFER_SIZE (src->mapbuf);
       
   656   mapend = mapstart + mapsize;  /* note this is the byte *after* the map */
       
   657 
       
   658   GST_LOG ("attempting to read %08lx, %08lx, %08lx, %08lx",
       
   659       (unsigned long) readsize, (unsigned long) readend,
       
   660       (unsigned long) mapstart, (unsigned long) mapend);
       
   661 
       
   662   /* if the start is past the mapstart */
       
   663   if (offset >= mapstart) {
       
   664     /* if the end is before the mapend, the buffer is in current mmap region... */
       
   665     /* ('cause by definition if readend is in the buffer, so's readstart) */
       
   666     if (readend <= mapend) {
       
   667       GST_LOG_OBJECT (src, "read buf %" G_GUINT64_FORMAT "+%u lives in "
       
   668           "current mapbuf %u+%u, creating subbuffer of mapbuf",
       
   669           offset, (guint) readsize, (guint) mapstart, (guint) mapsize);
       
   670       buf = gst_buffer_create_sub (src->mapbuf, offset - mapstart, readsize);
       
   671       GST_BUFFER_OFFSET (buf) = offset;
       
   672 
       
   673       /* if the start actually is within the current mmap region, map an overlap buffer */
       
   674     } else if (offset < mapend) {
       
   675       GST_LOG_OBJECT (src, "read buf %" G_GUINT64_FORMAT "+%u starts in "
       
   676           "mapbuf %u+%u but ends outside, creating new mmap",
       
   677           offset, (guint) readsize, (guint) mapstart, (guint) mapsize);
       
   678       buf = gst_file_src_map_small_region (src, offset, readsize);
       
   679       if (buf == NULL)
       
   680         goto could_not_mmap;
       
   681     }
       
   682 
       
   683     /* the only other option is that buffer is totally outside, which means we search for it */
       
   684 
       
   685     /* now we can assume that the start is *before* the current mmap region */
       
   686     /* if the readend is past mapstart, we have two options */
       
   687   } else if (readend >= mapstart) {
       
   688     /* either the read buffer overlaps the start of the mmap region */
       
   689     /* or the read buffer fully contains the current mmap region    */
       
   690     /* either way, it's really not relevant, we just create a new region anyway */
       
   691     GST_LOG_OBJECT (src, "read buf %" G_GUINT64_FORMAT "+%d starts before "
       
   692         "mapbuf %d+%d, but overlaps it", (guint64) offset, (gint) readsize,
       
   693         (gint) mapstart, (gint) mapsize);
       
   694     buf = gst_file_src_map_small_region (src, offset, readsize);
       
   695     if (buf == NULL)
       
   696       goto could_not_mmap;
       
   697   }
       
   698 
       
   699   /* then deal with the case where the read buffer is totally outside */
       
   700   if (buf == NULL) {
       
   701     /* first check to see if there's a map that covers the right region already */
       
   702     GST_LOG_OBJECT (src, "searching for mapbuf to cover %" G_GUINT64_FORMAT
       
   703         "+%d", offset, (int) readsize);
       
   704 
       
   705     /* if the read buffer crosses a mmap region boundary, create a one-off region */
       
   706     if ((offset / src->mapsize) != (readend / src->mapsize)) {
       
   707       GST_LOG_OBJECT (src, "read buf %" G_GUINT64_FORMAT "+%d crosses a "
       
   708           "%d-byte boundary, creating a one-off", offset, (int) readsize,
       
   709           (int) src->mapsize);
       
   710       buf = gst_file_src_map_small_region (src, offset, readsize);
       
   711       if (buf == NULL)
       
   712         goto could_not_mmap;
       
   713 
       
   714       /* otherwise we will create a new mmap region and set it to the default */
       
   715     } else {
       
   716       gsize mapsize;
       
   717 
       
   718       off_t nextmap = offset - (offset % src->mapsize);
       
   719 
       
   720       GST_LOG_OBJECT (src, "read buf %" G_GUINT64_FORMAT "+%d in new mapbuf "
       
   721           "at %" G_GUINT64_FORMAT "+%d, mapping and subbuffering",
       
   722           offset, (gint) readsize, (guint64) nextmap, (gint) src->mapsize);
       
   723       /* first, we're done with the old mapbuf */
       
   724       gst_buffer_unref (src->mapbuf);
       
   725       mapsize = src->mapsize;
       
   726 
       
   727       /* double the mapsize as long as the readsize is smaller */
       
   728       while (readsize + offset > nextmap + mapsize) {
       
   729         GST_LOG_OBJECT (src, "readsize smaller then mapsize %08x %d",
       
   730             (guint) readsize, (gint) mapsize);
       
   731         mapsize <<= 1;
       
   732       }
       
   733       /* create a new one */
       
   734       src->mapbuf = gst_file_src_map_region (src, nextmap, mapsize, FALSE);
       
   735       if (src->mapbuf == NULL)
       
   736         goto could_not_mmap;
       
   737 
       
   738       /* subbuffer it */
       
   739       buf = gst_buffer_create_sub (src->mapbuf, offset - nextmap, readsize);
       
   740       GST_BUFFER_OFFSET (buf) =
       
   741           GST_BUFFER_OFFSET (src->mapbuf) + offset - nextmap;
       
   742     }
       
   743   }
       
   744 
       
   745   /* if we need to touch the buffer (to bring it into memory), do so */
       
   746   if (src->touch) {
       
   747     volatile guchar *p = GST_BUFFER_DATA (buf), c;
       
   748 
       
   749     /* read first byte of each page */
       
   750     for (i = 0; i < GST_BUFFER_SIZE (buf); i += src->pagesize)
       
   751       c = p[i];
       
   752   }
       
   753 
       
   754   /* we're done, return the buffer */
       
   755   *buffer = buf;
       
   756 
       
   757   return GST_FLOW_OK;
       
   758 
       
   759   /* ERROR */
       
   760 could_not_mmap:
       
   761   {
       
   762     return GST_FLOW_ERROR;
       
   763   }
       
   764 }
       
   765 #endif
       
   766 
       
   767 /***
       
   768  * read code below
       
   769  * that is to say, you shouldn't read the code below, but the code that reads
       
   770  * stuff is below.  Well, you shouldn't not read the code below, feel free
       
   771  * to read it of course.  It's just that "read code below" is a pretty crappy
       
   772  * documentation string because it sounds like we're expecting you to read
       
   773  * the code to understand what it does, which, while true, is really not
       
   774  * the sort of attitude we want to be advertising.  No sir.
       
   775  *
       
   776  */
       
   777 
       
   778 static GstFlowReturn
       
   779 gst_file_src_create_read (GstFileSrc * src, guint64 offset, guint length,
       
   780     GstBuffer ** buffer)
       
   781 {
       
   782   int ret;
       
   783   GstBuffer *buf;
       
   784 
       
   785   if (G_UNLIKELY (src->read_position != offset)) {
       
   786     off_t res;
       
   787 
       
   788     res = lseek (src->fd, offset, SEEK_SET);
       
   789     if (G_UNLIKELY (res < 0 || res != offset))
       
   790       goto seek_failed;
       
   791 
       
   792     src->read_position = offset;
       
   793   }
       
   794 
       
   795   buf = gst_buffer_new_and_alloc (length);
       
   796 
       
   797   GST_LOG_OBJECT (src, "Reading %d bytes", length);
       
   798   ret = read (src->fd, GST_BUFFER_DATA (buf), length);
       
   799   if (G_UNLIKELY (ret < 0))
       
   800     goto could_not_read;
       
   801 
       
   802   /* seekable regular files should have given us what we expected */
       
   803   if (G_UNLIKELY ((guint) ret < length && src->seekable))
       
   804     goto unexpected_eos;
       
   805 
       
   806   /* other files should eos if they read 0 and more was requested */
       
   807   if (G_UNLIKELY (ret == 0 && length > 0))
       
   808     goto eos;
       
   809 
       
   810   length = ret;
       
   811 
       
   812   GST_BUFFER_SIZE (buf) = length;
       
   813   GST_BUFFER_OFFSET (buf) = offset;
       
   814   GST_BUFFER_OFFSET_END (buf) = offset + length;
       
   815 
       
   816   *buffer = buf;
       
   817 
       
   818   src->read_position += length;
       
   819 
       
   820   return GST_FLOW_OK;
       
   821 
       
   822   /* ERROR */
       
   823 seek_failed:
       
   824   {
       
   825     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
       
   826     return GST_FLOW_ERROR;
       
   827   }
       
   828 could_not_read:
       
   829   {
       
   830     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
       
   831     gst_buffer_unref (buf);
       
   832     return GST_FLOW_ERROR;
       
   833   }
       
   834 unexpected_eos:
       
   835   {
       
   836     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
       
   837         ("unexpected end of file."));
       
   838     gst_buffer_unref (buf);
       
   839     return GST_FLOW_ERROR;
       
   840   }
       
   841 eos:
       
   842   {
       
   843     GST_DEBUG ("non-regular file hits EOS");
       
   844     gst_buffer_unref (buf);
       
   845     return GST_FLOW_UNEXPECTED;
       
   846   }
       
   847 }
       
   848 
       
   849 static GstFlowReturn
       
   850 gst_file_src_create (GstBaseSrc * basesrc, guint64 offset, guint length,
       
   851     GstBuffer ** buffer)
       
   852 {
       
   853   GstFileSrc *src;
       
   854   GstFlowReturn ret;
       
   855 
       
   856   src = GST_FILE_SRC (basesrc);
       
   857 
       
   858 #ifdef HAVE_MMAP
       
   859   if (src->using_mmap) {
       
   860     ret = gst_file_src_create_mmap (src, offset, length, buffer);
       
   861   } else {
       
   862     ret = gst_file_src_create_read (src, offset, length, buffer);
       
   863   }
       
   864 #else
       
   865   ret = gst_file_src_create_read (src, offset, length, buffer);
       
   866 #endif
       
   867 
       
   868   return ret;
       
   869 }
       
   870 
       
   871 static gboolean
       
   872 gst_file_src_is_seekable (GstBaseSrc * basesrc)
       
   873 {
       
   874   GstFileSrc *src = GST_FILE_SRC (basesrc);
       
   875 
       
   876   return src->seekable;
       
   877 }
       
   878 
       
   879 static gboolean
       
   880 gst_file_src_get_size (GstBaseSrc * basesrc, guint64 * size)
       
   881 {
       
   882   struct stat stat_results;
       
   883   GstFileSrc *src;
       
   884 
       
   885   src = GST_FILE_SRC (basesrc);
       
   886 
       
   887   if (!src->seekable) {
       
   888     /* If it isn't seekable, we won't know the length (but fstat will still
       
   889      * succeed, and wrongly say our length is zero. */
       
   890     return FALSE;
       
   891   }
       
   892 
       
   893   if (fstat (src->fd, &stat_results) < 0)
       
   894     goto could_not_stat;
       
   895 
       
   896   *size = stat_results.st_size;
       
   897 
       
   898   return TRUE;
       
   899 
       
   900   /* ERROR */
       
   901 could_not_stat:
       
   902   {
       
   903     return FALSE;
       
   904   }
       
   905 }
       
   906 
       
   907 /* open the file and mmap it, necessary to go to READY state */
       
   908 static gboolean
       
   909 gst_file_src_start (GstBaseSrc * basesrc)
       
   910 {
       
   911   GstFileSrc *src = GST_FILE_SRC (basesrc);
       
   912   struct stat stat_results;
       
   913 
       
   914   if (src->filename == NULL || src->filename[0] == '\0')
       
   915     goto no_filename;
       
   916 
       
   917   GST_INFO_OBJECT (src, "opening file %s", src->filename);
       
   918 
       
   919   /* open the file */
       
   920   src->fd = open (src->filename, O_RDONLY | O_BINARY);
       
   921   if (src->fd < 0)
       
   922     goto open_failed;
       
   923 
       
   924   /* check if it is a regular file, otherwise bail out */
       
   925   if (fstat (src->fd, &stat_results) < 0)
       
   926     goto no_stat;
       
   927 
       
   928   if (S_ISDIR (stat_results.st_mode))
       
   929     goto was_directory;
       
   930 
       
   931   if (S_ISSOCK (stat_results.st_mode))
       
   932     goto was_socket;
       
   933 
       
   934   src->using_mmap = FALSE;
       
   935   src->read_position = 0;
       
   936 
       
   937   /* record if it's a regular (hence seekable and lengthable) file */
       
   938   if (S_ISREG (stat_results.st_mode))
       
   939     src->is_regular = TRUE;
       
   940 
       
   941 #ifdef HAVE_MMAP
       
   942   if (src->use_mmap) {
       
   943     /* FIXME: maybe we should only try to mmap if it's a regular file */
       
   944     /* allocate the first mmap'd region if it's a regular file ? */
       
   945     src->mapbuf = gst_file_src_map_region (src, 0, src->mapsize, TRUE);
       
   946     if (src->mapbuf != NULL) {
       
   947       GST_DEBUG_OBJECT (src, "using mmap for file");
       
   948       src->using_mmap = TRUE;
       
   949       src->seekable = TRUE;
       
   950     }
       
   951   }
       
   952   if (src->mapbuf == NULL)
       
   953 #endif
       
   954   {
       
   955     /* If not in mmap mode, we need to check if the underlying file is
       
   956      * seekable. */
       
   957     off_t res = lseek (src->fd, 0, SEEK_END);
       
   958 
       
   959     if (res < 0) {
       
   960       GST_LOG_OBJECT (src, "disabling seeking, not in mmap mode and lseek "
       
   961           "failed: %s", g_strerror (errno));
       
   962       src->seekable = FALSE;
       
   963     } else {
       
   964       src->seekable = TRUE;
       
   965     }
       
   966     lseek (src->fd, 0, SEEK_SET);
       
   967   }
       
   968 
       
   969   /* We can only really do seeking on regular files - for other file types, we
       
   970    * don't know their length, so seeking isn't useful/meaningful */
       
   971   src->seekable = src->seekable && src->is_regular;
       
   972 
       
   973   return TRUE;
       
   974 
       
   975   /* ERROR */
       
   976 no_filename:
       
   977   {
       
   978     GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
       
   979         (_("No file name specified for reading.")), (NULL));
       
   980     return FALSE;
       
   981   }
       
   982 open_failed:
       
   983   {
       
   984     switch (errno) {
       
   985       case ENOENT:
       
   986         GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
       
   987             ("No such file \"%s\"", src->filename));
       
   988         break;
       
   989       default:
       
   990         GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
       
   991             (_("Could not open file \"%s\" for reading."), src->filename),
       
   992             GST_ERROR_SYSTEM);
       
   993         break;
       
   994     }
       
   995     return FALSE;
       
   996   }
       
   997 no_stat:
       
   998   {
       
   999     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
       
  1000         (_("Could not get info on \"%s\"."), src->filename), (NULL));
       
  1001     close (src->fd);
       
  1002     return FALSE;
       
  1003   }
       
  1004 was_directory:
       
  1005   {
       
  1006     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
       
  1007         (_("\"%s\" is a directory."), src->filename), (NULL));
       
  1008     close (src->fd);
       
  1009     return FALSE;
       
  1010   }
       
  1011 was_socket:
       
  1012   {
       
  1013     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
       
  1014         (_("File \"%s\" is a socket."), src->filename), (NULL));
       
  1015     close (src->fd);
       
  1016     return FALSE;
       
  1017   }
       
  1018 }
       
  1019 
       
  1020 /* unmap and close the file */
       
  1021 static gboolean
       
  1022 gst_file_src_stop (GstBaseSrc * basesrc)
       
  1023 {
       
  1024   GstFileSrc *src = GST_FILE_SRC (basesrc);
       
  1025 
       
  1026   /* close the file */
       
  1027   close (src->fd);
       
  1028 
       
  1029   /* zero out a lot of our state */
       
  1030   src->fd = 0;
       
  1031   src->is_regular = FALSE;
       
  1032 
       
  1033   if (src->mapbuf) {
       
  1034     gst_buffer_unref (src->mapbuf);
       
  1035     src->mapbuf = NULL;
       
  1036   }
       
  1037 
       
  1038   return TRUE;
       
  1039 }
       
  1040 
       
  1041 /*** GSTURIHANDLER INTERFACE *************************************************/
       
  1042 #ifdef __SYMBIAN32__
       
  1043 GstURIType
       
  1044 #else
       
  1045 static guint
       
  1046 #endif 
       
  1047 gst_file_src_uri_get_type (void)
       
  1048 {
       
  1049   return GST_URI_SRC;
       
  1050 }
       
  1051 static gchar **
       
  1052 gst_file_src_uri_get_protocols (void)
       
  1053 {
       
  1054   static gchar *protocols[] = { "file", NULL };
       
  1055 
       
  1056   return protocols;
       
  1057 }
       
  1058 static const gchar *
       
  1059 gst_file_src_uri_get_uri (GstURIHandler * handler)
       
  1060 {
       
  1061   GstFileSrc *src = GST_FILE_SRC (handler);
       
  1062 
       
  1063   return src->uri;
       
  1064 }
       
  1065 
       
  1066 static gboolean
       
  1067 gst_file_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
       
  1068 {
       
  1069   gchar *protocol, *location;
       
  1070   gboolean ret;
       
  1071   GstFileSrc *src = GST_FILE_SRC (handler);
       
  1072 
       
  1073   protocol = gst_uri_get_protocol (uri);
       
  1074   if (strcmp (protocol, "file") != 0) {
       
  1075     g_free (protocol);
       
  1076     return FALSE;
       
  1077   }
       
  1078   g_free (protocol);
       
  1079 
       
  1080   /* allow file://localhost/foo/bar by stripping localhost but fail
       
  1081    * for every other hostname */
       
  1082   if (g_str_has_prefix (uri, "file://localhost/")) {
       
  1083     char *tmp;
       
  1084 
       
  1085     /* 16 == strlen ("file://localhost") */
       
  1086     tmp = g_strconcat ("file://", uri + 16, NULL);
       
  1087     /* we use gst_uri_get_location() although we already have the
       
  1088      * "location" with uri + 16 because it provides unescaping */
       
  1089     location = gst_uri_get_location (tmp);
       
  1090     g_free (tmp);
       
  1091   } else if (strcmp (uri, "file://") == 0) {
       
  1092     /* Special case for "file://" as this is used by some applications
       
  1093      *  to test with gst_element_make_from_uri if there's an element
       
  1094      *  that supports the URI protocol. */
       
  1095     gst_file_src_set_location (src, NULL);
       
  1096     return TRUE;
       
  1097   } else {
       
  1098     location = gst_uri_get_location (uri);
       
  1099   }
       
  1100 
       
  1101   if (!location)
       
  1102     return FALSE;
       
  1103   if (!g_path_is_absolute (location)) {
       
  1104     g_free (location);
       
  1105     return FALSE;
       
  1106   }
       
  1107 
       
  1108   ret = gst_file_src_set_location (src, location);
       
  1109   g_free (location);
       
  1110 
       
  1111   return ret;
       
  1112 }
       
  1113 
       
  1114 static void
       
  1115 gst_file_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
       
  1116 {
       
  1117   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
       
  1118 
       
  1119   iface->get_type = gst_file_src_uri_get_type;
       
  1120   iface->get_protocols = gst_file_src_uri_get_protocols;
       
  1121   iface->get_uri = gst_file_src_uri_get_uri;
       
  1122   iface->set_uri = gst_file_src_uri_set_uri;
       
  1123 }