+2005-09-08 Michael Smith <msmith@fluendo.com>
+
+ * gst/elements/gstfilesrc.c: (gst_file_src_map_region),
+ (gst_file_src_map_small_region), (gst_file_src_create_mmap),
+ (gst_file_src_is_seekable), (gst_file_src_get_size),
+ (gst_file_src_start):
+ * gst/elements/gstfilesrc.h:
+ Various fixes for unseekable, unmmapable, and non-normal files, so
+ that fallback to read() rather than mmap() works.
+ * gst/gstevent.c: (gst_event_new_newsegment):
+ Allow newsegment events with segment_start == segment_end, as will
+ correctly happen if you use filesrc on a zero-size file, for
+ example.
+
2005-09-07 Jan Schmidt <thaytan@mad.scientist.com>
* gst/gstplugin.c: (gst_plugin_load_file):
}
static GstBuffer *
-gst_file_src_map_region (GstFileSrc * src, off_t offset, size_t size)
+gst_file_src_map_region (GstFileSrc * src, off_t offset, size_t size,
+ gboolean testonly)
{
GstBuffer *buf;
void *mmapregion;
/* ERROR */
mmap_failed:
{
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
- ("mmap (0x%08lx, %d, 0x%llx) failed: %s",
- (gulong) size, src->fd, offset, strerror (errno)));
+ if (!testonly) {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
+ ("mmap (0x%08lx, %d, 0x%llx) failed: %s",
+ (gulong) size, src->fd, offset, strerror (errno)));
+ }
return NULL;
}
}
"not on page boundaries, resizing to map to %llu+%d",
(unsigned long long) mapbase, (gint) mapsize);
- map = gst_file_src_map_region (src, mapbase, mapsize);
+ map = gst_file_src_map_region (src, mapbase, mapsize, FALSE);
if (map == NULL)
return NULL;
gst_buffer_unref (map);
} else {
- ret = gst_file_src_map_region (src, offset, size);
+ ret = gst_file_src_map_region (src, offset, size, FALSE);
}
return ret;
mapsize <<= 1;
}
/* create a new one */
- src->mapbuf = gst_file_src_map_region (src, nextmap, mapsize);
+ src->mapbuf = gst_file_src_map_region (src, nextmap, mapsize, FALSE);
if (src->mapbuf == NULL)
goto could_not_mmap;
}
static gboolean
-gst_file_src_is_seekable (GstBaseSrc * src)
+gst_file_src_is_seekable (GstBaseSrc * basesrc)
{
- return TRUE;
+ GstFileSrc *src = GST_FILE_SRC (basesrc);
+
+ return src->seekable;
}
static gboolean
src = GST_FILE_SRC (basesrc);
+ if (!src->seekable) {
+ /* If it isn't seekable, we won't know the length (but fstat will still
+ * succeed, and wrongly say our length is zero. */
+ return FALSE;
+ }
+
if (fstat (src->fd, &stat_results) < 0)
goto could_not_stat;
#ifdef HAVE_MMAP
/* FIXME: maybe we should only try to mmap if it's a regular file */
/* allocate the first mmap'd region if it's a regular file ? */
- src->mapbuf = gst_file_src_map_region (src, 0, src->mapsize);
+ src->mapbuf = gst_file_src_map_region (src, 0, src->mapsize, TRUE);
if (src->mapbuf != NULL) {
GST_DEBUG_OBJECT (src, "using mmap for file");
src->using_mmap = TRUE;
- }
+ src->seekable = TRUE;
+ } else
#endif
+ {
+ /* If not in mmap mode, we need to check if the underlying file is
+ * seekable. */
+ off_t res = lseek (src->fd, 0, SEEK_CUR);
+
+ if (res < 0) {
+ GST_LOG_OBJECT (src, "disabling seeking, not in mmap mode and lseek "
+ "failed: %s", strerror (errno));
+ src->seekable = FALSE;
+ } else {
+ src->seekable = TRUE;
+ }
+ }
+
+ /* We can only really do seeking on regular files - for other file types, we
+ * don't know their length, so seeking isn't useful/meaningful */
+ src->seekable = src->seekable && src->is_regular;
return TRUE;
break;
default:
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
- (_("Could not open file \"%s\" for reading."), src->filename),
- GST_ERROR_SYSTEM);
+ (_("Could not open file \"%s\" for reading: %s."), src->filename,
+ strerror (errno)), GST_ERROR_SYSTEM);
break;
}
return FALSE;
gboolean touch; /* whether to touch every page */
gboolean using_mmap; /* whether we opened it with mmap */
+ gboolean seekable; /* whether the file is seekable */
gboolean is_regular; /* whether it's a (symlink to a)
regular file */
GstBuffer *mapbuf;
g_return_val_if_fail (start_value != -1, NULL);
if (stop_value != -1)
- g_return_val_if_fail (start_value < stop_value, NULL);
+ g_return_val_if_fail (start_value <= stop_value, NULL);
return gst_event_new_custom (GST_EVENT_NEWSEGMENT,
gst_structure_new ("GstEventNewsegment", "rate", G_TYPE_DOUBLE, rate,
}
static GstBuffer *
-gst_file_src_map_region (GstFileSrc * src, off_t offset, size_t size)
+gst_file_src_map_region (GstFileSrc * src, off_t offset, size_t size,
+ gboolean testonly)
{
GstBuffer *buf;
void *mmapregion;
/* ERROR */
mmap_failed:
{
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
- ("mmap (0x%08lx, %d, 0x%llx) failed: %s",
- (gulong) size, src->fd, offset, strerror (errno)));
+ if (!testonly) {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
+ ("mmap (0x%08lx, %d, 0x%llx) failed: %s",
+ (gulong) size, src->fd, offset, strerror (errno)));
+ }
return NULL;
}
}
"not on page boundaries, resizing to map to %llu+%d",
(unsigned long long) mapbase, (gint) mapsize);
- map = gst_file_src_map_region (src, mapbase, mapsize);
+ map = gst_file_src_map_region (src, mapbase, mapsize, FALSE);
if (map == NULL)
return NULL;
gst_buffer_unref (map);
} else {
- ret = gst_file_src_map_region (src, offset, size);
+ ret = gst_file_src_map_region (src, offset, size, FALSE);
}
return ret;
mapsize <<= 1;
}
/* create a new one */
- src->mapbuf = gst_file_src_map_region (src, nextmap, mapsize);
+ src->mapbuf = gst_file_src_map_region (src, nextmap, mapsize, FALSE);
if (src->mapbuf == NULL)
goto could_not_mmap;
}
static gboolean
-gst_file_src_is_seekable (GstBaseSrc * src)
+gst_file_src_is_seekable (GstBaseSrc * basesrc)
{
- return TRUE;
+ GstFileSrc *src = GST_FILE_SRC (basesrc);
+
+ return src->seekable;
}
static gboolean
src = GST_FILE_SRC (basesrc);
+ if (!src->seekable) {
+ /* If it isn't seekable, we won't know the length (but fstat will still
+ * succeed, and wrongly say our length is zero. */
+ return FALSE;
+ }
+
if (fstat (src->fd, &stat_results) < 0)
goto could_not_stat;
#ifdef HAVE_MMAP
/* FIXME: maybe we should only try to mmap if it's a regular file */
/* allocate the first mmap'd region if it's a regular file ? */
- src->mapbuf = gst_file_src_map_region (src, 0, src->mapsize);
+ src->mapbuf = gst_file_src_map_region (src, 0, src->mapsize, TRUE);
if (src->mapbuf != NULL) {
GST_DEBUG_OBJECT (src, "using mmap for file");
src->using_mmap = TRUE;
- }
+ src->seekable = TRUE;
+ } else
#endif
+ {
+ /* If not in mmap mode, we need to check if the underlying file is
+ * seekable. */
+ off_t res = lseek (src->fd, 0, SEEK_CUR);
+
+ if (res < 0) {
+ GST_LOG_OBJECT (src, "disabling seeking, not in mmap mode and lseek "
+ "failed: %s", strerror (errno));
+ src->seekable = FALSE;
+ } else {
+ src->seekable = TRUE;
+ }
+ }
+
+ /* We can only really do seeking on regular files - for other file types, we
+ * don't know their length, so seeking isn't useful/meaningful */
+ src->seekable = src->seekable && src->is_regular;
return TRUE;
break;
default:
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
- (_("Could not open file \"%s\" for reading."), src->filename),
- GST_ERROR_SYSTEM);
+ (_("Could not open file \"%s\" for reading: %s."), src->filename,
+ strerror (errno)), GST_ERROR_SYSTEM);
break;
}
return FALSE;
gboolean touch; /* whether to touch every page */
gboolean using_mmap; /* whether we opened it with mmap */
+ gboolean seekable; /* whether the file is seekable */
gboolean is_regular; /* whether it's a (symlink to a)
regular file */
GstBuffer *mapbuf;