]> git.sesse.net Git - vlc/blobdiff - src/misc/block.c
aout_BufferAlloc : returns the allocated buffer
[vlc] / src / misc / block.c
index cbe15a805d8204d708df10c84dab0c4740dab2c0..9ffc6733d8755c82d9a9442a5cff2c8e4e962861 100644 (file)
@@ -2,7 +2,7 @@
  * block.c: Data blocks management functions
  *****************************************************************************
  * Copyright (C) 2003-2004 the VideoLAN team
- * $Id$
+ * Copyright (C) 2007-2009 RĂ©mi Denis-Courmont
  *
  * Authors: Laurent Aimar <fenrir@videolan.org>
  *
@@ -30,6 +30,7 @@
 
 #include <vlc_common.h>
 #include <sys/stat.h>
+#include <assert.h>
 #include "vlc_block.h"
 
 /**
@@ -63,6 +64,7 @@ void block_Init( block_t *restrict b, void *buf, size_t size )
     b->i_dts = VLC_TS_INVALID;
     b->i_length = 0;
     b->i_rate = 0;
+    b->i_samples = 0;
     b->p_buffer = buf;
     b->i_buffer = size;
 #ifndef NDEBUG
@@ -75,6 +77,17 @@ static void BlockRelease( block_t *p_block )
     free( p_block );
 }
 
+static void BlockMetaCopy( block_t *restrict out, const block_t *in )
+{
+    out->p_next    = in->p_next;
+    out->i_dts     = in->i_dts;
+    out->i_pts     = in->i_pts;
+    out->i_flags   = in->i_flags;
+    out->i_length  = in->i_length;
+    out->i_rate    = in->i_rate;
+    out->i_samples = in->i_samples;
+}
+
 /* Memory alignment */
 #define BLOCK_ALIGN        16
 /* Initial size of reserved header and footer */
