Various fixes for unseekable, unmmapable, and non-normal files, so that fallback to read() rather than mmap() works.

Original commit message from CVS:
Various fixes for unseekable, unmmapable, and non-normal files, so that
fallback to read() rather than mmap() works.

Allow newsegment events with start == end, so that cases where that's
correct work (e.g. filesrc on a zero-size file).
This commit is contained in:
Michael Smith 2005-09-08 17:23:57 +00:00
parent 686a044c4f
commit 4e78d6183f
6 changed files with 101 additions and 27 deletions

View file

@ -1,3 +1,17 @@
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> 2005-09-07 Jan Schmidt <thaytan@mad.scientist.com>
* gst/gstplugin.c: (gst_plugin_load_file): * gst/gstplugin.c: (gst_plugin_load_file):

View file

@ -473,7 +473,8 @@ gst_mmap_buffer_finalize (GstMmapBuffer * mmap_buffer)
} }
static GstBuffer * 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; GstBuffer *buf;
void *mmapregion; void *mmapregion;
@ -515,9 +516,11 @@ gst_file_src_map_region (GstFileSrc * src, off_t offset, size_t size)
/* ERROR */ /* ERROR */
mmap_failed: mmap_failed:
{ {
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), if (!testonly) {
("mmap (0x%08lx, %d, 0x%llx) failed: %s", GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
(gulong) size, src->fd, offset, strerror (errno))); ("mmap (0x%08lx, %d, 0x%llx) failed: %s",
(gulong) size, src->fd, offset, strerror (errno)));
}
return NULL; return NULL;
} }
} }
@ -550,7 +553,7 @@ gst_file_src_map_small_region (GstFileSrc * src, off_t offset, size_t size)
"not on page boundaries, resizing to map to %llu+%d", "not on page boundaries, resizing to map to %llu+%d",
(unsigned long long) mapbase, (gint) mapsize); (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) if (map == NULL)
return NULL; return NULL;
@ -559,7 +562,7 @@ gst_file_src_map_small_region (GstFileSrc * src, off_t offset, size_t size)
gst_buffer_unref (map); gst_buffer_unref (map);
} else { } else {
ret = gst_file_src_map_region (src, offset, size); ret = gst_file_src_map_region (src, offset, size, FALSE);
} }
return ret; return ret;
@ -660,7 +663,7 @@ gst_file_src_create_mmap (GstFileSrc * src, guint64 offset, guint length,
mapsize <<= 1; mapsize <<= 1;
} }
/* create a new one */ /* 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) if (src->mapbuf == NULL)
goto could_not_mmap; goto could_not_mmap;
@ -792,9 +795,11 @@ gst_file_src_create (GstBaseSrc * basesrc, guint64 offset, guint length,
} }
static gboolean 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 static gboolean
@ -805,6 +810,12 @@ gst_file_src_get_size (GstBaseSrc * basesrc, guint64 * size)
src = GST_FILE_SRC (basesrc); 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) if (fstat (src->fd, &stat_results) < 0)
goto could_not_stat; goto could_not_stat;
@ -856,12 +867,30 @@ gst_file_src_start (GstBaseSrc * basesrc)
#ifdef HAVE_MMAP #ifdef HAVE_MMAP
/* FIXME: maybe we should only try to mmap if it's a regular file */ /* 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 ? */ /* 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) { if (src->mapbuf != NULL) {
GST_DEBUG_OBJECT (src, "using mmap for file"); GST_DEBUG_OBJECT (src, "using mmap for file");
src->using_mmap = TRUE; src->using_mmap = TRUE;
} src->seekable = TRUE;
} else
#endif #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; return TRUE;
@ -881,8 +910,8 @@ open_failed:
break; break;
default: default:
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
(_("Could not open file \"%s\" for reading."), src->filename), (_("Could not open file \"%s\" for reading: %s."), src->filename,
GST_ERROR_SYSTEM); strerror (errno)), GST_ERROR_SYSTEM);
break; break;
} }
return FALSE; return FALSE;

View file

@ -57,6 +57,7 @@ struct _GstFileSrc {
gboolean touch; /* whether to touch every page */ gboolean touch; /* whether to touch every page */
gboolean using_mmap; /* whether we opened it with mmap */ 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) gboolean is_regular; /* whether it's a (symlink to a)
regular file */ regular file */
GstBuffer *mapbuf; GstBuffer *mapbuf;

