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;
335 src = GST_PD_PUSHSRC_CAST (basesrc);
337 GST_LOG_OBJECT (src, "read position = %"G_GUINT64_FORMAT ", offset = %"G_GUINT64_FORMAT", length = %d",
338 src->read_position, offset, length);
340 memset (&stat_results, 0, sizeof (stat_results));
342 if (fstat (src->fd, &stat_results) < 0)
345 GST_LOG_OBJECT (src, "offset + length = %"G_GUINT64_FORMAT " and filesize = %"G_GUINT64_FORMAT, offset + length, stat_results.st_size);
347 while ((offset + length) > stat_results.st_size)
351 struct timeval timeout = {0,};
352 guint64 avail_size = 0;
358 FD_SET (src->fd, &fds);
361 timeout.tv_usec = ((basesrc->blocksize * 8 * 1000) / 64000); // wait_time = (blocksize * 8) / (min downloadratei.e. 64Kbps)
363 GST_DEBUG_OBJECT (src, "Going to wait for %ld msec", timeout.tv_usec);
365 ret = select (src->fd + 1, &fds, NULL, NULL, &timeout);
368 GST_ERROR_OBJECT (src, "ERROR in select () : reason - %s...\n", strerror(errno));
369 return GST_FLOW_ERROR;
373 GST_WARNING_OBJECT (src, "select () timeout happened...");
377 memset (&stat_results, 0, sizeof (stat_results));
379 if (fstat (src->fd, &stat_results) < 0)
382 avail_size = stat_results.st_size;
384 GST_LOG_OBJECT (src, "Available data size in file = %"G_GUINT64_FORMAT, avail_size);
386 if ((offset + length) > avail_size)
388 GST_LOG_OBJECT (src, "Enough data is NOT available...");
392 GST_LOG_OBJECT (src, "Enough data is available...");
397 if (G_UNLIKELY (src->read_position != offset)) {
400 res = lseek (src->fd, offset, SEEK_SET);
401 if (G_UNLIKELY (res < 0 || res != offset))
403 src->read_position = offset;
406 buf = gst_buffer_try_new_and_alloc (length);
407 if (G_UNLIKELY (buf == NULL && length > 0)) {
408 GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", length);
409 return GST_FLOW_ERROR;
412 /* No need to read anything if length is 0 */
414 GST_LOG_OBJECT (src, "Reading %d bytes at offset 0x%" G_GINT64_MODIFIER "x",
416 ret = read (src->fd, GST_BUFFER_DATA (buf), length);
417 if (G_UNLIKELY (ret < 0))
420 /* seekable regular files should have given us what we expected */
421 if (G_UNLIKELY ((guint) ret < length && src->seekable))
424 /* other files should eos if they read 0 and more was requested */
425 if (G_UNLIKELY (ret == 0 && length > 0))
429 GST_BUFFER_SIZE (buf) = length;
430 GST_BUFFER_OFFSET (buf) = offset;
431 GST_BUFFER_OFFSET_END (buf) = offset + length;
433 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);
459 gst_buffer_unref (buf);
460 return GST_FLOW_ERROR;
464 GST_ERROR_OBJECT (src, "Unexpected EOS occured...");
465 GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), ("unexpected end of file."));
467 gst_buffer_unref (buf);
468 return GST_FLOW_ERROR;
472 GST_ERROR_OBJECT (src, "non-regular file hits EOS");
474 gst_buffer_unref (buf);
475 return GST_FLOW_UNEXPECTED;
480 gst_pd_pushsrc_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer)
487 pdsrc = GST_PD_PUSHSRC_CAST (basesrc);
488 ret = gst_pd_pushsrc_create_read (basesrc, offset, length, buffer);
495 gst_pd_pushsrc_query (GstBaseSrc * basesrc, GstQuery * query)
499 gboolean ret = FALSE;
500 GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
502 switch (GST_QUERY_TYPE (query)) {
504 gst_query_set_uri (query, src->uri);
513 ret = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
520 gst_pd_pushsrc_checkgetrange (GstPad * pad)
530 gst_pd_pushsrc_is_seekable (GstBaseSrc * basesrc)
534 GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
536 GST_DEBUG_OBJECT (src, "seekable = %d", src->seekable);
539 return src->seekable;
544 gst_pd_pushsrc_get_size (GstBaseSrc * basesrc, guint64 * size)
548 struct stat stat_results;
551 src = GST_PD_PUSHSRC (basesrc);
553 if (!src->seekable) {
554 /* If it isn't seekable, we won't know the length (but fstat will still
555 * succeed, and wrongly say our length is zero. */
559 if (fstat (src->fd, &stat_results) < 0)
562 //*size = stat_results.st_size;
563 /* Naveen : Intentionally, doing this because we dont know the file size...because its keep on increasing in PD case */
566 GST_DEBUG ("size of the file = %"G_GUINT64_FORMAT, *size);
575 GST_ERROR_OBJECT (src, "Could not stat");
580 /* open the file, necessary to go to READY state */
582 gst_pd_pushsrc_start (GstBaseSrc * basesrc)
586 GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
587 struct stat stat_results;
589 if (src->filename == NULL || src->filename[0] == '\0')
592 GST_INFO_OBJECT (src, "opening file %s", src->filename);
595 src->fd = file_open (src->filename, O_RDONLY | O_BINARY, 0);
600 /* check if it is a regular file, otherwise bail out */
601 if (fstat (src->fd, &stat_results) < 0)
604 if (S_ISDIR (stat_results.st_mode))
607 if (S_ISSOCK (stat_results.st_mode))
610 src->read_position = 0;
612 /* record if it's a regular (hence seekable and lengthable) file */
613 if (S_ISREG (stat_results.st_mode))
614 src->is_regular = TRUE;
617 /* we need to check if the underlying file is seekable. */
618 off_t res = lseek (src->fd, 0, SEEK_END);
621 GST_LOG_OBJECT (src, "disabling seeking, not in mmap mode and lseek "
622 "failed: %s", g_strerror (errno));
623 src->seekable = FALSE;
625 src->seekable = TRUE;
627 lseek (src->fd, 0, SEEK_SET);
630 /* We can only really do seeking on regular files - for other file types, we
631 * don't know their length, so seeking isn't useful/meaningful */
632 src->seekable = src->seekable && src->is_regular;
640 GST_ERROR_OBJECT (src, "No file name specified for reading...");
641 GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
642 ("No file name specified for reading."), (NULL));
649 GST_ERROR_OBJECT (src, "File could not be found");
650 GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
651 ("No such file \"\""));
654 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
655 ("Could not open file for reading."),
663 GST_ERROR_OBJECT (src, "Could not get stat info...");
664 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
665 ("Could not get info on \"\"."), (NULL));
671 GST_ERROR_OBJECT (src, "Is a Directory");
672 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
673 ("\"\" is a directory."), (NULL));
679 GST_ERROR_OBJECT (src, "Is a Socket");
680 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
681 ("File \"\" is a socket."), (NULL));
687 /* unmap and close the file */
689 gst_pd_pushsrc_stop (GstBaseSrc * basesrc)
693 GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
698 /* zero out a lot of our state */
700 src->is_regular = FALSE;
707 /*** GSTURIHANDLER INTERFACE *************************************************/
710 gst_pd_pushsrc_uri_get_type (void)
719 gst_pd_pushsrc_uri_get_protocols (void)
722 static gchar *protocols[] = { (char *) "file", NULL };
729 gst_pd_pushsrc_uri_get_uri (GstURIHandler * handler)
732 GstPDPushSrc *src = GST_PD_PUSHSRC (handler);
739 gst_pd_pushsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri)
743 gchar *location, *hostname = NULL;
744 gboolean ret = FALSE;
745 GstPDPushSrc *src = GST_PD_PUSHSRC (handler);
746 GError *error = NULL;
748 if (strcmp (uri, "file://") == 0) {
749 /* Special case for "file://" as this is used by some applications
750 * to test with gst_element_make_from_uri if there's an element
751 * that supports the URI protocol. */
752 gst_pd_pushsrc_set_location (src, NULL);
756 location = g_filename_from_uri (uri, &hostname, &error);
758 if (!location || error) {
760 GST_WARNING_OBJECT (src, "Invalid URI '%s' for filesrc: %s", uri,
762 g_error_free (error);
764 GST_WARNING_OBJECT (src, "Invalid URI '%s' for filesrc", uri);
769 if ((hostname) && (strcmp (hostname, "localhost"))) {
770 /* Only 'localhost' is permitted */
771 GST_WARNING_OBJECT (src, "Invalid hostname '%s' for filesrc", hostname);
775 /* Unfortunately, g_filename_from_uri() doesn't handle some UNC paths
776 * correctly on windows, it leaves them with an extra backslash
777 * at the start if they're of the mozilla-style file://///host/path/file
778 * form. Correct this.
780 if (location[0] == '\\' && location[1] == '\\' && location[2] == '\\')
781 g_memmove (location, location + 1, strlen (location + 1) + 1);
784 ret = gst_pd_pushsrc_set_location (src, location);
798 gst_pd_pushsrc_uri_handler_init (gpointer g_iface, gpointer iface_data)
801 GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
803 iface->get_type = gst_pd_pushsrc_uri_get_type;
804 iface->get_protocols = gst_pd_pushsrc_uri_get_protocols;
805 iface->get_uri = gst_pd_pushsrc_uri_get_uri;
806 iface->set_uri = gst_pd_pushsrc_uri_set_uri;
811 gst_pd_pushsrc_plugin_init (GstPlugin *plugin)
813 if (!gst_element_register (plugin, "pdpushsrc", GST_RANK_NONE, gst_pd_pushsrc_get_type()))
820 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
824 gst_pd_pushsrc_plugin_init,
827 "Samsung Electronics Co",
828 "http://www.samsung.com")