@@ -111,9 +124,10 @@ block_t *block_Alloc( size_t i_size )
 block_t *block_Realloc( block_t *p_block, ssize_t i_prebody, size_t i_body )
 {
     block_sys_t *p_sys = (block_sys_t *)p_block;
-    ssize_t i_buffer_size = i_prebody + i_body;
+    size_t requested = i_prebody + i_body;
 
-    if( i_buffer_size <= 0 )
+    /* Corner case: empty block requested */
+    if( i_prebody <= 0 && i_body <= (size_t)(-i_prebody) )
     {
         block_Release( p_block );
         return NULL;
@@ -132,55 +146,76 @@ block_t *block_Realloc( block_t *p_block, ssize_t i_prebody, size_t i_body )
         p_sys = (block_sys_t *)p_block;
     }
 
-    /* Adjust reserved header if there is enough room */
-    if( p_block->p_buffer - i_prebody > p_sys->p_allocated_buffer &&
-        p_block->p_buffer - i_prebody < p_sys->p_allocated_buffer +
-        p_sys->i_allocated_buffer )
+    uint8_t *p_start = p_sys->p_allocated_buffer;
+    uint8_t *p_end = p_sys->p_allocated_buffer + p_sys->i_allocated_buffer;
+
+    assert( p_block->p_buffer + p_block->i_buffer <= p_end );
+    assert( p_block->p_buffer >= p_start );
+
+    /* Corner case: the current payload is discarded completely */
+    if( i_prebody <= 0 && p_block->i_buffer <= (size_t)-i_prebody )
+         p_block->i_buffer = 0; /* discard current payload */
+    if( p_block->i_buffer == 0 )
+    {
+        size_t available = p_end - p_start;
+
+        if( requested <= available )
+        {   /* Enough room: recycle buffer */
+            size_t extra = available - requested;
+
+            p_block->p_buffer = p_start + (extra / 2);
+            p_block->i_buffer = requested;
+            return p_block;
+        }
+        /* Not enough room: allocate a new buffer */
+        block_t *p_rea = block_Alloc( requested );
+        if( p_rea )
+            BlockMetaCopy( p_rea, p_block );
+        block_Release( p_block );
+        return p_rea;
+    }
+
+    /* First, shrink payload */
+
+    /* Pull payload start */
+    if( i_prebody < 0 )
     {
+        assert( p_block->i_buffer >= (size_t)-i_prebody );
         p_block->p_buffer -= i_prebody;
         p_block->i_buffer += i_prebody;
+        i_body += i_prebody;
         i_prebody = 0;
     }
 
-    /* Adjust payload size if there is enough room */
-    if( p_block->p_buffer + i_body < p_sys->p_allocated_buffer +
-        p_sys->i_allocated_buffer )
-    {
-        p_block->i_buffer = i_buffer_size;
-        i_body = 0;
-    }
+    /* Trim payload end */
+    if( p_block->i_buffer > i_body )
+        p_block->i_buffer = i_body;
 
-    /* Not enough room, reallocate the buffer */
-    if( i_body > 0 || i_prebody > 0 )
+    /* Second, reallocate the buffer if we lack space. This is done now to
+     * minimize the payload size for memory copy. */
+    assert( i_prebody >= 0 );
+    if( (size_t)(p_block->p_buffer - p_start) < (size_t)i_prebody
+     || (size_t)(p_end - p_block->p_buffer) < i_body )
     {
         /* FIXME: this is really dumb, we should use realloc() */
-        block_t *p_rea = block_New( NULL, i_buffer_size );
-
+        block_t *p_rea = block_Alloc( requested );
         if( p_rea )
         {
-            p_rea->i_dts     = p_block->i_dts;
-            p_rea->i_pts     = p_block->i_pts;
-            p_rea->i_flags   = p_block->i_flags;
-            p_rea->i_length  = p_block->i_length;
-            p_rea->i_rate    = p_block->i_rate;
-            p_rea->i_samples = p_block->i_samples;
-
-            memcpy( p_rea->p_buffer + i_prebody, p_block->p_buffer,
-                    __MIN( p_block->i_buffer, p_rea->i_buffer - i_prebody ) );
+            BlockMetaCopy( p_rea, p_block );
+            p_rea->p_buffer += i_prebody;
+            p_rea->i_buffer -= i_prebody;
+            memcpy( p_rea->p_buffer, p_block->p_buffer, p_block->i_buffer );
         }
-
         block_Release( p_block );
-
-        return p_rea;
+        p_block = p_rea;
     }
-
+    else
     /* We have a very large reserved footer now? Release some of it.
-     * XXX it may not keep the algniment of p_buffer */
-    if( (p_sys->p_allocated_buffer + p_sys->i_allocated_buffer) -
-        (p_block->p_buffer + p_block->i_buffer) > BLOCK_WASTE_SIZE )
+     * XXX it might not preserve the alignment of p_buffer */
+    if( p_end - (p_block->p_buffer + i_body) > BLOCK_WASTE_SIZE )
     {
-        const ptrdiff_t i_prebody = p_block->p_buffer - p_sys->p_allocated_buffer;
-        const size_t i_new = i_prebody + p_block->i_buffer + 1 * BLOCK_PADDING_SIZE;
+        const ptrdiff_t i_prebody = p_block->p_buffer - p_start;
+        const size_t i_new = requested + 1 * BLOCK_PADDING_SIZE;
         block_sys_t *p_new = realloc( p_sys, sizeof (*p_sys) + i_new );
 
         if( p_new != NULL )
@@ -191,6 +226,23 @@ block_t *block_Realloc( block_t *p_block, ssize_t i_prebody, size_t i_body )
             p_block->p_buffer = &p_sys->p_allocated_buffer[i_prebody];
         }
     }
+
+    /* NOTE: p_start and p_end are corrupted from this point */
+
+    /* Third, expand payload */
+
+    /* Push payload start */
+    if( i_prebody > 0 )
+    {
+        p_block->p_buffer -= i_prebody;
+        p_block->i_buffer += i_prebody;
+        i_body += i_prebody;
+        i_prebody = 0;
+    }
+
+    /* Expand payload to requested size */
+    p_block->i_buffer = i_body;
+
     return p_block;
 }