[vlc-devel] [PATCH] restore cache_block equivalent code and remove bugs

Francois Cartegnie fcvlcdev at free.fr
Fri May 18 15:22:03 CEST 2018


Demonstrating the little benefit of using block bytestream
(which does not work with uint64) for that purpose,
once you have restored code equivalence and fixed bugs.

---
 modules/stream_filter/cache_block.c | 163 +++++++++++++++++++++++++++++-------
 1 file changed, 133 insertions(+), 30 deletions(-)

diff --git a/modules/stream_filter/cache_block.c b/modules/stream_filter/cache_block.c
index 86237de654..8901e97b31 100644
--- a/modules/stream_filter/cache_block.c
+++ b/modules/stream_filter/cache_block.c
@@ -67,6 +67,7 @@
 
 typedef struct
 {
+    uint64_t i_pos;           /* Current reading offset */
     block_bytestream_t cache; /* bytestream chain for storing cache */
 
     struct
@@ -74,6 +75,7 @@ typedef struct
         /* Stats for calculating speed */
         uint64_t read_bytes;
         uint64_t read_time;
+        int read_count;
     } stat;
 } stream_sys_t;
 
@@ -89,7 +91,7 @@ static int AStreamRefillBlock(stream_t *s)
         cache_size = sys->cache.i_total;
     }
     if (cache_size >= STREAM_CACHE_SIZE &&
-        sys->cache.p_chain != *sys->cache.pp_last)
+        sys->cache.p_chain != *sys->cache.pp_last) /* At least 2 packets */
     {
         /* Enough data, don't read more */
         return VLC_SUCCESS;
@@ -110,12 +112,15 @@ static int AStreamRefillBlock(stream_t *s)
         if (vlc_stream_Eof(s->s))
             return VLC_EGENERIC;
     }
-    sys->stat.read_time += mdate() - start;
-    size_t added_bytes;
-    block_ChainProperties( b, NULL, &added_bytes, NULL );
-    sys->stat.read_bytes += added_bytes;
 
     block_BytestreamPush( &sys->cache, b );
+    sys->stat.read_time += mdate() - start;
+    for( ; b; b = b->p_next )
+    {
+        sys->stat.read_bytes += b->i_buffer;
+        sys->stat.read_count++;
+    }
+
     return VLC_SUCCESS;
 }
 
@@ -158,6 +163,8 @@ static void AStreamPrebufferBlock(stream_t *s)
         }
 
         block_BytestreamPush( &sys->cache, b);
