4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Seungbae Shin <seungbae.shin@samsung.com>
8 * This library is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU Lesser General Public License as published by the
10 * Free Software Foundation; either version 2.1 of the License, or (at your option)
13 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
14 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 * License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, write to the Free Software Foundation, Inc., 51
20 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30 #include "gstpdpushsrc.h"
33 #include <sys/types.h>
35 #include <io.h> /* lseek, open, close, read */
36 /* On win32, stat* default to 32 bit; we need the 64-bit
37 * variants, so explicitly define it that way. */
39 #define fstat _fstat64
41 #define lseek _lseeki64
44 /* Prevent stat.h from defining the stat* functions as
45 * _stat*, since we're explicitly overriding that */
58 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
63 /* FIXME we should be using glib for this */
65 #define S_ISREG(mode) ((mode)&_S_IFREG)
68 #define S_ISDIR(mode) ((mode)&_S_IFDIR)
71 #define S_ISSOCK(x) (0)
78 file_open (const gchar * filename, int flags, int mode)
80 return open (filename, flags, mode);
83 GST_DEBUG_CATEGORY_STATIC (gst_pd_pushsrc_debug);
84 #define GST_CAT_DEFAULT gst_pd_pushsrc_debug
86 /* FileSrc signals and args */
93 #define DEFAULT_BLOCKSIZE 4*1024
102 static void gst_pd_pushsrc_finalize (GObject * object);
104 static void gst_pd_pushsrc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec);
105 static void gst_pd_pushsrc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec);
107 static gboolean gst_pd_pushsrc_start (GstBaseSrc * basesrc);
108 static gboolean gst_pd_pushsrc_stop (GstBaseSrc * basesrc);
110 static gboolean gst_pd_pushsrc_is_seekable (GstBaseSrc * src);
111 static gboolean gst_pd_pushsrc_get_size (GstBaseSrc * src, guint64 * size);
112 static gboolean gst_pd_pushsrc_query (GstBaseSrc * src, GstQuery * query);
113 static void gst_pd_pushsrc_uri_handler_init (gpointer g_iface, gpointer iface_data);
114 static GstFlowReturn gst_pd_pushsrc_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer);
115 static gboolean gst_pd_pushsrc_checkgetrange (GstPad * pad);
118 _do_init (GType pd_pushsrc_type)
120 static const GInterfaceInfo urihandler_info = {
121 gst_pd_pushsrc_uri_handler_init,
126 g_type_add_interface_static (pd_pushsrc_type, GST_TYPE_URI_HANDLER, &urihandler_info);
127 GST_DEBUG_CATEGORY_INIT (gst_pd_pushsrc_debug, "pdpushsrc", 0, "PD push source element");
130 GST_BOILERPLATE_FULL (GstPDPushSrc, gst_pd_pushsrc, GstBaseSrc, GST_TYPE_BASE_SRC, _do_init);
133 gst_pd_pushsrc_base_init (gpointer g_class)
137 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
139 gst_element_class_set_details_simple (gstelement_class,
142 "Read from arbitrary point in a file",
143 "Naveen Ch <naveen.ch@samsung.com>");
144 gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&srctemplate));
150 gst_pd_pushsrc_class_init (GstPDPushSrcClass * klass)
154 GObjectClass *gobject_class;
155 GstBaseSrcClass *gstbasesrc_class;
157 gobject_class = G_OBJECT_CLASS (klass);
158 gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
160 gobject_class->set_property = gst_pd_pushsrc_set_property;
161 gobject_class->get_property = gst_pd_pushsrc_get_property;
162 gobject_class->finalize = gst_pd_pushsrc_finalize;
164 g_object_class_install_property (gobject_class, ARG_LOCATION,
165 g_param_spec_string ("location", "File Location",
166 "Location of the file to read", NULL,
167 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
168 GST_PARAM_MUTABLE_READY));
170 g_object_class_install_property (gobject_class, ARG_EOS,
171 g_param_spec_boolean ("eos",
172 "EOS recived on downloading pipeline",
173 "download of clip is over",
177 gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_start);
178 gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_stop);
179 gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_is_seekable);
180 gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_get_size);
181 gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_query);
182 gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_create);
184 if (sizeof (off_t) < 8) {
185 GST_LOG ("No large file support, sizeof (off_t) = %" G_GSIZE_FORMAT "!",
194 gst_pd_pushsrc_init (GstPDPushSrc * src, GstPDPushSrcClass * g_class)
197 GstBaseSrc *basesrc = GST_BASE_SRC (src);
199 src->filename = NULL;
202 src->is_regular = FALSE;
205 gst_pad_set_checkgetrange_function (basesrc->srcpad, GST_DEBUG_FUNCPTR (gst_pd_pushsrc_checkgetrange));
211 gst_pd_pushsrc_finalize (GObject * object)
217 src = GST_PD_PUSHSRC (object);
219 g_free (src->filename);
222 G_OBJECT_CLASS (parent_class)->finalize (object);
228 gst_pd_pushsrc_set_location (GstPDPushSrc * src, const gchar * location)
234 /* the element must be stopped in order to do this */
235 GST_OBJECT_LOCK (src);
236 state = GST_STATE (src);
237 if (state != GST_STATE_READY && state != GST_STATE_NULL)
239 GST_OBJECT_UNLOCK (src);
241 g_free (src->filename);
244 /* clear the filename if we get a NULL (is that possible?) */
245 if (location == NULL) {
246 src->filename = NULL;
249 /* we store the filename as received by the application. On Windows this
251 src->filename = g_strdup (location);
252 src->uri = gst_filename_to_uri (location, NULL);
253 GST_INFO ("filename : %s", src->filename);
254 GST_INFO ("uri : %s", src->uri);
256 g_object_notify (G_OBJECT (src), "location");
257 gst_uri_handler_new_uri (GST_URI_HANDLER (src), src->uri);
266 g_warning ("Changing the `location' property on filesrc when a file is "
267 "open is not supported.");
268 GST_OBJECT_UNLOCK (src);
269 GST_LOG ("OUT :: wrong_state");
275 gst_pd_pushsrc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
281 g_return_if_fail (GST_IS_PD_PUSHSRC (object));
283 src = GST_PD_PUSHSRC (object);
287 gst_pd_pushsrc_set_location (src, g_value_get_string (value));
290 src->is_eos = g_value_get_boolean (value);
291 g_print ("\n\n\nis_eos is becoming %d\n\n\n", src->is_eos);
294 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
301 gst_pd_pushsrc_get_property (GObject * object, guint prop_id, GValue * value,
307 g_return_if_fail (GST_IS_PD_PUSHSRC (object));
309 src = GST_PD_PUSHSRC (object);
313 g_value_set_string (value, src->filename);
316 g_value_set_boolean (value, src->is_eos);
319 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
326 gst_pd_pushsrc_create_read (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer)
331 GstBuffer *buf = NULL;
332 struct stat stat_results;
336 return GST_FLOW_ERROR;
338 src = GST_PD_PUSHSRC_CAST (basesrc);
340 GST_LOG_OBJECT (src, "read position = %"G_GUINT64_FORMAT ", offset = %"G_GUINT64_FORMAT", length = %d",
341 src->read_position, offset, length);
343 memset (&stat_results, 0, sizeof (stat_results));
345 if (fstat (src->fd, &stat_results) < 0)
348 GST_LOG_OBJECT (src, "offset + length = %"G_GUINT64_FORMAT " and filesize = %"G_GUINT64_FORMAT, offset + length, stat_results.st_size);
350 while ((offset + length) > stat_results.st_size)
354 struct timeval timeout = {0,};
355 guint64 avail_size = 0;
361 FD_SET (src->fd, &fds);
364 timeout.tv_usec = ((basesrc->blocksize * 8 * 1000) / 64000); // wait_time = (blocksize * 8) / (min downloadratei.e. 64Kbps)
366 GST_DEBUG_OBJECT (src, "Going to wait for %ld msec", timeout.tv_usec);
368 ret = select (src->fd + 1, &fds, NULL, NULL, &timeout);
371 GST_ERROR_OBJECT (src, "ERROR in select () : reason - %s...\n", strerror(errno));
372 return GST_FLOW_ERROR;
376 GST_WARNING_OBJECT (src, "select () timeout happened...");
380 memset (&stat_results, 0, sizeof (stat_results));
382 if (fstat (src->fd, &stat_results) < 0)
385 avail_size = stat_results.st_size;
387 GST_LOG_OBJECT (src, "Available data size in file = %"G_GUINT64_FORMAT, avail_size);
389 if ((offset + length) > avail_size)
391 GST_LOG_OBJECT (src, "Enough data is NOT available...");
395 GST_LOG_OBJECT (src, "Enough data is available...");
400 if (G_UNLIKELY (src->read_position != offset)) {
403 res = lseek (src->fd, offset, SEEK_SET);
404 if (G_UNLIKELY (res < 0 || res != offset))
406 src->read_position = offset;
409 buf = gst_buffer_try_new_and_alloc (length);
410 if (G_UNLIKELY (buf == NULL)) {
411 GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", length);
412 return GST_FLOW_ERROR;
415 GST_LOG_OBJECT (src, "Reading %d bytes at offset 0x%" G_GINT64_MODIFIER "x",
417 ret = read (src->fd, GST_BUFFER_DATA (buf), length);
418 if (G_UNLIKELY (ret < 0))
421 /* seekable regular files should have given us what we expected */
422 if (G_UNLIKELY ((guint) ret < length && src->seekable))
425 /* other files should eos if they read 0 and more was requested */
426 if (G_UNLIKELY (ret == 0 && length > 0))
430 GST_BUFFER_SIZE (buf) = length;
431 GST_BUFFER_OFFSET (buf) = offset;
432 GST_BUFFER_OFFSET_END (buf) = offset + length;
434 src->read_position += length;
444 GST_ERROR_OBJECT (src, "Seek failed...");
445 GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
446 return GST_FLOW_ERROR;
450 GST_ERROR_OBJECT (src, "Could not stat");
451 GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
452 return GST_FLOW_ERROR;
456 GST_ERROR_OBJECT (src, "Could not read...");
457 GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
458 gst_buffer_unref (buf);
459 return GST_FLOW_ERROR;
463 GST_ERROR_OBJECT (src, "Unexpected EOS occured...");
464 GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), ("unexpected end of file."));
465 gst_buffer_unref (buf);
466 return GST_FLOW_ERROR;
470 GST_ERROR_OBJECT (src, "non-regular file hits EOS");
472 gst_buffer_unref (buf);
473 return GST_FLOW_UNEXPECTED;
478 gst_pd_pushsrc_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer)
485 pdsrc = GST_PD_PUSHSRC_CAST (basesrc);
486 ret = gst_pd_pushsrc_create_read (basesrc, offset, length, buffer);
493 gst_pd_pushsrc_query (GstBaseSrc * basesrc, GstQuery * query)
497 gboolean ret = FALSE;
498 GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
500 switch (GST_QUERY_TYPE (query)) {
502 gst_query_set_uri (query, src->uri);
511 ret = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
518 gst_pd_pushsrc_checkgetrange (GstPad * pad)
528 gst_pd_pushsrc_is_seekable (GstBaseSrc * basesrc)
532 GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
534 GST_DEBUG_OBJECT (src, "seekable = %d", src->seekable);
537 return src->seekable;
542 gst_pd_pushsrc_get_size (GstBaseSrc * basesrc, guint64 * size)
546 struct stat stat_results;
549 src = GST_PD_PUSHSRC (basesrc);
551 if (!src->seekable) {
552 /* If it isn't seekable, we won't know the length (but fstat will still
553 * succeed, and wrongly say our length is zero. */
557 if (fstat (src->fd, &stat_results) < 0)
560 //*size = stat_results.st_size;
561 /* Naveen : Intentionally, doing this because we dont know the file size...because its keep on increasing in PD case */
564 GST_DEBUG ("size of the file = %"G_GUINT64_FORMAT, *size);
573 GST_ERROR_OBJECT (src, "Could not stat");
578 /* open the file, necessary to go to READY state */
580 gst_pd_pushsrc_start (GstBaseSrc * basesrc)
584 GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
585 struct stat stat_results;
587 if (src->filename == NULL || src->filename[0] == '\0')
590 GST_INFO_OBJECT (src, "opening file %s", src->filename);
593 src->fd = file_open (src->filename, O_RDONLY | O_BINARY, 0);
598 /* check if it is a regular file, otherwise bail out */
599 if (fstat (src->fd, &stat_results) < 0)
602 if (S_ISDIR (stat_results.st_mode))
605 if (S_ISSOCK (stat_results.st_mode))
608 src->read_position = 0;
610 /* record if it's a regular (hence seekable and lengthable) file */
611 if (S_ISREG (stat_results.st_mode))
612 src->is_regular = TRUE;
615 /* we need to check if the underlying file is seekable. */
616 off_t res = lseek (src->fd, 0, SEEK_END);
619 GST_LOG_OBJECT (src, "disabling seeking, not in mmap mode and lseek "
620 "failed: %s", g_strerror (errno));
621 src->seekable = FALSE;
623 src->seekable = TRUE;
625 lseek (src->fd, 0, SEEK_SET);
628 /* We can only really do seeking on regular files - for other file types, we
629 * don't know their length, so seeking isn't useful/meaningful */
630 src->seekable = src->seekable && src->is_regular;
638 GST_ERROR_OBJECT (src, "No file name specified for reading...");
639 GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
640 ("No file name specified for reading."), (NULL));
647 GST_ERROR_OBJECT (src, "File could not be found");
648 GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
649 ("No such file \"\""));
652 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
653 ("Could not open file for reading."),
661 GST_ERROR_OBJECT (src, "Could not get stat info...");
662 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
663 ("Could not get info on \"\"."), (NULL));
669 GST_ERROR_OBJECT (src, "Is a Directory");
670 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
671 ("\"\" is a directory."), (NULL));
677 GST_ERROR_OBJECT (src, "Is a Socket");
678 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
679 ("File \"\" is a socket."), (NULL));
685 /* unmap and close the file */
687 gst_pd_pushsrc_stop (GstBaseSrc * basesrc)
691 GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
696 /* zero out a lot of our state */
698 src->is_regular = FALSE;
705 /*** GSTURIHANDLER INTERFACE *************************************************/
708 gst_pd_pushsrc_uri_get_type (void)
717 gst_pd_pushsrc_uri_get_protocols (void)
720 static gchar *protocols[] = { (char *) "file", NULL };
727 gst_pd_pushsrc_uri_get_uri (GstURIHandler * handler)
730 GstPDPushSrc *src = GST_PD_PUSHSRC (handler);
737 gst_pd_pushsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri)
741 gchar *location, *hostname = NULL;
742 gboolean ret = FALSE;
743 GstPDPushSrc *src = GST_PD_PUSHSRC (handler);
744 GError *error = NULL;
746 if (strcmp (uri, "file://") == 0) {
747 /* Special case for "file://" as this is used by some applications
748 * to test with gst_element_make_from_uri if there's an element
749 * that supports the URI protocol. */
750 gst_pd_pushsrc_set_location (src, NULL);
754 location = g_filename_from_uri (uri, &hostname, &error);
756 if (!location || error) {
758 GST_WARNING_OBJECT (src, "Invalid URI '%s' for filesrc: %s", uri,
760 g_error_free (error);
762 GST_WARNING_OBJECT (src, "Invalid URI '%s' for filesrc", uri);
767 if ((hostname) && (strcmp (hostname, "localhost"))) {
768 /* Only 'localhost' is permitted */
769 GST_WARNING_OBJECT (src, "Invalid hostname '%s' for filesrc", hostname);
773 /* Unfortunately, g_filename_from_uri() doesn't handle some UNC paths
774 * correctly on windows, it leaves them with an extra backslash
775 * at the start if they're of the mozilla-style file://///host/path/file
776 * form. Correct this.
778 if (location[0] == '\\' && location[1] == '\\' && location[2] == '\\')
779 g_memmove (location, location + 1, strlen (location + 1) + 1);
782 ret = gst_pd_pushsrc_set_location (src, location);
796 gst_pd_pushsrc_uri_handler_init (gpointer g_iface, gpointer iface_data)
799 GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
801 iface->get_type = gst_pd_pushsrc_uri_get_type;
802 iface->get_protocols = gst_pd_pushsrc_uri_get_protocols;
803 iface->get_uri = gst_pd_pushsrc_uri_get_uri;
804 iface->set_uri = gst_pd_pushsrc_uri_set_uri;
809 gst_pd_pushsrc_plugin_init (GstPlugin *plugin)
811 if (!gst_element_register (plugin, "pdpushsrc", GST_RANK_NONE, gst_pd_pushsrc_get_type()))
818 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
822 gst_pd_pushsrc_plugin_init,
825 "Samsung Electronics Co",
826 "http://www.samsung.com")