]> git.sesse.net Git - vlc/commitdiff
Next Generation Buffer Manager, for PS plug-in.
authorChristophe Massiot <massiot@videolan.org>
Wed, 12 Dec 2001 11:18:38 +0000 (11:18 +0000)
committerChristophe Massiot <massiot@videolan.org>
Wed, 12 Dec 2001 11:18:38 +0000 (11:18 +0000)
include/config.h.in
include/input_ext-dec.h
include/input_ext-plugins.h
plugins/mpeg_system/input_ps.c

index 38e0c5ce5d95c7bb80469f8e4c24e5dbf497b62d..f39baf855185c83c25b4bf792857cd86b91425a3 100644 (file)
 /* Maximum length of a hostname or source name */
 #define INPUT_MAX_SOURCE_LENGTH         100
 
+/* Maximum memory the input is allowed to use (20 MB) */
+#define INPUT_MAX_ALLOCATION                   20971520
+
 /* Default network protocol */
 #define INPUT_NETWORK_PROTOCOL_VAR      "vlc_network_protocol"
 #define INPUT_NETWORK_PROTOCOL_DEFAULT  "ts"
index 99b0d4be00d324932f6ba3de5e75f4099df0551d..ae867f7e54ac76cf6f36ec49a5daff8044565f74 100644 (file)
@@ -2,7 +2,7 @@
  * input_ext-dec.h: structures exported to the VideoLAN decoders
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
- * $Id: input_ext-dec.h,v 1.42 2001/12/10 04:53:10 sam Exp $
+ * $Id: input_ext-dec.h,v 1.43 2001/12/12 11:18:38 massiot Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *          Michel Kaempf <maxx@via.ecp.fr>
@@ -44,6 +44,7 @@ typedef struct data_packet_s
 {
     /* Nothing before this line, the code relies on that */
     byte_t *                p_buffer;                     /* raw data packet */
+    byte_t *                p_buffer_end;
     long                    l_size;                           /* buffer size */
 
     /* Decoders information */
@@ -83,6 +84,9 @@ typedef struct pes_packet_s
        p_next fields of the data_packet_t struct) */
     data_packet_t *         p_first;      /* The first packet contained by this
                                            * PES (used by decoders). */