+        for( ; b; b=b->p_next )
+            sys->stat.read_count++;
 
         if (first)
         {
@@ -175,6 +182,8 @@ static void AStreamControlReset(stream_t *s)
 {
     stream_sys_t *sys = s->p_sys;
 
+    sys->i_pos = 0;
+
     block_BytestreamEmpty( &sys->cache );
 
     /* Do the prebuffering */
@@ -184,52 +193,142 @@ static void AStreamControlReset(stream_t *s)
 static int AStreamSeekBlock(stream_t *s, uint64_t i_pos)
 {
     stream_sys_t *sys = s->p_sys;
+    bool b_seek;
 
-    if( block_SkipBytes( &sys->cache, i_pos) == VLC_SUCCESS )
-        return VLC_SUCCESS;
+    if(i_pos >= sys->i_pos && i_pos - sys->i_pos < SIZE_MAX)
+    {
+        size_t i_offset = i_pos - sys->i_pos;
+        if(block_SkipBytes( &sys->cache, i_offset) == VLC_SUCCESS)
+        {
+            sys->i_pos = i_pos;
+            return VLC_SUCCESS;
+        }
+    }
+
+    /* We may need to seek or to read data */
+    if (i_pos < sys->i_pos)
+    {
+        bool b_aseek;
+        vlc_stream_Control(s->s, STREAM_CAN_SEEK, &b_aseek);
 
-    /* Not enought bytes, empty and seek */
-    /* Do the access seek */
-    if (vlc_stream_Seek(s->s, i_pos)) return VLC_EGENERIC;
+        if (!b_aseek)
+        {
+            msg_Err(s, "backward seeking impossible (access not seekable)");
+            return VLC_EGENERIC;
+        }
 
-    block_BytestreamEmpty( &sys->cache );
+        b_seek = true;
+    }
+    else
+    {
+        bool b_aseek, b_aseekfast;
+        uint64_t i_offset = i_pos - sys->i_pos;
 
-    /* Refill a block */
-    if (AStreamRefillBlock(s))
-        return VLC_EGENERIC;
+        vlc_stream_Control(s->s, STREAM_CAN_SEEK, &b_aseek);
+        vlc_stream_Control(s->s, STREAM_CAN_FASTSEEK, &b_aseekfast);
 
-    return VLC_SUCCESS;
+        size_t i_cached = block_BytestreamRemaining(&sys->cache);
+        if (!b_aseek)
+        {
+            b_seek = false;
+            msg_Warn(s, "%"PRId64" bytes need to be skipped "
+                      "(access non seekable)", i_offset - i_cached);
+        }
+        else
+        {
+            uint64_t i_skip = i_offset - i_cached;
+
+            /* Avg bytes per packets */
+            uint64_t i_avg = sys->stat.read_bytes / sys->stat.read_count;
+            /* TODO compute a seek cost instead of fixed threshold */
+            int i_th = b_aseekfast ? 1 : 5;
+
+            if (i_skip <= i_th * i_avg &&
+                i_skip < STREAM_CACHE_SIZE)
+                b_seek = false;
+            else
+                b_seek = true;
+
+            msg_Dbg(s, "b_seek=%d th*avg=%"PRIu64" skip=%"PRIu64,
+                     b_seek, i_th*i_avg, i_skip);
+        }
+    }
+
+    if( b_seek )
+    {
+        /* Do the access seek */
+        if (vlc_stream_Seek(s->s, i_pos)) return VLC_EGENERIC;
+
+        /* Release data */
+        block_BytestreamEmpty(&sys->cache);
+
+        /* Refill a block */
+        if (AStreamRefillBlock(s))
+            return VLC_EGENERIC;
+
+        return VLC_SUCCESS;
+    }
+    else
+    {
+        uint64_t i_offset = i_pos - sys->i_pos;
+        while(i_offset > 0)
+        {
+            size_t i_cached = block_BytestreamRemaining(&sys->cache);
+            if(i_cached > 0)
+            {
+                if(i_offset > i_cached)
+                {
+                    block_BytestreamEmpty(&sys->cache);
+                    i_offset -= i_cached;
+                    i_cached = 0;
+                }
+                else
+                {
+                    size_t i_skip = i_offset < SIZE_MAX ? i_offset : SIZE_MAX;
+                    assert(!block_SkipBytes(&sys->cache, i_skip));
+                    i_offset -= i_skip;
+                    i_cached -= i_skip;
+                }
+            }
+
+            if (i_cached > i_offset && AStreamRefillBlock(s))
+                break;
+        }
+
+        sys->i_pos = i_pos - i_offset;
+
+        return (sys->i_pos == i_pos) ? VLC_SUCCESS: VLC_EGENERIC;
+    }
+
+    vlc_assert_unreachable();
+    return VLC_EGENERIC;
 }
 
 static ssize_t AStreamReadBlock(stream_t *s, void *buf, size_t len)
 {
     stream_sys_t *sys = s->p_sys;
 
-    ssize_t i_current = block_BytestreamRemaining( &sys->cache );
-    size_t i_copy = VLC_CLIP((size_t)i_current, 0, len);
+    size_t i_remain = block_BytestreamRemaining(&sys->cache);
 
     /**
      * we should not signal end-of-file if we have not exhausted
-     * the cache. i_copy == 0 just means that the cache currently does
+     * the cache. i_remain == 0 just means that the cache currently does
      * not contain data at the offset that we want, not EOF.
      **/
-    if( i_copy == 0 )
+
+    /* Get a new block if needed */
+    if(i_remain == 0 && len > 0)
     {
-        /* Return EOF if we are unable to refill cache, most likely
-         * really EOF */
-        if( AStreamRefillBlock(s) == VLC_EGENERIC )
+        if(AStreamRefillBlock(s))
             return 0;
+        i_remain = block_BytestreamRemaining(&sys->cache);
     }
 
+    size_t i_copy = VLC_CLIP(i_remain, 0, len);
     /* Copy data */
-    if( block_GetBytes( &sys->cache, buf, i_copy ) )
-        return -1;
-
-
-    /* If we ended up on refill, try to read refilled cache */
-    if( i_copy == 0 && sys->cache.p_chain )
-        return AStreamReadBlock( s, buf, len );
+    assert(!block_GetBytes(&sys->cache, buf, i_copy));
 
+    sys->i_pos += i_copy;
     return i_copy;
 }
 
@@ -289,8 +388,12 @@ static int Open(vlc_object_t *obj)
 
     msg_Dbg(s, "Using block method for AStream*");
 
-    /* Init all fields of sys->block */
+    /* Init all fields of sys->cache */
     block_BytestreamInit( &sys->cache );
+    sys->i_pos = 0;
+    sys->stat.read_bytes = 0;
+    sys->stat.read_time = 0;
+    sys->stat.read_count = 0;
 
     s->p_sys = sys;
     /* Do the prebuffering */
-- 
2.14.3



More information about the vlc-devel mailing list