gio: make better use of the cached buffer
authorJonathan Matthew <jonathan@d14n.org>
Sat, 3 Aug 2013 15:01:25 +0000 (01:01 +1000)
committerSebastian Dröge <slomo@circular-chaos.org>
Mon, 12 Aug 2013 13:24:31 +0000 (15:24 +0200)
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

gst/gio/gstgiobasesrc.c

index 0170664..afadf38 100644 (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;
+
+    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 (src->cache) {
+    if (src->cache)
       gst_buffer_unref (src->cache);
-      src->cache = NULL;
-    }
+    src->cache = newbuffer;
 
-    if (G_UNLIKELY (offset != src->position)) {
+    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;