+
+    /* Chained list used by the input buffers manager */
+    struct pes_packet_s *   p_next;
 } pes_packet_t;
 
 /*****************************************************************************
index c1049647eb4db638ac8b0d14fc89145af1d1fbf8..5eb3e3a074a692dd8a727c8d0cacbb372a99aa7a 100644 (file)
@@ -3,7 +3,7 @@
  *                      but exported to plug-ins
  *****************************************************************************
  * Copyright (C) 1999, 2000, 2001 VideoLAN
- * $Id: input_ext-plugins.h,v 1.8 2001/12/10 04:53:10 sam Exp $
+ * $Id: input_ext-plugins.h,v 1.9 2001/12/12 11:18:38 massiot Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -197,6 +197,359 @@ void                    input_NetlistDeletePES( void *,
 void                    input_NetlistEnd( struct input_thread_s * );
 
 
+/*
+ * Optional Next Generation buffer manager
+ *
+ * Either buffers can only be used in one data packet (PS case), or buffers
+ * contain several data packets (DVD case). In the first case, buffers are
+ * embedded into data packets, otherwise they are allocated separately and
+ * shared with a refcount. --Meuuh
+ */
+
+/* Number of buffers for the calculation of the mean */
+#define INPUT_BRESENHAM_NB      50
+
+/* Flags */
+#define BUFFERS_NOFLAGS         0
+#define BUFFERS_SHARED          1
+#define BUFFERS_UNIQUE_SIZE     2
+
+/*****************************************************************************
+ * input_buffers_t: defines a LIFO per data type to keep
+ *****************************************************************************/
+#define PACKETS_LIFO( TYPE, NAME )                                           \
+struct                                                                      \
+{                                                                           \
+    TYPE * p_stack;                                                         \
+    unsigned int i_depth;                                                   \
+} NAME;
+
+#define BUFFERS_LIFO( TYPE, NAME )                                          \
+struct                                                                      \
+{                                                                           \
+    TYPE * p_stack; /* First item in the LIFO */                            \
+    unsigned int i_depth; /* Number of items in the LIFO */                 \
+    unsigned int i_average_size; /* Average size of the items (Bresenham) */\
+} NAME;
+
+#define DECLARE_BUFFERS_EMBEDDED( FLAGS, NB_LIFO )                          \
+typedef struct input_buffers_s                                              \
+{                                                                           \
+    vlc_mutex_t lock;                                                       \
+    PACKETS_LIFO( pes_packet_t, pes )                                       \
+    BUFFERS_LIFO( data_packet_t, data[NB_LIFO] )                            \
+    size_t i_allocated;                                                     \
+} input_buffers_t;
+
+#define DECLARE_BUFFERS_SHARED( FLAGS, NB_LIFO )                            \
+typedef struct data_buffer_s                                                \
+{                                                                           \
+    int i_refcount;                                                         \
+    int i_size;                                                             \
+    struct data_buffers_s * p_next;                                         \
+    byte_t payload_start;                                                   \
+} data_buffer_t;                                                            \
+                                                                            \
+typedef struct input_buffers_s                                              \
+{                                                                           \
+    vlc_mutex_t lock;                                                       \
+    PACKETS_LIFO( pes_packet_t, pes )                                       \
+    PACKETS_LIFO( data_packet_t, data )                                     \
+    BUFFERS_LIFO( data_buffers_t, buffers[NB_LIFO] )                        \
+    size_t i_allocated;                                                     \
+} input_buffers_t;
+
+
+/*****************************************************************************
+ * input_BuffersInit: initialize the cache structures, return a pointer to it
+ *****************************************************************************/
+#define DECLARE_BUFFERS_INIT( FLAGS, NB_LIFO )                              \
+static void * input_BuffersInit( void )                                     \
+{                                                                           \
+    input_buffers_t * p_buffers = malloc( sizeof( input_buffers_t ) );      \
+                                                                            \
+    if( p_buffers == NULL )                                                 \
+    {                                                                       \
+        return( NULL );                                                     \
+    }                                                                       \
+                                                                            \
+    memset( p_buffers, 0, sizeof( input_buffers_t ) );                      \
+    vlc_mutex_init( &p_buffers->lock );                                     \
+                                                                            \
+    return (void *)p_buffers;                                               \
+}
+
+/*****************************************************************************
+ * input_BuffersEnd: free all cached structures
+ *****************************************************************************/
+#define DECLARE_BUFFERS_END( FLAGS, NB_LIFO )                               \
+static void input_BuffersEnd( void * _p_buffers )                           \
+{                                                                           \
+    input_buffers_t *   p_buffers = (input_buffers_t *)_p_buffers;          \
+                                                                            \
+    if( _p_buffers != NULL )                                                \
+    {                                                                       \
+        pes_packet_t * p_pes = p_buffers->pes.p_stack;                      \
+        int i;                                                              \
+                                                                            \
+        if( p_main->b_stats )                                               \
+        {                                                                   \
+            int i;                                                          \
+            for( i = 0; i < NB_LIFO; i++ )                                  \
+            {                                                               \
+                intf_StatMsg(                                               \
+                     "input buffers stats: data[%d]: %d bytes, %d packets", \
+                              i, p_buffers->data[i].i_average_size,         \
+                              p_buffers->data[i].i_depth );                 \
+            }                                                               \
+        }                                                                   \
+                                                                            \
+        /* Free PES */                                                      \
+        while( p_pes != NULL )                                              \
+        {                                                                   \
+            pes_packet_t * p_next = p_pes->p_next;                          \
+            free( p_pes );                                                  \
+            p_pes = p_next;                                                 \
+        }                                                                   \
+                                                                            \
+        for( i = 0; i < NB_LIFO; i++ )                                      \
+        {                                                                   \
+            data_packet_t * p_data = p_buffers->data[i].p_stack;            \
+                                                                            \
+            /* Free data packets */                                         \
+            while( p_data != NULL )                                         \
+            {                                                               \
+                data_packet_t * p_next = p_data->p_next;                    \
+                p_buffers->i_allocated -= p_data->p_buffer_end              \
+                                            - p_data->p_buffer;             \
+                free( p_data );                                             \
+                p_data = p_next;                                            \
+            }                                                               \
+        }                                                                   \
+                                                                            \
+        if( p_buffers->i_allocated )                                        \
+        {                                                                   \
+            intf_ErrMsg( "input buffers error: %d bytes have not been"      \
+                         " freed, expect memory leak",                      \
+                         p_buffers->i_allocated );                          \
+        }                                                                   \
+                                                                            \
+        vlc_mutex_destroy( &p_buffers->lock );                              \
+        free( _p_buffers );                                                 \
+    }                                                                       \
+}
+
+/*****************************************************************************
+ * input_NewPacket: return a pointer to a data packet of the appropriate size
+ *****************************************************************************/
+#define DECLARE_BUFFERS_NEWPACKET( FLAGS, NB_LIFO )                         \
+static data_packet_t * input_NewPacket( void * _p_buffers, size_t i_size )  \
+{                                                                           \
+    input_buffers_t *   p_buffers = (input_buffers_t *)_p_buffers;          \
+    int                 i_select;                                           \
+    data_packet_t *     p_data;                                             \
+                                                                            \
+    /* Safety checks */                                                     \
+    if( i_size > INPUT_MAX_PACKET_SIZE )                                    \
+    {                                                                       \
+        intf_ErrMsg( "Packet too big (%d)", i_size );                       \
+        return NULL;                                                        \
+    }                                                                       \
+                                                                            \
+    vlc_mutex_lock( &p_buffers->lock );                                     \
+                                                                            \
+    if( p_buffers->i_allocated > INPUT_MAX_ALLOCATION )                     \
+    {                                                                       \
+        vlc_mutex_unlock( &p_buffers->lock );                               \
+        intf_ErrMsg( "INPUT_MAX_ALLOCATION reached (%d)",                   \
+                     p_buffers->i_allocated );                              \
+        return NULL;                                                        \
+    }                                                                       \
+                                                                            \
+    for( i_select = 0; i_select < NB_LIFO - 1; i_select++ )                 \
+    {                                                                       \
+        if( i_size <= (2 * p_buffers->data[i_select].i_average_size         \
+                      + p_buffers->data[i_select + 1].i_average_size) / 3 ) \
+        {                                                                   \
+            break;                                                          \
+        }                                                                   \
+    }                                                                       \
+                                                                            \
+    if( p_buffers->data[i_select].p_stack != NULL )                         \
+    {                                                                       \
+        /* Take the packet from the cache */                                \
+        p_data = p_buffers->data[i_select].p_stack;                         \
+        p_buffers->data[i_select].p_stack = p_data->p_next;                 \
+        p_buffers->data[i_select].i_depth--;                                \
+                                                                            \
+        /* Reallocate the packet if it is too small or too large */         \
+        if( p_data->p_buffer_end - p_data->p_buffer < i_size ||             \
+            p_data->p_buffer_end - p_data->p_buffer > 3 * i_size )          \
+        {                                                                   \
+            p_buffers->i_allocated -= p_data->p_buffer_end                  \
+                                        - p_data->p_buffer;                 \
+            p_data = realloc( p_data, sizeof( data_packet_t ) + i_size );   \
+            if( p_data == NULL )                                            \
+            {                                                               \
+                vlc_mutex_unlock( &p_buffers->lock );                       \
+                intf_ErrMsg( "Out of memory" );                             \
+                return NULL;                                                \
+            }                                                               \
+            p_data->p_buffer = (byte_t *)p_data + sizeof( data_packet_t );  \
+            p_data->p_buffer_end = p_data->p_buffer + i_size;               \
+            p_buffers->i_allocated += i_size;                               \
+        }                                                                   \
+    }                                                                       \
+    else                                                                    \
+    {                                                                       \
+        /* Allocate a new packet */                                         \
+        p_data = malloc( sizeof( data_packet_t ) + i_size );                \
+        if( p_data == NULL )                                                \
+        {                                                                   \
+            vlc_mutex_unlock( &p_buffers->lock );                           \
+            intf_ErrMsg( "Out of memory" );                                 \
+            return NULL;                                                    \
+        }                                                                   \
+        p_data->p_buffer = (byte_t *)p_data + sizeof( data_packet_t );      \
+        p_data->p_buffer_end = p_data->p_buffer + i_size;                   \
+        p_buffers->i_allocated += i_size;                                   \
+    }                                                                       \
+                                                                            \
+    vlc_mutex_unlock( &p_buffers->lock );                                   \
+                                                                            \
+    /* Initialize data */                                                   \
+    p_data->p_next = NULL;                                                  \
+    p_data->b_discard_payload = 0;                                          \
+    p_data->p_payload_start = p_data->p_buffer;                             \
+    p_data->p_payload_end = p_data->p_buffer + i_size;                      \
+                                                                            \
+    return( p_data );                                                       \
+}
+
+/*****************************************************************************
+ * input_DeletePacket: put a packet back into the cache
+ *****************************************************************************/
+#define DECLARE_BUFFERS_DELETEPACKET( FLAGS, NB_LIFO, DATA_CACHE_SIZE )     \
+static __inline__ void _input_DeletePacket( void * _p_buffers,              \
+                                            data_packet_t * p_data )        \
+{                                                                           \
+    input_buffers_t *   p_buffers = (input_buffers_t *)_p_buffers;          \
+    int                 i_select, i_size;                                   \
+                                                                            \
+    i_size = p_data->p_buffer_end - p_data->p_buffer;                       \
+    for( i_select = 0; i_select < NB_LIFO - 1; i_select++ )                 \
+    {                                                                       \
+        if( i_size <= (2 * p_buffers->data[i_select].i_average_size         \
+                      + p_buffers->data[i_select + 1].i_average_size) / 3 ) \
+        {                                                                   \
+            break;                                                          \
+        }                                                                   \
+    }                                                                       \
+                                                                            \
+    if( p_buffers->data[i_select].i_depth < DATA_CACHE_SIZE )               \
+    {                                                                       \
+        /* Cache not full : store the packet in it */                       \
+        p_data->p_next = p_buffers->data[i_select].p_stack;                 \
+        p_buffers->data[i_select].p_stack = p_data;                         \
+        p_buffers->data[i_select].i_depth++;                                \
+                                                                            \
+        /* Update Bresenham mean (very approximative) */                    \
+        p_buffers->data[i_select].i_average_size = ( i_size                 \
+            + p_buffers->data[i_select].i_average_size                      \
+              * (INPUT_BRESENHAM_NB - 1) )                                  \
+            / INPUT_BRESENHAM_NB;                                           \
+    }                                                                       \
+    else                                                                    \
+    {                                                                       \
+        p_buffers->i_allocated -= p_data->p_buffer_end - p_data->p_buffer;  \
+        free( p_data );                                                     \
+    }                                                                       \
+}                                                                           \
+                                                                            \
+static void input_DeletePacket( void * _p_buffers, data_packet_t * p_data ) \
+{                                                                           \
+    input_buffers_t *   p_buffers = (input_buffers_t *)_p_buffers;          \
+                                                                            \
+    vlc_mutex_lock( &p_buffers->lock );                                     \
+    _input_DeletePacket( _p_buffers, p_data );                              \
+    vlc_mutex_unlock( &p_buffers->lock );                                   \
+}
+
+/*****************************************************************************
+ * input_NewPES: return a pointer to a new PES packet
+ *****************************************************************************/
+#define DECLARE_BUFFERS_NEWPES( FLAGS, NB_LIFO )                            \
+static pes_packet_t * input_NewPES( void * _p_buffers )                     \
+{                                                                           \
+    input_buffers_t *   p_buffers = (input_buffers_t *)_p_buffers;          \
+    pes_packet_t *      p_pes;                                              \
+                                                                            \
+    vlc_mutex_lock( &p_buffers->lock );                                     \
+                                                                            \
+    if( p_buffers->pes.p_stack != NULL )                                    \
+    {                                                                       \
+        p_pes = p_buffers->pes.p_stack;                                     \
+        p_buffers->pes.p_stack = p_pes->p_next;                             \
+        p_buffers->pes.i_depth--;                                           \
+    }                                                                       \
+    else                                                                    \
+    {                                                                       \
+        p_pes = malloc( sizeof( pes_packet_t ) );                           \
+        if( p_pes == NULL )                                                 \
+        {                                                                   \
+            intf_ErrMsg( "Out of memory" );                                 \
+            vlc_mutex_unlock( &p_buffers->lock );                           \
+            return( NULL );                                                 \
+        }                                                                   \
+    }                                                                       \
+                                                                            \
+    vlc_mutex_unlock( &p_buffers->lock );                                   \
+                                                                            \
+    /* Initialize data */                                                   \
+    p_pes->p_next = NULL;                                                   \
+    p_pes->b_data_alignment = p_pes->b_discontinuity =                      \
+        p_pes->i_pts = p_pes->i_dts = 0;                                    \
+    p_pes->i_pes_size = 0;                                                  \
+    p_pes->p_first = NULL;                                                  \
+                                                                            \
+    return( p_pes );                                                        \
+}
+
+/*****************************************************************************
+ * input_DeletePES: put a pes and all data packets back into the cache
+ *****************************************************************************/
+#define DECLARE_BUFFERS_DELETEPES( FLAGS, NB_LIFO, PES_CACHE_SIZE )         \
+static void input_DeletePES( void * _p_buffers, pes_packet_t * p_pes )      \
+{                                                                           \
+    input_buffers_t *   p_buffers = (input_buffers_t *)_p_buffers;          \
+    data_packet_t *     p_data;                                             \
+                                                                            \
+    vlc_mutex_lock( &p_buffers->lock );                                     \
+                                                                            \
+    p_data = p_pes->p_first;                                                \
+    while( p_data != NULL )                                                 \
+    {                                                                       \
+        data_packet_t * p_next = p_data->p_next;                            \
+        _input_DeletePacket( _p_buffers, p_data );                          \
+        p_data = p_next;                                                    \
+    }                                                                       \
+                                                                            \
+    if( p_buffers->pes.i_depth < PES_CACHE_SIZE )                           \
+    {                                                                       \
+        /* Cache not full : store the packet in it */                       \
+        p_pes->p_next = p_buffers->pes.p_stack;                             \
+        p_buffers->pes.p_stack = p_pes;                                     \
+        p_buffers->pes.i_depth++;                                           \
+    }                                                                       \
+    else                                                                    \
+    {                                                                       \
+        free( p_pes );                                                      \
+    }                                                                       \
+                                                                            \
+    vlc_mutex_unlock( &p_buffers->lock );                                   \
+}
+
+
 /*
  * Optional MPEG demultiplexing
  */
