gio: make better use of the cached buffer

When playing mp3 files from a smb server, we get 64k read requests
that mostly overlap.  Without using the cache to partially satisfy
these, we send these requests straight to the server, resulting in
a lot more network traffic than necessary.

https://bugzilla.gnome.org/show_bug.cgi?id=705415
This commit is contained in:
Jonathan Matthew 2013-08-04 01:01:25 +10:00 committed by Sebastian Dröge
parent ca2a515373
commit cc1de5ae94

View file

@ -320,50 +320,75 @@ gst_gio_base_src_create (GstBaseSrc * base_src, guint64 offset, guint size,
} else {
guint cachesize = MAX (4096, size);
GstMapInfo map;
gssize read, res;
gssize read, streamread, res;
guint64 readoffset;
gboolean success, eos;
GError *err = NULL;
GstBuffer *newbuffer;
GstMemory *mem;
if (src->cache) {
gst_buffer_unref (src->cache);
src->cache = NULL;
newbuffer = gst_buffer_new ();
/* copy any overlapping data from the cached buffer */
if (src->cache && offset >= GST_BUFFER_OFFSET (src->cache) &&
offset <= GST_BUFFER_OFFSET_END (src->cache)) {
read = GST_BUFFER_OFFSET_END (src->cache) - offset;
GST_LOG_OBJECT (src,
"Copying %" G_GUINT64_FORMAT " bytes from cached buffer at %"
G_GUINT64_FORMAT, read, offset - GST_BUFFER_OFFSET (src->cache));
gst_buffer_copy_into (newbuffer, src->cache, GST_BUFFER_COPY_MEMORY,
offset - GST_BUFFER_OFFSET (src->cache), read);
} else {
read = 0;
}
if (G_UNLIKELY (offset != src->position)) {
if (src->cache)
gst_buffer_unref (src->cache);
src->cache = newbuffer;
readoffset = offset + read;
GST_LOG_OBJECT (src,
"Reading %u bytes from offset %" G_GUINT64_FORMAT, cachesize,
readoffset);
if (G_UNLIKELY (readoffset != src->position)) {
if (!GST_GIO_STREAM_IS_SEEKABLE (src->stream))
return GST_FLOW_NOT_SUPPORTED;
GST_DEBUG_OBJECT (src, "Seeking to position %" G_GUINT64_FORMAT, offset);
ret = gst_gio_seek (src, G_SEEKABLE (src->stream), offset, src->cancel);
GST_DEBUG_OBJECT (src, "Seeking to position %" G_GUINT64_FORMAT,
readoffset);
ret =
gst_gio_seek (src, G_SEEKABLE (src->stream), readoffset, src->cancel);
if (ret == GST_FLOW_OK)
src->position = offset;
src->position = readoffset;
else
return ret;
}
src->cache = gst_buffer_new_and_alloc (cachesize);
if (G_UNLIKELY (src->cache == NULL)) {
GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", cachesize);
return GST_FLOW_ERROR;
}
GST_LOG_OBJECT (src, "Reading %u bytes from offset %" G_GUINT64_FORMAT,
cachesize, offset);
/* GIO sometimes gives less bytes than requested although
* it's not at the end of file. SMB for example only
* supports reads up to 64k. So we loop here until we get at
* at least the requested amount of bytes or a read returns
* nothing. */
gst_buffer_map (src->cache, &map, GST_MAP_WRITE);
read = 0;
mem = gst_allocator_alloc (NULL, cachesize, NULL);
if (mem == NULL) {
GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", cachesize);
return GST_FLOW_ERROR;
}
gst_memory_map (mem, &map, GST_MAP_WRITE);
streamread = 0;
while (size - read > 0 && (res =
g_input_stream_read (G_INPUT_STREAM (src->stream),
map.data + read, cachesize - read, src->cancel, &err)) > 0) {
map.data + streamread, cachesize - streamread, src->cancel,
&err)) > 0) {
read += res;
streamread += res;
src->position += res;
}
gst_buffer_unmap (src->cache, &map);
gst_memory_unmap (mem, &map);
gst_buffer_append_memory (src->cache, mem);
success = (read >= 0);
eos = (cachesize > 0 && read == 0);
@ -375,8 +400,6 @@ gst_gio_base_src_create (GstBaseSrc * base_src, guint64 offset, guint size,
}
if (success && !eos) {
src->position += read;
GST_BUFFER_OFFSET (src->cache) = offset;
GST_BUFFER_OFFSET_END (src->cache) = offset + read;