View file

@ -323,7 +323,7 @@ gst_event_new_newsegment (gdouble rate, GstFormat format,
g_return_val_if_fail (start_value != -1, NULL); g_return_val_if_fail (start_value != -1, NULL);
if (stop_value != -1) 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, return gst_event_new_custom (GST_EVENT_NEWSEGMENT,
gst_structure_new ("GstEventNewsegment", "rate", G_TYPE_DOUBLE, rate, gst_structure_new ("GstEventNewsegment", "rate", G_TYPE_DOUBLE, rate,

View file

@ -473,7 +473,8 @@ gst_mmap_buffer_finalize (GstMmapBuffer * mmap_buffer)
} }
static GstBuffer * 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; GstBuffer *buf;
void *mmapregion; void *mmapregion;
@ -515,9 +516,11 @@ gst_file_src_map_region (GstFileSrc * src, off_t offset, size_t size)
/* ERROR */ /* ERROR */
mmap_failed: mmap_failed:
{ {
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), if (!testonly) {
("mmap (0x%08lx, %d, 0x%llx) failed: %s", GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
(gulong) size, src->fd, offset, strerror (errno))); ("mmap (0x%08lx, %d, 0x%llx) failed: %s",
(gulong) size, src->fd, offset, strerror (errno)));
}
return NULL; return NULL;
} }
} }
@ -550,7 +553,7 @@ gst_file_src_map_small_region (GstFileSrc * src, off_t offset, size_t size)
"not on page boundaries, resizing to map to %llu+%d", "not on page boundaries, resizing to map to %llu+%d",
(unsigned long long) mapbase, (gint) mapsize); (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) if (map == NULL)
return NULL; return NULL;
@ -559,7 +562,7 @@ gst_file_src_map_small_region (GstFileSrc * src, off_t offset, size_t size)
gst_buffer_unref (map); gst_buffer_unref (map);
} else { } else {
ret = gst_file_src_map_region (src, offset, size); ret = gst_file_src_map_region (src, offset, size, FALSE);
} }
return ret; return ret;
@ -660,7 +663,7 @@ gst_file_src_create_mmap (GstFileSrc * src, guint64 offset, guint length,
mapsize <<= 1; mapsize <<= 1;
} }
/* create a new one */ /* 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) if (src->mapbuf == NULL)
goto could_not_mmap; goto could_not_mmap;
@ -792,9 +795,11 @@ gst_file_src_create (GstBaseSrc * basesrc, guint64 offset, guint length,
} }
static gboolean 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 static gboolean
@ -805,6 +810,12 @@ gst_file_src_get_size (GstBaseSrc * basesrc, guint64 * size)
src = GST_FILE_SRC (basesrc); 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) if (fstat (src->fd, &stat_results) < 0)
goto could_not_stat; goto could_not_stat;
@ -856,12 +867,30 @@ gst_file_src_start (GstBaseSrc * basesrc)
#ifdef HAVE_MMAP #ifdef HAVE_MMAP
/* FIXME: maybe we should only try to mmap if it's a regular file */ /* 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 ? */ /* 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) { if (src->mapbuf != NULL) {
GST_DEBUG_OBJECT (src, "using mmap for file"); GST_DEBUG_OBJECT (src, "using mmap for file");
src->using_mmap = TRUE; src->using_mmap = TRUE;
} src->seekable = TRUE;
} else
#endif #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; return TRUE;
@ -881,8 +910,8 @@ open_failed:
break; break;
default: default:
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
(_("Could not open file \"%s\" for reading."), src->filename), (_("Could not open file \"%s\" for reading: %s."), src->filename,
GST_ERROR_SYSTEM); strerror (errno)), GST_ERROR_SYSTEM);
break; break;
} }
return FALSE; return FALSE;

View file

@ -57,6 +57,7 @@ struct _GstFileSrc {
gboolean touch; /* whether to touch every page */ gboolean touch; /* whether to touch every page */
gboolean using_mmap; /* whether we opened it with mmap */ 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) gboolean is_regular; /* whether it's a (symlink to a)
regular file */ regular file */
GstBuffer *mapbuf; GstBuffer *mapbuf;