index 5f795c12996fc5e9708ca6ed02c0a4b65e0fb3b0..242b9c3818acf471a8f7429dfbd1c456a7778f13 100644 (file)
@@ -2,7 +2,7 @@
  * input_ps.c: PS demux and packet management
  *****************************************************************************
  * Copyright (C) 1998-2001 VideoLAN
- * $Id: input_ps.c,v 1.2 2001/12/10 04:53:11 sam Exp $
+ * $Id: input_ps.c,v 1.3 2001/12/12 11:18:38 massiot Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *          Cyril Deguet <asmax@via.ecp.fr>
@@ -91,10 +91,20 @@ static void PSInit          ( struct input_thread_s * );
 static void PSEnd           ( struct input_thread_s * );
 static int  PSSetProgram    ( struct input_thread_s * , pgrm_descriptor_t * );
 static void PSSeek          ( struct input_thread_s *, off_t );
-static struct pes_packet_s *  NewPES    ( void * );
-static struct data_packet_s * NewPacket ( void *, size_t );
-static void DeletePacket    ( void *, struct data_packet_s * );
-static void DeletePES       ( void *, struct pes_packet_s * );
+
+/*****************************************************************************
+ * Declare a buffer manager
+ *****************************************************************************/
+#define FLAGS           BUFFERS_NOFLAGS
+#define NB_LIFO         2
+DECLARE_BUFFERS_EMBEDDED( FLAGS, NB_LIFO );
+DECLARE_BUFFERS_INIT( FLAGS, NB_LIFO );
+DECLARE_BUFFERS_END( FLAGS, NB_LIFO );
+DECLARE_BUFFERS_NEWPACKET( FLAGS, NB_LIFO );
+DECLARE_BUFFERS_DELETEPACKET( FLAGS, NB_LIFO, 150 );
+DECLARE_BUFFERS_NEWPES( FLAGS, NB_LIFO );
+DECLARE_BUFFERS_DELETEPES( FLAGS, NB_LIFO, 150 );
+
 
 /*****************************************************************************
  * Functions exported as capabilities. They are declared as static so that
@@ -113,10 +123,10 @@ void _M( input_getfunctions )( function_list_t * p_function_list )
     input.pf_set_program      = PSSetProgram;
     input.pf_read             = PSRead;
     input.pf_demux            = input_DemuxPS;
-    input.pf_new_packet       = NewPacket;
-    input.pf_new_pes          = NewPES;
-    input.pf_delete_packet    = DeletePacket;
-    input.pf_delete_pes       = DeletePES;
+    input.pf_new_packet       = input_NewPacket;
+    input.pf_new_pes          = input_NewPES;
+    input.pf_delete_packet    = input_DeletePacket;
+    input.pf_delete_pes       = input_DeletePES;
     input.pf_rewind           = NULL;
     input.pf_seek             = PSSeek;
 #undef input
@@ -158,65 +168,12 @@ static int PSProbe( probedata_t *p_data )
  *****************************************************************************/
 static void PSInit( input_thread_t * p_input )
 {
-    packet_cache_t *    p_packet_cache;
-
-    /* creates the packet cache structure */
-    p_packet_cache = malloc( sizeof(packet_cache_t) );
-    if ( p_packet_cache == NULL )
+    if( (p_input->p_method_data = input_BuffersInit()) == NULL )
     {
-        intf_ErrMsg( "Out of memory" );
         p_input->b_error = 1;
         return;
     }
-    p_input->p_method_data = (void *)p_packet_cache;
 
-    /* Initialize packet cache mutex */
-    vlc_mutex_init( &p_packet_cache->lock );
-    
-    /* allocates the data cache */
-    p_packet_cache->data.p_stack = malloc( DATA_CACHE_SIZE * 
-        sizeof(data_packet_t*) );
-    if ( p_packet_cache->data.p_stack == NULL )
-    {
-        intf_ErrMsg( "Out of memory" );
-        p_input->b_error = 1;
-        return;
-    }
-    p_packet_cache->data.l_index = 0;
-    
-    /* allocates the PES cache */
-    p_packet_cache->pes.p_stack = malloc( PES_CACHE_SIZE * 
-        sizeof(pes_packet_t*) );
-    if ( p_packet_cache->pes.p_stack == NULL )
-    {
-        intf_ErrMsg( "Out of memory" );
-        p_input->b_error = 1;
-        return;
-    }
-    p_packet_cache->pes.l_index = 0;
-    
-    /* allocates the small buffer cache */
-    p_packet_cache->smallbuffer.p_stack = malloc( SMALL_CACHE_SIZE * 
-        sizeof(packet_buffer_t) );
-    if ( p_packet_cache->smallbuffer.p_stack == NULL )
-    {
-        intf_ErrMsg( "Out of memory" );
-        p_input->b_error = 1;
-        return;
-    }
-    p_packet_cache->smallbuffer.l_index = 0;
-    
-    /* allocates the large buffer cache */
-    p_packet_cache->largebuffer.p_stack = malloc( LARGE_CACHE_SIZE * 
-        sizeof(packet_buffer_t) );
-    if ( p_packet_cache->largebuffer.p_stack == NULL )
-    {
-        intf_ErrMsg( "Out of memory" );
-        p_input->b_error = 1;
-        return;
-    }
-    p_packet_cache->largebuffer.l_index = 0;
-    
     if( p_input->p_stream == NULL )
     {
         /* Re-open the socket as a buffered FILE stream */
@@ -275,7 +232,7 @@ static void PSInit( input_thread_t * p_input )
             {
                 /* FIXME: use i_p_config_t */
                 input_ParsePS( p_input, pp_packets[i] );
-                DeletePacket( p_input->p_method_data, pp_packets[i] );
+                p_input->pf_delete_packet( p_input->p_method_data, pp_packets[i] );
             }
 
             /* File too big. */
@@ -388,22 +345,7 @@ static void PSInit( input_thread_t * p_input )
  *****************************************************************************/
 static void PSEnd( input_thread_t * p_input )
 {
-#define p_packet_cache ((packet_cache_t *)p_input->p_method_data)
-
-    vlc_mutex_destroy( &p_packet_cache->lock );
-
-    if( p_packet_cache->data.p_stack )
-        free( p_packet_cache->data.p_stack );
-    if( p_packet_cache->pes.p_stack )
-        free( p_packet_cache->pes.p_stack );
-    if( p_packet_cache->smallbuffer.p_stack )
-        free( p_packet_cache->smallbuffer.p_stack );
-    if( p_packet_cache->largebuffer.p_stack )
-        free( p_packet_cache->largebuffer.p_stack );
-
-#undef p_packet_cache
-
-    free( p_input->p_method_data );
+    input_BuffersEnd( p_input->p_method_data );
 }
 
 /*****************************************************************************
@@ -528,7 +470,8 @@ static int PSRead( input_thread_t * p_input,
         }
 
         /* Fetch a packet of the appropriate size. */
-        p_data = NewPacket( p_input->p_method_data, i_packet_size + 6 );
+        p_data = p_input->pf_new_packet( p_input->p_method_data,
+                                         i_packet_size + 6 );
         if( p_data == NULL )
         {
             intf_ErrMsg( "Out of memory" );
@@ -598,358 +541,3 @@ static void PSSeek( input_thread_t * p_input, off_t i_position )
     p_input->stream.p_selected_area->i_tell = i_position;
 }
 
-/*
- * Packet management utilities
- */
-
-
-/*****************************************************************************
- * NewPacket: allocates a data packet
- *****************************************************************************/
-static struct data_packet_s * NewPacket( void * p_packet_cache,
-                                         size_t l_size )
-{ 
-    packet_cache_t *   p_cache;
-    data_packet_t *    p_data;
-    long               l_index;
-
-    p_cache = (packet_cache_t *)p_packet_cache;
-
-#ifdef DEBUG
-    if ( p_cache == NULL )
-    {
-        intf_ErrMsg( "PPacket cache not initialized" );
-        return NULL;
-    }
-#endif
-
-    /* Safety check */
-    if( l_size > INPUT_MAX_PACKET_SIZE )
-    {
-        intf_ErrMsg( "Packet too big (%d)", l_size );
-        return NULL;
-    }
-
-    vlc_mutex_lock( &p_cache->lock );
-
-    /* Checks whether the data cache is empty */
-    if( p_cache->data.l_index == 0 )
-    {
-        /* Allocates a new packet */
-        p_data = malloc( sizeof(data_packet_t) );
-        if( p_data == NULL )
-        {
-            intf_ErrMsg( "Out of memory" );
-            vlc_mutex_unlock( &p_cache->lock );
-            return NULL;
-        }
-#ifdef TRACE_INPUT
-        intf_DbgMsg( "PS input: data packet allocated" );
-#endif
-    }
-    else
-    {
-        /* Takes the packet out from the cache */
-        if( (p_data = p_cache->data.p_stack[ -- p_cache->data.l_index ]) 
-            == NULL )
-        {
-            intf_ErrMsg( "NULL packet in the data cache" );
-            vlc_mutex_unlock( &p_cache->lock );
-            return NULL;
-        }
-    }
-    
-    if( l_size < MAX_SMALL_SIZE )
-    {
-        /* Small buffer */  
-   
-        /* Checks whether the buffer cache is empty */
-        if( p_cache->smallbuffer.l_index == 0 )
-        {
-            /* Allocates a new packet */
-            p_data->p_buffer = malloc( l_size );
-            if( p_data->p_buffer == NULL )
-            {
-                intf_DbgMsg( "Out of memory" );
-                free( p_data );
-                vlc_mutex_unlock( &p_cache->lock );
-                return NULL;
-            }
-#ifdef TRACE_INPUT
-            intf_DbgMsg( "PS input: small buffer allocated" );
-#endif
-            p_data->l_size = l_size;
-        }
-        else
-        {
-            /* Takes the packet out from the cache */
-            l_index = -- p_cache->smallbuffer.l_index;    
-            if( (p_data->p_buffer = p_cache->smallbuffer.p_stack[l_index].p_data)
-                == NULL )
-            {
-                intf_ErrMsg( "NULL packet in the small buffer cache" );
-                free( p_data );
-                vlc_mutex_unlock( &p_cache->lock );
-                return NULL;
-            }
-            /* Reallocates the packet if it is too small or too large */
-            if( p_cache->smallbuffer.p_stack[l_index].l_size < l_size ||
-                p_cache->smallbuffer.p_stack[l_index].l_size > 2*l_size )
-            {
-                p_data->p_buffer = realloc( p_data->p_buffer, l_size );
-                p_data->l_size = l_size;
-            }
-            else
-            {
-                p_data->l_size = p_cache->smallbuffer.p_stack[l_index].l_size;
-            }
-        }
-    }
-    else
-    {
-        /* Large buffer */  
-   
-        /* Checks whether the buffer cache is empty */
-        if( p_cache->largebuffer.l_index == 0 )
-        {
-            /* Allocates a new packet */
-            p_data->p_buffer = malloc( l_size );
-            if ( p_data->p_buffer == NULL )
-            {
-                intf_ErrMsg( "Out of memory" );
-                free( p_data );
-                vlc_mutex_unlock( &p_cache->lock );
-                return NULL;
-            }
-#ifdef TRACE_INPUT
-            intf_DbgMsg( "PS input: large buffer allocated" );
-#endif
-            p_data->l_size = l_size;
-        }
-        else
-        {
-            /* Takes the packet out from the cache */
-            l_index = -- p_cache->largebuffer.l_index;    
-            p_data->p_buffer = p_cache->largebuffer.p_stack[l_index].p_data;
-            if( p_data->p_buffer == NULL )
-            {
-                intf_ErrMsg( "NULL packet in the small buffer cache" );
-                free( p_data );
-                vlc_mutex_unlock( &p_cache->lock );
-                return NULL;
-            }
-            /* Reallocates the packet if it is too small or too large */
-            if( p_cache->largebuffer.p_stack[l_index].l_size < l_size ||
-                p_cache->largebuffer.p_stack[l_index].l_size > 2*l_size )
-            {
-                p_data->p_buffer = realloc( p_data->p_buffer, l_size );
-                p_data->l_size = l_size;
-            }
-            else
-            {
-                p_data->l_size = p_cache->largebuffer.p_stack[l_index].l_size;
-            }
-        }
-    }
-
-    vlc_mutex_unlock( &p_cache->lock );
-
-    /* Initialize data */
-    p_data->p_next = NULL;
-    p_data->b_discard_payload = 0;
-    p_data->p_payload_start = p_data->p_buffer;
-    p_data->p_payload_end = p_data->p_buffer + l_size;
-
-    return( p_data );
-
-}
-
-
-/*****************************************************************************
- * NewPES: allocates a pes packet
- *****************************************************************************/
-static pes_packet_t * NewPES( void * p_packet_cache )
-{
-    packet_cache_t *   p_cache;
-    pes_packet_t *     p_pes;
-
-    p_cache = (packet_cache_t *)p_packet_cache;
-
-#ifdef DEBUG
-    if ( p_cache == NULL )
-    {
-        intf_ErrMsg( "Packet cache not initialized" );
-        return NULL;
-    }
-#endif
-
-    vlc_mutex_lock( &p_cache->lock );
-
-    /* Checks whether the PES cache is empty */
-    if( p_cache->pes.l_index == 0 )
-    {
-        /* Allocates a new packet */
-        p_pes = malloc( sizeof(pes_packet_t) );
-        if( p_pes == NULL )
-        {
-            intf_DbgMsg( "Out of memory" );
-            vlc_mutex_unlock( &p_cache->lock );
-            return NULL;
-        }
-#ifdef TRACE_INPUT
-        intf_DbgMsg( "PS input: PES packet allocated" );
-#endif
-    }
-    else
-    {
-        /* Takes the packet out from the cache */
-        p_pes = p_cache->pes.p_stack[ -- p_cache->pes.l_index ];
-        if( p_pes == NULL )
-        {
-            intf_ErrMsg( "NULL packet in the data cache" );
-            vlc_mutex_unlock( &p_cache->lock );
-            return NULL;
-        }
-    }
-
-    vlc_mutex_unlock( &p_cache->lock );
-
-    p_pes->b_data_alignment = p_pes->b_discontinuity =
-        p_pes->i_pts = p_pes->i_dts = 0;
-    p_pes->i_pes_size = 0;
-    p_pes->p_first = NULL;
-
-    return( p_pes );
-    
-}
-
-/*****************************************************************************
- * DeletePacket: deletes a data packet
- *****************************************************************************/
-static void DeletePacket( void * p_packet_cache,
-                          data_packet_t * p_data )
-{
-    packet_cache_t *   p_cache;
-
-    p_cache = (packet_cache_t *)p_packet_cache;
-
-#ifdef DEBUG
-    if ( p_cache == NULL )
-    {
-        intf_ErrMsg( "Packet cache not initialized" );
-        return;
-    }
-#endif
-
-    ASSERT( p_data );
-
-    vlc_mutex_lock( &p_cache->lock );
-
-    /* Checks whether the data cache is full */
-    if ( p_cache->data.l_index < DATA_CACHE_SIZE )
-    {
-        /* Cache not full: store the packet in it */
-        p_cache->data.p_stack[ p_cache->data.l_index ++ ] = p_data;
-        /* Small buffer or large buffer? */
-        if ( p_data->l_size < MAX_SMALL_SIZE )
-        {
-            /* Checks whether the small buffer cache is full */
-            if ( p_cache->smallbuffer.l_index < SMALL_CACHE_SIZE )
-            {
-                p_cache->smallbuffer.p_stack[
-                    p_cache->smallbuffer.l_index ].l_size = p_data->l_size;
-                p_cache->smallbuffer.p_stack[
-                    p_cache->smallbuffer.l_index++ ].p_data = p_data->p_buffer;
-            }
-            else
-            {
-                ASSERT( p_data->p_buffer );
-                free( p_data->p_buffer );
-#ifdef TRACE_INPUT
-                intf_DbgMsg( "PS input: small buffer freed" );
-#endif
-            }
-        }
-        else
-        {
-            /* Checks whether the large buffer cache is full */
-            if ( p_cache->largebuffer.l_index < LARGE_CACHE_SIZE )
-            {
-                p_cache->largebuffer.p_stack[
-                    p_cache->largebuffer.l_index ].l_size = p_data->l_size;
-                p_cache->largebuffer.p_stack[
-                    p_cache->largebuffer.l_index++ ].p_data = p_data->p_buffer;
-            }
-            else
-            {
-                ASSERT( p_data->p_buffer );
-                free( p_data->p_buffer );
-#ifdef TRACE_INPUT
-                intf_DbgMsg( "PS input: large buffer freed" );
-#endif
-            }
-        }
-    }
-    else
-    {
-        /* Cache full: the packet must be freed */
-        free( p_data->p_buffer );
-        free( p_data );
-#ifdef TRACE_INPUT
-        intf_DbgMsg( "PS input: data packet freed" );
-#endif
-    }
-
-    vlc_mutex_unlock( &p_cache->lock );
-}
-
-/*****************************************************************************
- * DeletePES: deletes a PES packet and associated data packets
- *****************************************************************************/
-static void DeletePES( void * p_packet_cache, pes_packet_t * p_pes )
-{
-    packet_cache_t *    p_cache;
-    data_packet_t *     p_data;
-    data_packet_t *     p_next;
-
-    p_cache = (packet_cache_t *)p_packet_cache;
-
-#ifdef DEBUG
-    if ( p_cache == NULL )
-    {
-        intf_ErrMsg( "Packet cache not initialized" );
-        return;
-    }
-#endif
-
-    ASSERT( p_pes);
-
-    p_data = p_pes->p_first;
-
-    while( p_data != NULL )
-    {
-        p_next = p_data->p_next;
-        DeletePacket( p_cache, p_data );
-        p_data = p_next;
-    }
-
-    vlc_mutex_lock( &p_cache->lock );
-
-    /* Checks whether the PES cache is full */
-    if ( p_cache->pes.l_index < PES_CACHE_SIZE )
-    {
-        /* Cache not full: store the packet in it */
-        p_cache->pes.p_stack[ p_cache->pes.l_index ++ ] = p_pes;
-    }
-    else
-    {
-        /* Cache full: the packet must be freed */
-        free( p_pes );
-#ifdef TRACE_INPUT
-        intf_DbgMsg( "PS input: PES packet freed" );
-#endif
-    }
-
-    vlc_mutex_unlock( &p_cache->lock );
-}
-