19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
20 * Boston, MA 02111-1307, USA. |
20 * Boston, MA 02111-1307, USA. |
21 */ |
21 */ |
22 /** |
22 /** |
23 * SECTION:element-filesrc |
23 * SECTION:element-filesrc |
|
24 * @short_description: read from arbitrary point in a file |
24 * @see_also: #GstFileSrc |
25 * @see_also: #GstFileSrc |
25 * |
26 * |
26 * Read data from a file in the local file system. |
27 * Read data from a file in the local file system. |
27 */ |
28 */ |
28 |
29 |
29 #ifdef HAVE_CONFIG_H |
30 #ifdef HAVE_CONFIG_H |
30 # include "config.h" |
31 # include "config.h" |
31 #endif |
32 #endif |
|
33 #ifdef __SYMBIAN32__ |
|
34 #include <gst_global.h> |
|
35 #endif |
32 |
36 |
33 #include <gst/gst.h> |
37 #include <gst/gst.h> |
34 #include "gstfilesrc.h" |
38 #include "gstfilesrc.h" |
35 |
39 |
36 #include <stdio.h> |
40 #include <stdio.h> |
37 #include <sys/types.h> |
41 #include <sys/types.h> |
38 #ifdef G_OS_WIN32 |
|
39 #include <io.h> /* lseek, open, close, read */ |
|
40 /* On win32, stat* default to 32 bit; we need the 64-bit |
|
41 * variants, so explicitly define it that way. */ |
|
42 #define stat __stat64 |
|
43 #define fstat _fstat64 |
|
44 #undef lseek |
|
45 #define lseek _lseeki64 |
|
46 #undef off_t |
|
47 #define off_t guint64 |
|
48 /* Prevent stat.h from defining the stat* functions as |
|
49 * _stat*, since we're explicitly overriding that */ |
|
50 #undef _INC_STAT_INL |
|
51 #endif |
|
52 #include <sys/stat.h> |
42 #include <sys/stat.h> |
53 #include <fcntl.h> |
43 #include <fcntl.h> |
54 |
44 |
|
45 #ifdef __SYMBIAN32__ |
|
46 #include <glib_global.h> |
|
47 #include <gobject_global.h> |
|
48 #endif |
|
49 |
55 #ifdef HAVE_UNISTD_H |
50 #ifdef HAVE_UNISTD_H |
56 # include <unistd.h> |
51 # include <unistd.h> |
57 #endif |
52 #endif |
58 |
53 |
59 #ifdef HAVE_MMAP |
54 #ifdef HAVE_MMAP |
60 # include <sys/mman.h> |
55 # include <sys/mman.h> |
61 #endif |
56 #endif |
62 |
57 |
|
58 #ifdef HAVE_WIN32 |
|
59 # include <io.h> /* lseek, open, close, read */ |
|
60 #endif |
|
61 |
63 #include <errno.h> |
62 #include <errno.h> |
64 #include <string.h> |
63 #include <string.h> |
65 |
64 |
66 #include "../../gst/gst-i18n-lib.h" |
65 #include "../../gst/gst-i18n-lib.h" |
|
66 #include <gstelement.h> |
67 |
67 |
68 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", |
68 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", |
69 GST_PAD_SRC, |
69 GST_PAD_SRC, |
70 GST_PAD_ALWAYS, |
70 GST_PAD_ALWAYS, |
71 GST_STATIC_CAPS_ANY); |
71 GST_STATIC_CAPS_ANY); |
81 #define S_ISSOCK(x) (0) |
81 #define S_ISSOCK(x) (0) |
82 #endif |
82 #endif |
83 #ifndef O_BINARY |
83 #ifndef O_BINARY |
84 #define O_BINARY (0) |
84 #define O_BINARY (0) |
85 #endif |
85 #endif |
86 |
|
87 /* Copy of glib's g_open due to win32 libc/cross-DLL brokenness: we can't |
|
88 * use the 'file descriptor' opened in glib (and returned from this function) |
|
89 * in this library, as they may have unrelated C runtimes. */ |
|
90 #ifdef __SYMBIAN32__ |
|
91 EXPORT_C |
|
92 #endif |
|
93 |
|
94 int |
|
95 gst_open (const gchar * filename, int flags, int mode) |
|
96 { |
|
97 #ifdef G_OS_WIN32 |
|
98 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL); |
|
99 int retval; |
|
100 int save_errno; |
|
101 |
|
102 if (wfilename == NULL) { |
|
103 errno = EINVAL; |
|
104 return -1; |
|
105 } |
|
106 |
|
107 retval = _wopen (wfilename, flags, mode); |
|
108 save_errno = errno; |
|
109 |
|
110 g_free (wfilename); |
|
111 |
|
112 errno = save_errno; |
|
113 return retval; |
|
114 #else |
|
115 return open (filename, flags, mode); |
|
116 #endif |
|
117 } |
|
118 |
86 |
119 |
87 |
120 /********************************************************************** |
88 /********************************************************************** |
121 * GStreamer Default File Source |
89 * GStreamer Default File Source |
122 * Theory of Operation |
90 * Theory of Operation |
195 |
163 |
196 static gboolean gst_file_src_is_seekable (GstBaseSrc * src); |
164 static gboolean gst_file_src_is_seekable (GstBaseSrc * src); |
197 static gboolean gst_file_src_get_size (GstBaseSrc * src, guint64 * size); |
165 static gboolean gst_file_src_get_size (GstBaseSrc * src, guint64 * size); |
198 static GstFlowReturn gst_file_src_create (GstBaseSrc * src, guint64 offset, |
166 static GstFlowReturn gst_file_src_create (GstBaseSrc * src, guint64 offset, |
199 guint length, GstBuffer ** buffer); |
167 guint length, GstBuffer ** buffer); |
200 static gboolean gst_file_src_query (GstBaseSrc * src, GstQuery * query); |
|
201 |
168 |
202 static void gst_file_src_uri_handler_init (gpointer g_iface, |
169 static void gst_file_src_uri_handler_init (gpointer g_iface, |
203 gpointer iface_data); |
170 gpointer iface_data); |
204 |
171 |
205 static void |
172 static void |
235 |
202 |
236 static void |
203 static void |
237 gst_file_src_class_init (GstFileSrcClass * klass) |
204 gst_file_src_class_init (GstFileSrcClass * klass) |
238 { |
205 { |
239 GObjectClass *gobject_class; |
206 GObjectClass *gobject_class; |
|
207 GstElementClass *gstelement_class; |
240 GstBaseSrcClass *gstbasesrc_class; |
208 GstBaseSrcClass *gstbasesrc_class; |
241 |
209 |
242 gobject_class = G_OBJECT_CLASS (klass); |
210 gobject_class = G_OBJECT_CLASS (klass); |
|
211 gstelement_class = GST_ELEMENT_CLASS (klass); |
243 gstbasesrc_class = GST_BASE_SRC_CLASS (klass); |
212 gstbasesrc_class = GST_BASE_SRC_CLASS (klass); |
244 |
213 |
245 gobject_class->set_property = gst_file_src_set_property; |
214 gobject_class->set_property = gst_file_src_set_property; |
246 gobject_class->get_property = gst_file_src_get_property; |
215 gobject_class->get_property = gst_file_src_get_property; |
247 |
216 |
248 g_object_class_install_property (gobject_class, ARG_FD, |
217 g_object_class_install_property (gobject_class, ARG_FD, |
249 g_param_spec_int ("fd", "File-descriptor", |
218 g_param_spec_int ("fd", "File-descriptor", |
250 "File-descriptor for the file being mmap()d", 0, G_MAXINT, 0, |
219 "File-descriptor for the file being mmap()d", 0, G_MAXINT, 0, |
251 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); |
220 G_PARAM_READABLE)); |
252 g_object_class_install_property (gobject_class, ARG_LOCATION, |
221 g_object_class_install_property (gobject_class, ARG_LOCATION, |
253 g_param_spec_string ("location", "File Location", |
222 g_param_spec_string ("location", "File Location", |
254 "Location of the file to read", NULL, |
223 "Location of the file to read", NULL, G_PARAM_READWRITE)); |
255 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | |
|
256 GST_PARAM_MUTABLE_READY)); |
|
257 g_object_class_install_property (gobject_class, ARG_MMAPSIZE, |
224 g_object_class_install_property (gobject_class, ARG_MMAPSIZE, |
258 g_param_spec_ulong ("mmapsize", "mmap() Block Size", |
225 g_param_spec_ulong ("mmapsize", "mmap() Block Size", |
259 "Size in bytes of mmap()d regions", 0, G_MAXULONG, DEFAULT_MMAPSIZE, |
226 "Size in bytes of mmap()d regions", 0, G_MAXULONG, DEFAULT_MMAPSIZE, |
260 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | |
227 G_PARAM_READWRITE)); |
261 GST_PARAM_MUTABLE_PLAYING)); |
|
262 g_object_class_install_property (gobject_class, ARG_TOUCH, |
228 g_object_class_install_property (gobject_class, ARG_TOUCH, |
263 g_param_spec_boolean ("touch", "Touch mapped region read data", |
229 g_param_spec_boolean ("touch", "Touch mapped region read data", |
264 "Touch mmapped data regions to force them to be read from disk", |
230 "Touch mmapped data regions to force them to be read from disk", |
265 DEFAULT_TOUCH, |
231 DEFAULT_TOUCH, G_PARAM_READWRITE)); |
266 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | |
|
267 GST_PARAM_MUTABLE_PLAYING)); |
|
268 /** |
232 /** |
269 * GstFileSrc:use-mmap |
233 * GstFileSrc:use-mmap |
270 * |
234 * |
271 * Whether to use mmap(). Set to TRUE to force use of mmap() instead of |
235 * Whether to use mmap(). Set to TRUE to force use of mmap() instead of |
272 * read() for reading data. |
236 * read() for reading data. |
284 * |
248 * |
285 **/ |
249 **/ |
286 g_object_class_install_property (gobject_class, ARG_USEMMAP, |
250 g_object_class_install_property (gobject_class, ARG_USEMMAP, |
287 g_param_spec_boolean ("use-mmap", "Use mmap to read data", |
251 g_param_spec_boolean ("use-mmap", "Use mmap to read data", |
288 "Whether to use mmap() instead of read()", |
252 "Whether to use mmap() instead of read()", |
289 DEFAULT_USEMMAP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | |
253 DEFAULT_USEMMAP, G_PARAM_READWRITE)); |
290 GST_PARAM_MUTABLE_READY)); |
|
291 g_object_class_install_property (gobject_class, ARG_SEQUENTIAL, |
254 g_object_class_install_property (gobject_class, ARG_SEQUENTIAL, |
292 g_param_spec_boolean ("sequential", "Optimise for sequential mmap access", |
255 g_param_spec_boolean ("sequential", "Optimise for sequential mmap access", |
293 "Whether to use madvise to hint to the kernel that access to " |
256 "Whether to use madvise to hint to the kernel that access to " |
294 "mmap pages will be sequential", |
257 "mmap pages will be sequential", |
295 DEFAULT_SEQUENTIAL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | |
258 DEFAULT_SEQUENTIAL, G_PARAM_READWRITE)); |
296 GST_PARAM_MUTABLE_PLAYING)); |
|
297 |
259 |
298 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_file_src_finalize); |
260 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_file_src_finalize); |
299 |
261 |
300 gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_file_src_start); |
262 gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_file_src_start); |
301 gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_file_src_stop); |
263 gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_file_src_stop); |
302 gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_file_src_is_seekable); |
264 gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_file_src_is_seekable); |
303 gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_file_src_get_size); |
265 gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_file_src_get_size); |
304 gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_file_src_create); |
266 gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_file_src_create); |
305 gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_file_src_query); |
|
306 |
267 |
307 if (sizeof (off_t) < 8) { |
268 if (sizeof (off_t) < 8) { |
308 GST_LOG ("No large file support, sizeof (off_t) = %" G_GSIZE_FORMAT "!", |
269 GST_LOG ("No large file support, sizeof (off_t) = %" G_GSIZE_FORMAT "!", |
309 sizeof (off_t)); |
270 sizeof (off_t)); |
310 } |
271 } |
362 /* clear the filename if we get a NULL (is that possible?) */ |
323 /* clear the filename if we get a NULL (is that possible?) */ |
363 if (location == NULL) { |
324 if (location == NULL) { |
364 src->filename = NULL; |
325 src->filename = NULL; |
365 src->uri = NULL; |
326 src->uri = NULL; |
366 } else { |
327 } else { |
367 /* we store the filename as received by the application. On Windoes this |
|
368 * should be UTF8 */ |
|
369 src->filename = g_strdup (location); |
328 src->filename = g_strdup (location); |
370 src->uri = gst_uri_construct ("file", src->filename); |
329 src->uri = gst_uri_construct ("file", src->filename); |
371 } |
330 } |
372 g_object_notify (G_OBJECT (src), "location"); |
331 g_object_notify (G_OBJECT (src), "location"); |
373 gst_uri_handler_new_uri (GST_URI_HANDLER (src), src->uri); |
332 gst_uri_handler_new_uri (GST_URI_HANDLER (src), src->uri); |
574 /* cast to unsigned long, since there's no gportable way to print |
532 /* cast to unsigned long, since there's no gportable way to print |
575 * guint64 as hex */ |
533 * guint64 as hex */ |
576 GST_LOG ("unmapped region %08lx+%08lx at %p", |
534 GST_LOG ("unmapped region %08lx+%08lx at %p", |
577 (gulong) offset, (gulong) size, data); |
535 (gulong) offset, (gulong) size, data); |
578 |
536 |
579 GST_MINI_OBJECT_CLASS (mmap_buffer_parent_class)->finalize (GST_MINI_OBJECT |
537 GST_MINI_OBJECT_CLASS (mmap_buffer_parent_class)-> |
580 (mmap_buffer)); |
538 finalize (GST_MINI_OBJECT (mmap_buffer)); |
581 } |
539 } |
582 |
540 |
583 static GstBuffer * |
541 static GstBuffer * |
584 gst_file_src_map_region (GstFileSrc * src, off_t offset, gsize size, |
542 gst_file_src_map_region (GstFileSrc * src, off_t offset, gsize size, |
585 gboolean testonly) |
543 gboolean testonly) |
607 GST_MMAP_BUFFER (buf)->filesrc = src; |
565 GST_MMAP_BUFFER (buf)->filesrc = src; |
608 |
566 |
609 #ifdef MADV_SEQUENTIAL |
567 #ifdef MADV_SEQUENTIAL |
610 if (src->sequential) { |
568 if (src->sequential) { |
611 /* madvise to tell the kernel what to do with it */ |
569 /* madvise to tell the kernel what to do with it */ |
|
570 #ifndef __SYMBIAN32__ |
612 if (madvise (mmapregion, size, MADV_SEQUENTIAL) < 0) { |
571 if (madvise (mmapregion, size, MADV_SEQUENTIAL) < 0) { |
613 GST_WARNING_OBJECT (src, "warning: madvise failed: %s", |
572 GST_WARNING_OBJECT (src, "warning: madvise failed: %s", |
614 g_strerror (errno)); |
573 g_strerror (errno)); |
615 } |
574 } |
616 } |
575 #endif |
617 #endif |
576 #endif |
618 |
577 |
619 /* fill in the rest of the fields */ |
578 /* fill in the rest of the fields */ |
620 GST_BUFFER_SIZE (buf) = size; |
579 GST_BUFFER_SIZE (buf) = size; |
621 GST_BUFFER_OFFSET (buf) = offset; |
580 GST_BUFFER_OFFSET (buf) = offset; |
831 goto seek_failed; |
790 goto seek_failed; |
832 |
791 |
833 src->read_position = offset; |
792 src->read_position = offset; |
834 } |
793 } |
835 |
794 |
836 buf = gst_buffer_try_new_and_alloc (length); |
795 buf = gst_buffer_new_and_alloc (length); |
837 if (G_UNLIKELY (buf == NULL && length > 0)) { |
796 |
838 GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", length); |
797 GST_LOG_OBJECT (src, "Reading %d bytes", length); |
839 return GST_FLOW_ERROR; |
|
840 } |
|
841 |
|
842 GST_LOG_OBJECT (src, "Reading %d bytes at offset 0x%" G_GINT64_MODIFIER "x", |
|
843 length, offset); |
|
844 ret = read (src->fd, GST_BUFFER_DATA (buf), length); |
798 ret = read (src->fd, GST_BUFFER_DATA (buf), length); |
845 if (G_UNLIKELY (ret < 0)) |
799 if (G_UNLIKELY (ret < 0)) |
846 goto could_not_read; |
800 goto could_not_read; |
847 |
801 |
848 /* seekable regular files should have given us what we expected */ |
802 /* seekable regular files should have given us what we expected */ |
1136 } |
1064 } |
1137 |
1065 |
1138 static gboolean |
1066 static gboolean |
1139 gst_file_src_uri_set_uri (GstURIHandler * handler, const gchar * uri) |
1067 gst_file_src_uri_set_uri (GstURIHandler * handler, const gchar * uri) |
1140 { |
1068 { |
1141 gchar *location, *hostname = NULL; |
1069 gchar *protocol, *location; |
1142 gboolean ret = FALSE; |
1070 gboolean ret; |
1143 GstFileSrc *src = GST_FILE_SRC (handler); |
1071 GstFileSrc *src = GST_FILE_SRC (handler); |
1144 GError *error = NULL; |
1072 |
1145 |
1073 protocol = gst_uri_get_protocol (uri); |
1146 if (strcmp (uri, "file://") == 0) { |
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) { |
1147 /* Special case for "file://" as this is used by some applications |
1092 /* Special case for "file://" as this is used by some applications |
1148 * to test with gst_element_make_from_uri if there's an element |
1093 * to test with gst_element_make_from_uri if there's an element |
1149 * that supports the URI protocol. */ |
1094 * that supports the URI protocol. */ |
1150 gst_file_src_set_location (src, NULL); |
1095 gst_file_src_set_location (src, NULL); |
1151 return TRUE; |
1096 return TRUE; |
1152 } |
1097 } else { |
1153 |
1098 location = gst_uri_get_location (uri); |
1154 location = g_filename_from_uri (uri, &hostname, &error); |
1099 } |
1155 |
1100 |
1156 if (!location || error) { |
1101 if (!location) |
1157 if (error) { |
1102 return FALSE; |
1158 GST_WARNING_OBJECT (src, "Invalid URI '%s' for filesrc: %s", uri, |
1103 if (!g_path_is_absolute (location)) { |
1159 error->message); |
1104 g_free (location); |
1160 g_error_free (error); |
1105 return FALSE; |
1161 } else { |
1106 } |
1162 GST_WARNING_OBJECT (src, "Invalid URI '%s' for filesrc", uri); |
|
1163 } |
|
1164 goto beach; |
|
1165 } |
|
1166 |
|
1167 if ((hostname) && (strcmp (hostname, "localhost"))) { |
|
1168 /* Only 'localhost' is permitted */ |
|
1169 GST_WARNING_OBJECT (src, "Invalid hostname '%s' for filesrc", hostname); |
|
1170 goto beach; |
|
1171 } |
|
1172 #ifdef G_OS_WIN32 |
|
1173 /* Unfortunately, g_filename_from_uri() doesn't handle some UNC paths |
|
1174 * correctly on windows, it leaves them with an extra backslash |
|
1175 * at the start if they're of the mozilla-style file://///host/path/file |
|
1176 * form. Correct this. |
|
1177 */ |
|
1178 if (location[0] == '\\' && location[1] == '\\' && location[2] == '\\') |
|
1179 g_memmove (location, location + 1, strlen (location + 1) + 1); |
|
1180 #endif |
|
1181 |
1107 |
1182 ret = gst_file_src_set_location (src, location); |
1108 ret = gst_file_src_set_location (src, location); |
1183 |
1109 g_free (location); |
1184 beach: |
|
1185 if (location) |
|
1186 g_free (location); |
|
1187 if (hostname) |
|
1188 g_free (hostname); |
|
1189 |
1110 |
1190 return ret; |
1111 return ret; |
1191 } |
1112 } |
1192 |
1113 |
1193 static void |
1114 static void |