* all: rework of the input.
authorLaurent Aimar <fenrir@videolan.org>
Tue, 22 Jun 2004 19:29:57 +0000 (19:29 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Tue, 22 Jun 2004 19:29:57 +0000 (19:29 +0000)
13 files changed:
src/input/access.c
src/input/clock.c [new file with mode: 0644]
src/input/control.c
src/input/decoder.c [new file with mode: 0644]
src/input/demux.c
src/input/es_out.c
src/input/input.c
src/input/input_clock.c [deleted file]
src/input/input_dec.c [deleted file]
src/input/input_ext-plugins.c [deleted file]
src/input/input_programs.c [deleted file]
src/input/stream.c
src/input/subtitles.c

index 49c51b2..dfca13c 100644 (file)
 #include <vlc/vlc.h>
 #include <vlc/input.h>
 
-#include "ninput.h"
-
-int access_vaControl( input_thread_t *p_input, int i_query, va_list args )
-{
-    if( p_input->pf_access_control )
-    {
-        return p_input->pf_access_control( p_input, i_query, args );
-    }
-    return VLC_EGENERIC;
-}
-
-int access_Control( input_thread_t *p_input, int i_query, ...  )
-{
-    va_list args;
-    int     i_result;
-
-    va_start( args, i_query );
-    i_result = access_vaControl( p_input, i_query, args );
-    va_end( args );
-
-    return i_result;
-}
-
-int access_vaControlDefault( input_thread_t *p_input, int i_query, va_list args )
-{
-    return VLC_EGENERIC;
-}
+#include "input_internal.h"
 
 /*****************************************************************************
  * access2_New:
diff --git a/src/input/clock.c b/src/input/clock.c
new file mode 100644 (file)
index 0000000..e39e653
--- /dev/null
@@ -0,0 +1,348 @@
+/*****************************************************************************
+ * input_clock.c: Clock/System date convertions, stream management
+ *****************************************************************************
+ * Copyright (C) 1999-2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Christophe Massiot <massiot@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>
+#include <vlc/vlc.h>
+
+#include <vlc/input.h>
+#include "input_internal.h"
+
+/*
+ * DISCUSSION : SYNCHRONIZATION METHOD
+ *
+ * In some cases we can impose the pace of reading (when reading from a
+ * file or a pipe), and for the synchronization we simply sleep() until
+ * it is time to deliver the packet to the decoders. When reading from
+ * the network, we must be read at the same pace as the server writes,
+ * otherwise the kernel's buffer will trash packets. The risk is now to
+ * overflow the input buffers in case the server goes too fast, that is
+ * why we do these calculations :
+ *
+ * We compute a mean for the pcr because we want to eliminate the
+ * network jitter and keep the low frequency variations. The mean is
+ * in fact a low pass filter and the jitter is a high frequency signal
+ * that is why it is eliminated by the filter/average.
+ *
+ * The low frequency variations enable us to synchronize the client clock
+ * with the server clock because they represent the time variation between
+ * the 2 clocks. Those variations (ie the filtered pcr) are used to compute
+ * the presentation dates for the audio and video frames. With those dates
+ * we can decode (or trash) the MPEG2 stream at "exactly" the same rate
+ * as it is sent by the server and so we keep the synchronization between
+ * the server and the client.
+ *
+ * It is a very important matter if you want to avoid underflow or overflow
+ * in all the FIFOs, but it may be not enough.
+ */
+
+/* p_input->i_cr_average : Maximum number of samples used to compute the
+ * dynamic average value.
+ * We use the following formula :
+ * new_average = (old_average * c_average + new_sample_value) / (c_average +1)
+ */
+
+
+static void ClockNewRef( input_clock_t * p_pgrm,
+                         mtime_t i_clock, mtime_t i_sysdate );
+
+/*****************************************************************************
+ * Constants
+ *****************************************************************************/
+
+/* Maximum gap allowed between two CRs. */
+#define CR_MAX_GAP 2000000
+
+/* Latency introduced on DVDs with CR == 0 on chapter change - this is from
+ * my dice --Meuuh */
+#define CR_MEAN_PTS_GAP 300000
+
+/*****************************************************************************
+ * ClockToSysdate: converts a movie clock to system date
+ *****************************************************************************/
+static mtime_t ClockToSysdate( input_thread_t *p_input,
+                               input_clock_t *cl, mtime_t i_clock )
+{
+    mtime_t     i_sysdate = 0;
+
+    if( cl->i_synchro_state == SYNCHRO_OK )
+    {
+        i_sysdate = (mtime_t)(i_clock - cl->cr_ref)
+                        * (mtime_t)p_input->i_rate
+                        * (mtime_t)300;
+        i_sysdate /= 27;
+        i_sysdate /= 1000;
+        i_sysdate += (mtime_t)cl->sysdate_ref;
+    }
+
+    return( i_sysdate );
+}
+
+/*****************************************************************************
+ * ClockCurrent: converts current system date to clock units
+ *****************************************************************************
+ * Caution : the synchro state must be SYNCHRO_OK for this to operate.
+ *****************************************************************************/
+static mtime_t ClockCurrent( input_thread_t *p_input,
+                             input_clock_t *cl )
+{
+    return( (mdate() - cl->sysdate_ref) * 27 * INPUT_RATE_DEFAULT
+             / p_input->i_rate / 300
+             + cl->cr_ref );
+}
+
+/*****************************************************************************
+ * ClockNewRef: writes a new clock reference
+ *****************************************************************************/
+static void ClockNewRef( input_clock_t *cl,
+                         mtime_t i_clock, mtime_t i_sysdate )
+{
+    cl->cr_ref = i_clock;
+    cl->sysdate_ref = i_sysdate ;
+}
+
+/*****************************************************************************
+ * input_ClockInit: reinitializes the clock reference after a stream
+ *                  discontinuity
+ *****************************************************************************/
+void input_ClockInit( input_clock_t *cl, vlc_bool_t b_master, int i_cr_average )
+{
+    cl->i_synchro_state = SYNCHRO_START;
+
+    cl->last_cr = 0;
+    cl->last_pts = 0;
+    cl->cr_ref = 0;
+    cl->sysdate_ref = 0;
+    cl->delta_cr = 0;
+    cl->c_average_count = 0;
+
+    cl->i_cr_average = i_cr_average;
+
+    cl->b_master = b_master;
+}
+
+#if 0
+/*****************************************************************************
+ * input_ClockManageControl: handles the messages from the interface
+ *****************************************************************************
+ * Returns UNDEF_S if nothing happened, PAUSE_S if the stream was paused
+ *****************************************************************************/
+int input_ClockManageControl( input_thread_t * p_input,
+                               input_clock_t *cl, mtime_t i_clock )
+{
+#if 0
+    vlc_value_t val;
+    int i_return_value = UNDEF_S;
+
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+
+    if( p_input->stream.i_new_status == PAUSE_S )
+    {
+        int i_old_status;
+
+        vlc_mutex_lock( &p_input->stream.control.control_lock );
+        i_old_status = p_input->stream.control.i_status;
+        p_input->stream.control.i_status = PAUSE_S;
+        vlc_mutex_unlock( &p_input->stream.control.control_lock );
+
+        vlc_cond_wait( &p_input->stream.stream_wait,
+                       &p_input->stream.stream_lock );
+        ClockNewRef( p_pgrm, i_clock, p_pgrm->last_pts > mdate() ?
+                                      p_pgrm->last_pts : mdate() );
+
+        if( p_input->stream.i_new_status == PAUSE_S )
+        {
+            /* PAUSE_S undoes the pause state: Return to old state. */
+            vlc_mutex_lock( &p_input->stream.control.control_lock );
+            p_input->stream.control.i_status = i_old_status;
+            vlc_mutex_unlock( &p_input->stream.control.control_lock );
+
+            p_input->stream.i_new_status = UNDEF_S;
+            p_input->stream.i_new_rate = UNDEF_S;
+        }
+
+        /* We handle i_new_status != PAUSE_S below... */
+
+        i_return_value = PAUSE_S;
+    }
+
+    if( p_input->stream.i_new_status != UNDEF_S )
+    {
+        vlc_mutex_lock( &p_input->stream.control.control_lock );
+
+        p_input->stream.control.i_status = p_input->stream.i_new_status;
+
+        ClockNewRef( p_pgrm, i_clock,
+                     ClockToSysdate( p_input, p_pgrm, i_clock ) );
+
+        if( p_input->stream.control.i_status == PLAYING_S )
+        {
+            p_input->stream.control.i_rate = DEFAULT_RATE;
+            p_input->stream.control.b_mute = 0;
+        }
+        else
+        {
+            p_input->stream.control.i_rate = p_input->stream.i_new_rate;
+            p_input->stream.control.b_mute = 1;
+
+            /* Feed the audio decoders with a NULL packet to avoid
+             * discontinuities. */
+            input_EscapeAudioDiscontinuity( p_input );
+        }
+
+        val.i_int = p_input->stream.control.i_rate;
+        var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
+
+        val.i_int = p_input->stream.control.i_status;
+        var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
+
+        p_input->stream.i_new_status = UNDEF_S;
+        p_input->stream.i_new_rate = UNDEF_S;
+
+        vlc_mutex_unlock( &p_input->stream.control.control_lock );
+    }
+
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+    return( i_return_value );
+#endif
+    return UNDEF_S;
+}
+#endif
+
+/*****************************************************************************
+ * input_ClockSetPCR: manages a clock reference
+ *****************************************************************************/
+void input_ClockSetPCR( input_thread_t *p_input,
+                        input_clock_t *cl, mtime_t i_clock )
+{
+    if( ( cl->i_synchro_state != SYNCHRO_OK ) ||
+        ( i_clock == 0 && cl->last_cr != 0 ) )
+    {
+        /* Feed synchro with a new reference point. */
+        ClockNewRef( cl, i_clock,
+                     cl->last_pts + CR_MEAN_PTS_GAP > mdate() ?
+                     cl->last_pts + CR_MEAN_PTS_GAP : mdate() );
+        cl->i_synchro_state = SYNCHRO_OK;
+
+        if( p_input->b_can_pace_control && cl->b_master )
+        {
+            cl->last_cr = i_clock;
+            if( !p_input->b_out_pace_control )
+            {
+                mtime_t i_wakeup = ClockToSysdate( p_input, cl, i_clock );
+                while( (i_wakeup - mdate()) / CLOCK_FREQ > 1 )
+                {
+                    msleep( CLOCK_FREQ );
+                    if( p_input->b_die ) i_wakeup = mdate();
+                }
+                mwait( i_wakeup );
+            }
+        }
+        else
+        {
+            cl->last_cr = 0;
+            cl->delta_cr = 0;
+            cl->c_average_count = 0;
+        }
+    }
+    else
+    {
+        if ( cl->last_cr != 0 &&
+               (    (cl->last_cr - i_clock) > CR_MAX_GAP
+                 || (cl->last_cr - i_clock) < - CR_MAX_GAP ) )
+        {
+            /* Stream discontinuity, for which we haven't received a
+             * warning from the stream control facilities (dd-edited
+             * stream ?). */
+            msg_Warn( p_input, "clock gap, unexpected stream discontinuity" );
+            input_ClockInit( cl, cl->b_master, cl->i_cr_average );
+            /* FIXME needed ? */
+#if 0
+            input_EscapeDiscontinuity( p_input );
+#endif
+        }
+
+        cl->last_cr = i_clock;
+
+        if( p_input->b_can_pace_control && cl->b_master )
+        {
+            /* Wait a while before delivering the packets to the decoder.
+             * In case of multiple programs, we arbitrarily follow the
+             * clock of the selected program. */
+            if( !p_input->b_out_pace_control )
+            {
+                mtime_t i_wakeup = ClockToSysdate( p_input, cl, i_clock );
+                while( (i_wakeup - mdate()) / CLOCK_FREQ > 1 )
+                {
+                    msleep( CLOCK_FREQ );
+                    if( p_input->b_die ) i_wakeup = mdate();
+                }
+                mwait( i_wakeup );
+            }
+            /* FIXME Not needed anymore ? */
+#if 0
+            /* Now take into account interface changes. */
+            input_ClockManageControl( p_input, cl, i_clock );
+#endif
+        }
+        else
+        {
+            /* Smooth clock reference variations. */
+            mtime_t     i_extrapoled_clock = ClockCurrent( p_input, cl );
+
+            /* Bresenham algorithm to smooth variations. */
+            if( cl->c_average_count == cl->i_cr_average )
+            {
+                cl->delta_cr = ( cl->delta_cr
+                                        * (cl->i_cr_average - 1)
+                                      + ( i_extrapoled_clock - i_clock ) )
+                                    / cl->i_cr_average;
+            }
+            else
+            {
+                cl->delta_cr = ( cl->delta_cr
+                                        * cl->c_average_count
+                                      + ( i_extrapoled_clock - i_clock ) )
+                                    / (cl->c_average_count + 1);
+                cl->c_average_count++;
+            }
+        }
+    }
+}
+
+/*****************************************************************************
+ * input_ClockGetTS: manages a PTS or DTS
+ *****************************************************************************/
+mtime_t input_ClockGetTS( input_thread_t * p_input,
+                          input_clock_t *cl, mtime_t i_ts )
+{
+    if( cl->i_synchro_state != SYNCHRO_OK )
+        return 0;
+
+    cl->last_pts = ClockToSysdate( p_input, cl, i_ts + cl->delta_cr );
+    return cl->last_pts + p_input->i_pts_delay;
+}
+
index b439470..da23735 100644 (file)
  *****************************************************************************/
 
 #include <stdlib.h>
-#include <stdio.h>
 #include <vlc/vlc.h>
 #include <vlc/input.h>
 
+#include "input_internal.h"
 #include "vlc_playlist.h"
 
-#include "ninput.h"
-#include "../../modules/demux/util/sub.h"
-
-struct input_thread_sys_t
-{
-    /* subtitles */
-    int              i_sub;
-    subtitle_demux_t **sub;
-    int64_t          i_stop_time;
-};
 
 static void UpdateBookmarksOption( input_thread_t * );
 
@@ -64,7 +54,6 @@ int input_Control( input_thread_t *p_input, int i_query, ...  )
 
 int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
 {
-    int     i_ret;
     seekpoint_t *p_bkmk, ***ppp_bkmk;
     int i_bkmk = 0;
     int *pi_bkmk;
@@ -75,54 +64,50 @@ int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
     double f, *pf;
     int64_t i_64, *pi_64;
 
-    vlc_mutex_lock( &p_input->stream.stream_lock );
     switch( i_query )
     {
         case INPUT_GET_POSITION:
             pf = (double*)va_arg( args, double * );
             *pf = var_GetFloat( p_input, "position" );
-            i_ret = VLC_SUCCESS;
-            break;
+            return VLC_SUCCESS;
+
         case INPUT_SET_POSITION:
             f = (double)va_arg( args, double );
-            i_ret = var_SetFloat( p_input, "position", f );
-            break;
+            return var_SetFloat( p_input, "position", f );
 
         case INPUT_GET_LENGTH:
             pi_64 = (int64_t*)va_arg( args, int64_t * );
             *pi_64 = var_GetTime( p_input, "length" );
-            i_ret = VLC_SUCCESS;
-            break;
+            return VLC_SUCCESS;
+
         case INPUT_GET_TIME:
             pi_64 = (int64_t*)va_arg( args, int64_t * );
             *pi_64 = var_GetTime( p_input, "time" );
-            i_ret = VLC_SUCCESS;
-            break;
+            return VLC_SUCCESS;
+
         case INPUT_SET_TIME:
             i_64 = (int64_t)va_arg( args, int64_t );
-            i_ret = var_SetTime( p_input, "time", i_64 );
-            break;
+            return var_SetTime( p_input, "time", i_64 );
 
         case INPUT_GET_RATE:
             pi_int = (int*)va_arg( args, int * );
             *pi_int = var_GetInteger( p_input, "rate" );
-            i_ret = VLC_SUCCESS;
-            break;
+            return VLC_SUCCESS;
+
         case INPUT_SET_RATE:
             i_int = (int)va_arg( args, int );
-            i_ret = var_SetInteger( p_input, "rate", i_int );
-            break;
+            return var_SetInteger( p_input, "rate", i_int );
 
         case INPUT_GET_STATE:
             pi_int = (int*)va_arg( args, int * );
             *pi_int = var_GetInteger( p_input, "state" );
-            i_ret = VLC_SUCCESS;
-            break;
+            return VLC_SUCCESS;
+
         case INPUT_SET_STATE:
             i_int = (int)va_arg( args, int );
-            i_ret = var_SetInteger( p_input, "state", i_int );
-            break;
+            return var_SetInteger( p_input, "state", i_int );
 
+#if 0
         case INPUT_ADD_OPTION:
         {
             psz_option = (char *)va_arg( args, char * );
@@ -130,7 +115,7 @@ int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
             i_ret = VLC_EGENERIC;
 
             vlc_mutex_lock( &p_input->p_item->lock );
-            /* Check if option already exists */            
+            /* Check if option already exists */
             for( i = 0; i < p_input->p_item->i_options; i++ )
             {
                 if( !strncmp( p_input->p_item->ppsz_options[i], psz_option,
@@ -500,22 +485,33 @@ int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
                 i_ret = VLC_EGENERIC;
             }
             break;
-
+#endif
+        case INPUT_GET_BOOKMARKS:
+        case INPUT_CLEAR_BOOKMARKS:
+        case INPUT_ADD_BOOKMARK:
+        case INPUT_CHANGE_BOOKMARK:
+        case INPUT_DEL_BOOKMARK:
+        case INPUT_SET_BOOKMARK:
+        case INPUT_ADD_OPTION:
+        case INPUT_ADD_INFO:
+        case INPUT_GET_INFO:
+        case INPUT_SET_NAME:
+        case INPUT_GET_SUBDELAY:
+        case INPUT_SET_SUBDELAY:
+            /* FIXME */
+            msg_Err( p_input, "unimplemented query in input_vaControl" );
         default:
             msg_Err( p_input, "unknown query in input_vaControl" );
-            i_ret = VLC_EGENERIC;
-            break;
+            return VLC_EGENERIC;
     }
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    return i_ret;
 }
 
 static void UpdateBookmarksOption( input_thread_t *p_input )
 {
     int i, i_len = 0;
     char *psz_value = NULL, *psz_next = NULL;
-
+    /* FIXME */
+#if 0
     vlc_mutex_unlock( &p_input->stream.stream_lock );
 
     for( i = 0; i < p_input->i_bookmarks; i++ )
@@ -546,4 +542,5 @@ static void UpdateBookmarksOption( input_thread_t *p_input )
                    psz_value ? psz_value : "" );
 
     vlc_mutex_lock( &p_input->stream.stream_lock );
+#endif
 }
diff --git a/src/input/decoder.c b/src/input/decoder.c
new file mode 100644 (file)
index 0000000..671a002
--- /dev/null
@@ -0,0 +1,820 @@
+/*****************************************************************************
+ * decoder.c: Functions for the management of decoders
+ *****************************************************************************
+ * Copyright (C) 1999-2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Christophe Massiot <massiot@via.ecp.fr>
+ *          Gildas Bazin <gbazin@netcourrier.com>
+ *          Laurent Aimar <fenrir@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>
+#include <vlc/vlc.h>
+
+#include <vlc/decoder.h>
+#include <vlc/vout.h>
+#include <vlc/input.h>
+
+#include "stream_output.h"
+#include "input_internal.h"
+
+static decoder_t * CreateDecoder( input_thread_t *, es_format_t *, int );
+static void        DeleteDecoder( decoder_t * );
+
+static int         DecoderThread( decoder_t * );
+static int         DecoderDecode( decoder_t * p_dec, block_t *p_block );
+
+/* Buffers allocation callbacks for the decoders */
+static aout_buffer_t *aout_new_buffer( decoder_t *, int );
+static void aout_del_buffer( decoder_t *, aout_buffer_t * );
+
+static picture_t *vout_new_buffer( decoder_t * );
+static void vout_del_buffer( decoder_t *, picture_t * );
+static void vout_link_picture( decoder_t *, picture_t * );
+static void vout_unlink_picture( decoder_t *, picture_t * );
+
+static es_format_t null_es_format = {0};
+
+struct decoder_owner_sys_t
+{
+    vlc_bool_t      b_own_thread;
+
+    input_thread_t  *p_input;
+
+    aout_instance_t *p_aout;
+    aout_input_t    *p_aout_input;
+
+    vout_thread_t   *p_vout;
+
+    sout_instance_t         *p_sout;
+    sout_packetizer_input_t *p_sout_input;
+
+    /* Some decoders require already packetized data (ie. not truncated) */
+    decoder_t *p_packetizer;
+
+    /* Current format in use by the output */
+    video_format_t video;
+    audio_format_t audio;
+    es_format_t    sout;
+
+    /* fifo */
+    block_fifo_t *p_fifo;
+};
+
+
+/**
+ * Spawns a new decoder thread
+ *
+ * \param p_input the input thread
+ * \param p_es the es descriptor
+ * \return the spawned decoder object
+ */
+decoder_t *input_DecoderNew( input_thread_t *p_input,
+                             es_format_t *fmt, vlc_bool_t b_force_decoder )
+{
+    decoder_t   *p_dec = NULL;
+    vlc_value_t val;
+
+    /* If we are in sout mode, search for packetizer module */
+    if( p_input->p_sout && !b_force_decoder )
+    {
+        /* Create the decoder configuration structure */
+        p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_PACKETIZER );
+        if( p_dec == NULL )
+        {
+            msg_Err( p_input, "could not create packetizer" );
+            return NULL;
+        }
+    }
+    else
+    {
+        /* Create the decoder configuration structure */
+        p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_DECODER );
+        if( p_dec == NULL )
+        {
+            msg_Err( p_input, "could not create decoder" );
+            return NULL;
+        }
+    }
+
+    if( !p_dec->p_module )
+    {
+        msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n"
+                 "VLC probably does not support this sound or video format.",
+                 (char*)&p_dec->fmt_in.i_codec );
+
+        DeleteDecoder( p_dec );
+        vlc_object_destroy( p_dec );
+        return NULL;
+    }
+
+    if( p_input->p_sout && p_input->input.b_can_pace_control &&
+        !b_force_decoder )
+    {
+        msg_Dbg( p_input, "stream out mode -> no decoder thread" );
+        p_dec->p_owner->b_own_thread = VLC_FALSE;
+    }
+    else
+    {
+        var_Get( p_input, "minimize-threads", &val );
+        p_dec->p_owner->b_own_thread = !val.b_bool;
+    }
+
+    if( p_dec->p_owner->b_own_thread )
+    {
+        int i_priority;
+        if( fmt->i_cat == AUDIO_ES )
+            i_priority = VLC_THREAD_PRIORITY_AUDIO;
+        else
+            i_priority = VLC_THREAD_PRIORITY_VIDEO;
+
+        /* Spawn the decoder thread */
+        if( vlc_thread_create( p_dec, "decoder", DecoderThread,
+                               i_priority, VLC_FALSE ) )
+        {
+            msg_Err( p_dec, "cannot spawn decoder thread \"%s\"",
+                             p_dec->p_module->psz_object_name );
+            module_Unneed( p_dec, p_dec->p_module );
+            DeleteDecoder( p_dec );
+            vlc_object_destroy( p_dec );
+            return NULL;
+        }
+    }
+
+    return p_dec;
+}
+
+/**
+ * Kills a decoder thread and waits until it's finished
+ *
+ * \param p_input the input thread
+ * \param p_es the es descriptor
+ * \return nothing
+ */
+void input_DecoderDelete( decoder_t *p_dec )
+{
+    p_dec->b_die = VLC_TRUE;
+
+    if( p_dec->p_owner->b_own_thread )
+    {
+        /* Make sure the thread leaves the function by
+         * sending it an empty block. */
+        block_t *p_block = block_New( p_dec, 0 );
+        input_DecoderDecode( p_dec, p_block );
+
+        vlc_thread_join( p_dec );
+
+        /* Don't module_Unneed() here because of the dll loader that wants
+         * close() in the same thread than open()/decode() */
+    }
+    else
+    {
+        module_Unneed( p_dec, p_dec->p_module );
+    }
+
+    /* Delete decoder configuration */
+    DeleteDecoder( p_dec );
+
+    /* Delete the decoder */
+    vlc_object_destroy( p_dec );
+}
+
+/**
+ * Put a block_t in the decoder's fifo.
+ *
+ * \param p_dec the decoder object
+ * \param p_block the data block
+ */
+void input_DecoderDecode( decoder_t * p_dec, block_t *p_block )
+{
+    if( p_dec->p_owner->b_own_thread )
+    {
+        block_FifoPut( p_dec->p_owner->p_fifo, p_block );
+
+        if( p_dec->p_owner->p_input->b_out_pace_control )
+        {
+            /* FIXME !!!!! */
+            while( !p_dec->b_die && !p_dec->b_error &&
+                   p_dec->p_owner->p_fifo->i_depth > 10 )
+            {
+                msleep( 1000 );
+            }
+        }
+    }
+    else
+    {
+        if( p_dec->b_error || p_block->i_buffer <= 0 )
+        {
+            block_Release( p_block );
+        }
+        else
+        {
+            DecoderDecode( p_dec, p_block );
+        }
+    }
+}
+
+void input_DecoderDiscontinuity( decoder_t * p_dec )
+{
+    block_t *p_null;
+
+    /* Empty the fifo */
+    if( p_dec->p_owner->b_own_thread )
+    {
+        block_FifoEmpty( p_dec->p_owner->p_fifo );
+    }
+
+    /* Send a special block */
+    p_null = block_New( p_dec, 128 );
+    p_null->i_flags |= BLOCK_FLAG_DISCONTINUITY;
+    memset( p_null->p_buffer, 0, p_null->i_buffer );
+
+    input_DecoderDecode( p_dec, p_null );
+}
+
+#if 0
+/**
+ * Create a NULL packet for padding in case of a data loss
+ *
+ * \param p_input the input thread
+ * \param p_es es descriptor
+ * \return nothing
+ */
+static void input_NullPacket( input_thread_t * p_input,
+                              es_descriptor_t * p_es )
+{
+#if 0
+    block_t *p_block = block_New( p_input, PADDING_PACKET_SIZE );
+    if( p_block )
+    {
+        memset( p_block->p_buffer, 0, PADDING_PACKET_SIZE );
+        p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
+
+        block_FifoPut( p_es->p_dec->p_owner->p_fifo, p_block );
+    }
+#endif
+}
+
+/**
+ * Send a NULL packet to the decoders
+ *
+ * \param p_input the input thread
+ * \return nothing
+ */
+void input_EscapeDiscontinuity( input_thread_t * p_input )
+{
+#if 0
+    unsigned int i_es, i;
+
+    for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
+    {
+        es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
+
+        if( p_es->p_dec != NULL )
+        {
+            for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
+            {
+                input_NullPacket( p_input, p_es );
+            }
+        }
+    }
+#endif
+}
+
+/**
+ * Send a NULL packet to the audio decoders
+ *
+ * \param p_input the input thread
+ * \return nothing
+ */
+void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
+{
+#if 0
+    unsigned int i_es, i;
+
+    for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
+    {
+        es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
+
+        if( p_es->p_dec != NULL && p_es->i_cat == AUDIO_ES )
+        {
+            for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
+            {
+                input_NullPacket( p_input, p_es );
+            }
+        }
+    }
+#endif
+}
+#endif
+
+/**
+ * Create a decoder object
+ *
+ * \param p_input the input thread
+ * \param p_es the es descriptor
+ * \param i_object_type Object type as define in include/vlc_objects.h
+ * \return the decoder object
+ */
+static decoder_t * CreateDecoder( input_thread_t *p_input,
+                                  es_format_t *fmt, int i_object_type )
+{
+    decoder_t *p_dec;
+
+    p_dec = vlc_object_create( p_input, i_object_type );
+    if( p_dec == NULL )
+    {
+        msg_Err( p_input, "out of memory" );
+        return NULL;
+    }
+
+    p_dec->pf_decode_audio = 0;
+    p_dec->pf_decode_video = 0;
+    p_dec->pf_decode_sub = 0;
+    p_dec->pf_packetize = 0;
+
+    /* Initialize the decoder fifo */
+    p_dec->p_module = NULL;
+
+
+    es_format_Copy( &p_dec->fmt_in, fmt );
+    es_format_Copy( &p_dec->fmt_out, &null_es_format );
+
+    /* Allocate our private structure for the decoder */
+    p_dec->p_owner = malloc( sizeof( decoder_owner_sys_t ) );
+    if( p_dec->p_owner == NULL )
+    {
+        msg_Err( p_dec, "out of memory" );
+        return NULL;
+    }
+    p_dec->p_owner->b_own_thread = VLC_TRUE;
+    p_dec->p_owner->p_input = p_input;
+    p_dec->p_owner->p_aout = NULL;
+    p_dec->p_owner->p_aout_input = NULL;
+    p_dec->p_owner->p_vout = NULL;
+    p_dec->p_owner->p_sout = p_input->p_sout;
+    p_dec->p_owner->p_sout_input = NULL;
+    p_dec->p_owner->p_packetizer = NULL;
+
+
+    /* decoder fifo */
+    if( ( p_dec->p_owner->p_fifo = block_FifoNew( p_dec ) ) == NULL )
+    {
+        msg_Err( p_dec, "out of memory" );
+        return NULL;
+    }
+    /* Set buffers allocation callbacks for the decoders */
+    p_dec->pf_aout_buffer_new = aout_new_buffer;
+    p_dec->pf_aout_buffer_del = aout_del_buffer;
+    p_dec->pf_vout_buffer_new = vout_new_buffer;
+    p_dec->pf_vout_buffer_del = vout_del_buffer;
+    p_dec->pf_picture_link    = vout_link_picture;
+    p_dec->pf_picture_unlink  = vout_unlink_picture;
+
+    vlc_object_attach( p_dec, p_input );
+
+    /* Find a suitable decoder/packetizer module */
+    if( i_object_type == VLC_OBJECT_DECODER )
+        p_dec->p_module = module_Need( p_dec, "decoder", "$codec", 0 );
+    else
+        p_dec->p_module = module_Need( p_dec, "packetizer", "$packetizer", 0 );
+
+    /* Check if decoder requires already packetized data */
+    if( i_object_type == VLC_OBJECT_DECODER &&
+        p_dec->b_need_packetized && !p_dec->fmt_in.b_packetized )
+    {
+        p_dec->p_owner->p_packetizer =
+            vlc_object_create( p_input, VLC_OBJECT_PACKETIZER );
+        if( p_dec->p_owner->p_packetizer )
+        {
+            es_format_Copy( &p_dec->p_owner->p_packetizer->fmt_in,
+                            &p_dec->fmt_in );
+
+            es_format_Copy( &p_dec->p_owner->p_packetizer->fmt_out,
+                            &null_es_format );
+
+            vlc_object_attach( p_dec->p_owner->p_packetizer, p_input );
+
+            p_dec->p_owner->p_packetizer->p_module =
+                module_Need( p_dec->p_owner->p_packetizer,
+                             "packetizer", "$packetizer", 0 );
+
+            if( !p_dec->p_owner->p_packetizer->p_module )
+            {
+                es_format_Clean( &p_dec->p_owner->p_packetizer->fmt_in );
+                vlc_object_detach( p_dec->p_owner->p_packetizer );
+                vlc_object_destroy( p_dec->p_owner->p_packetizer );
+            }
+        }
+    }
+
+    return p_dec;
+}
+
+/**
+ * The decoding main loop
+ *
+ * \param p_dec the decoder
+ * \return 0
+ */
+static int DecoderThread( decoder_t * p_dec )
+{
+    block_t *p_block;
+
+    /* The decoder's main loop */
+    while( !p_dec->b_die && !p_dec->b_error )
+    {
+        if( ( p_block = block_FifoGet( p_dec->p_owner->p_fifo ) ) == NULL )
+        {
+            p_dec->b_error = 1;
+            break;
+        }
+        if( DecoderDecode( p_dec, p_block ) != VLC_SUCCESS )
+        {
+            break;
+        }
+    }
+
+    while( !p_dec->b_die )
+    {
+        /* Trash all received PES packets */
+        p_block = block_FifoGet( p_dec->p_owner->p_fifo );
+        if( p_block ) block_Release( p_block );
+    }
+
+    /* We do it here because of the dll loader that wants close() in the
+     * same thread than open()/decode() */
+    module_Unneed( p_dec, p_dec->p_module );
+
+    return 0;
+}
+
+/**
+ * Decode a block
+ *
+ * \param p_dec the decoder object
+ * \param p_block the block to decode
+ * \return VLC_SUCCESS or an error code
+ */
+static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
+{
+    if( p_block->i_buffer <= 0 )
+    {
+        block_Release( p_block );
+        return VLC_SUCCESS;
+    }
+
+    if( p_dec->i_object_type == VLC_OBJECT_PACKETIZER )
+    {
+        block_t *p_sout_block;
+
+        while( (p_sout_block = p_dec->pf_packetize( p_dec, &p_block )) )
+        {
+            if( !p_dec->p_owner->p_sout_input )
+            {
+                es_format_Copy( &p_dec->p_owner->sout, &p_dec->fmt_out );
+
+                p_dec->p_owner->sout.i_group =p_dec->fmt_in.i_group;
+                p_dec->p_owner->sout.i_id = p_dec->fmt_in.i_id;
+                if( p_dec->fmt_in.psz_language )
+                {
+                    p_dec->p_owner->sout.psz_language =
+                        strdup( p_dec->fmt_in.psz_language );
+                }
+
+                p_dec->p_owner->p_sout_input =
+                    sout_InputNew( p_dec->p_owner->p_sout,
+                                   &p_dec->p_owner->sout );
+
+                if( p_dec->p_owner->p_sout_input == NULL )
+                {
+                    msg_Err( p_dec, "cannot create packetizer output" );
+                    p_dec->b_error = VLC_TRUE;
+
+                    while( p_sout_block )
+                    {
+                        block_t *p_next = p_sout_block->p_next;
+                        block_Release( p_sout_block );
+                        p_sout_block = p_next;
+                    }
+                    break;
+                }
+            }
+
+            while( p_sout_block )
+            {
+                block_t       *p_next = p_sout_block->p_next;
+
+                p_sout_block->p_next = NULL;
+
+                sout_InputSendBuffer( p_dec->p_owner->p_sout_input,
+                                      p_sout_block );
+
+                p_sout_block = p_next;
+            }
+
+            /* For now it's enough, as only sout inpact on this flag */
+            if( p_dec->p_owner->p_sout->i_out_pace_nocontrol > 0 &&
+                p_dec->p_owner->p_input->b_out_pace_control )
+            {
+                msg_Dbg( p_dec, "switching to synch mode" );
+                p_dec->p_owner->p_input->b_out_pace_control = VLC_FALSE;
+            }
+            else if( p_dec->p_owner->p_sout->i_out_pace_nocontrol <= 0 &&
+                     !p_dec->p_owner->p_input->b_out_pace_control )
+            {
+                msg_Dbg( p_dec, "switching to asynch mode" );
+                p_dec->p_owner->p_input->b_out_pace_control = VLC_TRUE;
+            }
+        }
+    }
+    else if( p_dec->fmt_in.i_cat == AUDIO_ES )
+    {
+        aout_buffer_t *p_aout_buf;
+
+        if( p_dec->p_owner->p_packetizer )
+        {
+            block_t *p_packetized_block;
+            decoder_t *p_packetizer = p_dec->p_owner->p_packetizer;
+
+            while( (p_packetized_block =
+                    p_packetizer->pf_packetize( p_packetizer, &p_block )) )
+            {
+                while( (p_aout_buf =
+                        p_dec->pf_decode_audio( p_dec, &p_packetized_block )) )
+                {
+                    aout_DecPlay( p_dec->p_owner->p_aout,
+                                  p_dec->p_owner->p_aout_input, p_aout_buf );
+                }
+            }
+        }
+        else while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) )
+        {
+            aout_DecPlay( p_dec->p_owner->p_aout,
+                          p_dec->p_owner->p_aout_input, p_aout_buf );
+        }
+    }
+    else if( p_dec->fmt_in.i_cat == VIDEO_ES )
+    {
+        picture_t *p_pic;
+
+        if( p_dec->p_owner->p_packetizer )
+        {
+            block_t *p_packetized_block;
+            decoder_t *p_packetizer = p_dec->p_owner->p_packetizer;
+
+            while( (p_packetized_block =
+                    p_packetizer->pf_packetize( p_packetizer, &p_block )) )
+            {
+                while( (p_pic =
+                        p_dec->pf_decode_video( p_dec, &p_packetized_block )) )
+                {
+                    vout_DatePicture( p_dec->p_owner->p_vout, p_pic,
+                                      p_pic->date );
+                    vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
+                }
+            }
+        }
+        else while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) )
+        {
+            vout_DatePicture( p_dec->p_owner->p_vout, p_pic, p_pic->date );
+            vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
+        }
+    }
+    else if( p_dec->fmt_in.i_cat == SPU_ES )
+    {
+        p_dec->pf_decode_sub( p_dec, &p_block );
+    }
+    else
+    {
+        msg_Err( p_dec, "unknown ES format" );
+        p_dec->b_error = 1;
+    }
+
+    return p_dec->b_error ? VLC_EGENERIC : VLC_SUCCESS;
+}
+
+/**
+ * Destroys a decoder object
+ *
+ * \param p_dec the decoder object
+ * \return nothing
+ */
+static void DeleteDecoder( decoder_t * p_dec )
+{
+    vlc_object_detach( p_dec );
+
+    msg_Dbg( p_dec, "killing decoder fourcc `%4.4s', %d PES in FIFO",
+             (char*)&p_dec->fmt_in.i_codec,
+             p_dec->p_owner->p_fifo->i_depth );
+
+    /* Free all packets still in the decoder fifo. */
+    block_FifoEmpty( p_dec->p_owner->p_fifo );
+    block_FifoRelease( p_dec->p_owner->p_fifo );
+
+   /* Cleanup */
+    if( p_dec->p_owner->p_aout_input )
+        aout_DecDelete( p_dec->p_owner->p_aout, p_dec->p_owner->p_aout_input );
+
+    if( p_dec->p_owner->p_vout )
+    {
+        int i_pic;
+
+#define p_pic p_dec->p_owner->p_vout->render.pp_picture[i_pic]
+        /* Hack to make sure all the the pictures are freed by the decoder */
+        for( i_pic = 0; i_pic < p_dec->p_owner->p_vout->render.i_pictures;
+             i_pic++ )
+        {
+            if( p_pic->i_status == RESERVED_PICTURE )
+                vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
+            if( p_pic->i_refcount > 0 )
+                vout_UnlinkPicture( p_dec->p_owner->p_vout, p_pic );
+        }
+#undef p_pic
+
+        /* We are about to die. Reattach video output to p_vlc. */
+        vout_Request( p_dec, p_dec->p_owner->p_vout, 0, 0, 0, 0 );
+    }
+
+    if( p_dec->p_owner->p_sout_input )
+    {
+        sout_InputDelete( p_dec->p_owner->p_sout_input );
+        es_format_Clean( &p_dec->p_owner->sout );
+    }
+
+    es_format_Clean( &p_dec->fmt_in );
+    es_format_Clean( &p_dec->fmt_out );
+
+    if( p_dec->p_owner->p_packetizer )
+    {
+        module_Unneed( p_dec->p_owner->p_packetizer,
+                       p_dec->p_owner->p_packetizer->p_module );
+        es_format_Clean( &p_dec->p_owner->p_packetizer->fmt_in );
+        es_format_Clean( &p_dec->p_owner->p_packetizer->fmt_out );
+        vlc_object_detach( p_dec->p_owner->p_packetizer );
+        vlc_object_destroy( p_dec->p_owner->p_packetizer );
+    }
+
+    free( p_dec->p_owner );
+}
+
+/*****************************************************************************
+ * Buffers allocation callbacks for the decoders
+ *****************************************************************************/
+static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples )
+{
+    decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner;
+    aout_buffer_t *p_buffer;
+
+    if( p_sys->p_aout_input != NULL &&
+        ( p_dec->fmt_out.audio.i_rate != p_sys->audio.i_rate ||
+          p_dec->fmt_out.audio.i_original_channels !=
+              p_sys->audio.i_original_channels ||
+          p_dec->fmt_out.audio.i_bytes_per_frame !=
+              p_sys->audio.i_bytes_per_frame ) )
+    {
+        /* Parameters changed, restart the aout */
+        aout_DecDelete( p_sys->p_aout, p_sys->p_aout_input );
+        p_sys->p_aout_input = NULL;
+    }
+
+    if( p_sys->p_aout_input == NULL )
+    {
+        p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
+        p_sys->audio = p_dec->fmt_out.audio;
+        p_sys->p_aout_input =
+            aout_DecNew( p_dec, &p_sys->p_aout, &p_sys->audio );
+        if( p_sys->p_aout_input == NULL )
+        {
+            msg_Err( p_dec, "failed to create audio output" );
+            p_dec->b_error = VLC_TRUE;
+            return NULL;
+        }
+        p_dec->fmt_out.audio.i_bytes_per_frame =
+            p_sys->audio.i_bytes_per_frame;
+    }
+
+    p_buffer = aout_DecNewBuffer( p_sys->p_aout, p_sys->p_aout_input,
+                                  i_samples );
+
+    return p_buffer;
+}
+
+static void aout_del_buffer( decoder_t *p_dec, aout_buffer_t *p_buffer )
+{
+    aout_DecDeleteBuffer( p_dec->p_owner->p_aout,
+                          p_dec->p_owner->p_aout_input, p_buffer );
+}
+
+static picture_t *vout_new_buffer( decoder_t *p_dec )
+{
+    decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner;
+    picture_t *p_pic;
+
+    if( p_sys->p_vout == NULL ||
+        p_dec->fmt_out.video.i_width != p_sys->video.i_width ||
+        p_dec->fmt_out.video.i_height != p_sys->video.i_height ||
+        p_dec->fmt_out.video.i_chroma != p_sys->video.i_chroma ||
+        p_dec->fmt_out.video.i_aspect != p_sys->video.i_aspect )
+    {
+        if( !p_dec->fmt_out.video.i_width ||
+            !p_dec->fmt_out.video.i_height )
+        {
+            /* Can't create a new vout without display size */
+            return NULL;
+        }
+
+        p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
+        p_sys->video = p_dec->fmt_out.video;
+
+        p_sys->p_vout = vout_Request( p_dec, p_sys->p_vout,
+                                      p_sys->video.i_width,
+                                      p_sys->video.i_height,
+                                      p_sys->video.i_chroma,
+                                      p_sys->video.i_aspect );
+
+        if( p_sys->p_vout == NULL )
+        {
+            msg_Err( p_dec, "failed to create video output" );
+            p_dec->b_error = VLC_TRUE;
+            return NULL;
+        }
+    }
+
+    /* Get a new picture */
+    while( !(p_pic = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 ) ) )
+    {
+        int i_pic, i_ready_pic = 0;
+
+        if( p_dec->b_die || p_dec->b_error )
+        {
+            return NULL;
+        }
+
+#define p_pic p_dec->p_owner->p_vout->render.pp_picture[i_pic]
+        /* Check the decoder doesn't leak pictures */
+        for( i_pic = 0; i_pic < p_dec->p_owner->p_vout->render.i_pictures;
+             i_pic++ )
+        {
+            if( p_pic->i_status == READY_PICTURE && i_ready_pic++ > 0 ) break;
+
+            if( p_pic->i_status != DISPLAYED_PICTURE &&
+                p_pic->i_status != RESERVED_PICTURE &&
+                p_pic->i_status != READY_PICTURE ) break;
+
+            if( !p_pic->i_refcount ) break;
+        }
+        if( i_pic == p_dec->p_owner->p_vout->render.i_pictures )
+        {
+            msg_Err( p_dec, "decoder is leaking pictures, resetting the heap" );
+
+            /* Just free all the pictures */
+            for( i_pic = 0; i_pic < p_dec->p_owner->p_vout->render.i_pictures;
+                 i_pic++ )
+            {
+                if( p_pic->i_status == RESERVED_PICTURE )
+                    vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
+                if( p_pic->i_refcount > 0 )
+                vout_UnlinkPicture( p_dec->p_owner->p_vout, p_pic );
+            }
+        }
+#undef p_pic
+
+        msleep( VOUT_OUTMEM_SLEEP );
+    }
+
+    return p_pic;
+}
+
+static void vout_del_buffer( decoder_t *p_dec, picture_t *p_pic )
+{
+    vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
+}
+
+static void vout_link_picture( decoder_t *p_dec, picture_t *p_pic )
+{
+    vout_LinkPicture( p_dec->p_owner->p_vout, p_pic );
+}
+
+static void vout_unlink_picture( decoder_t *p_dec, picture_t *p_pic )
+{
+    vout_UnlinkPicture( p_dec->p_owner->p_vout, p_pic );
+}
index 9373953..f05c7d3 100644 (file)
 #include <vlc/vlc.h>
 #include <vlc/input.h>
 
-#include "ninput.h"
-
-int demux_vaControl( input_thread_t *p_input, int i_query, va_list args )
-{
-    if( p_input->pf_demux_control )
-    {
-        return p_input->pf_demux_control( p_input, i_query, args );
-    }
-    return VLC_EGENERIC;
-}
-
-int demux_Control( input_thread_t *p_input, int i_query, ...  )
-{
-    va_list args;
-    int     i_result;
-
-    va_start( args, i_query );
-    i_result = demux_vaControl( p_input, i_query, args );
-    va_end( args );
-
-    return i_result;
-}
-
-static void SeekOffset( input_thread_t *p_input, int64_t i_pos );
-
-int demux_vaControlDefault( input_thread_t *p_input, int i_query,
-                            va_list args )
-{
-    int     i_ret;
-    double  f, *pf;
-    int64_t i64, *pi64;
-
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-    switch( i_query )
-    {
-        case DEMUX_GET_POSITION:
-            pf = (double*)va_arg( args, double * );
-            if( p_input->stream.p_selected_area->i_size <= 0 )
-            {
-                *pf = 0.0;
-            }
-            else
-            {
-                *pf = (double)p_input->stream.p_selected_area->i_tell /
-                      (double)p_input->stream.p_selected_area->i_size;
-            }
-            i_ret = VLC_SUCCESS;
-            break;
-
-        case DEMUX_SET_POSITION:
-            f = (double)va_arg( args, double );
-            if( p_input->stream.b_seekable && p_input->pf_seek != NULL &&
-                f >= 0.0 && f <= 1.0 )
-            {
-                SeekOffset( p_input, (int64_t)(f *
-                            (double)p_input->stream.p_selected_area->i_size) );
-                i_ret = VLC_SUCCESS;
-            }
-            else
-            {
-                i_ret = VLC_EGENERIC;
-            }
-            break;
-
-        case DEMUX_GET_TIME:
-            pi64 = (int64_t*)va_arg( args, int64_t * );
-            if( p_input->stream.i_mux_rate > 0 )
-            {
-                *pi64 = (int64_t)1000000 *
-                        ( p_input->stream.p_selected_area->i_tell / 50 ) /
-                        p_input->stream.i_mux_rate;
-                i_ret = VLC_SUCCESS;
-            }
-            else
-            {
-                *pi64 = 0;
-                i_ret = VLC_EGENERIC;
-            }
-            break;
-
-        case DEMUX_SET_TIME:
-            i64 = (int64_t)va_arg( args, int64_t );
-            if( p_input->stream.i_mux_rate > 0 &&
-                p_input->stream.b_seekable &&
-                p_input->pf_seek != NULL && i64 >= 0 )
-            {
-                SeekOffset( p_input, i64 * 50 *
-                                     (int64_t)p_input->stream.i_mux_rate /
-                                     (int64_t)1000000 );
-                i_ret = VLC_SUCCESS;
-            }
-            else
-            {
-                i_ret = VLC_EGENERIC;
-            }
-            break;
-
-        case DEMUX_GET_LENGTH:
-            pi64 = (int64_t*)va_arg( args, int64_t * );
-            if( p_input->stream.i_mux_rate > 0 )
-            {
-                *pi64 = (int64_t)1000000 *
-                        ( p_input->stream.p_selected_area->i_size / 50 ) /
-                        p_input->stream.i_mux_rate;
-                i_ret = VLC_SUCCESS;
-            }
-            else
-            {
-                *pi64 = 0;
-                i_ret = VLC_EGENERIC;
-            }
-            break;
-        case DEMUX_GET_FPS:
-            i_ret = VLC_EGENERIC;
-            break;
-        case DEMUX_GET_META:
-            i_ret = VLC_EGENERIC;
-            break;
-
-        default:
-            msg_Err( p_input, "unknown query in demux_vaControlDefault" );
-            i_ret = VLC_EGENERIC;
-            break;
-    }
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    return i_ret;
-}
-
-static void SeekOffset( input_thread_t *p_input, int64_t i_pos )
-{
-    /* Reinitialize buffer manager. */
-    input_AccessReinit( p_input );
-
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-    p_input->pf_seek( p_input, i_pos );
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-}
-
+#include "input_internal.h"
 
 /*****************************************************************************
  * demux2_New:
+ *  if s is NULL then load a access_demux
  *****************************************************************************/
 demux_t *__demux2_New( vlc_object_t *p_obj,
                        char *psz_access, char *psz_demux, char *psz_path,
@@ -198,8 +61,12 @@ demux_t *__demux2_New( vlc_object_t *p_obj,
     p_demux->info.i_title  = 0;
     p_demux->info.i_seekpoint = 0;
 
-    psz_module = p_demux->psz_demux;
-    if( *psz_module == '\0' && strrchr( p_demux->psz_path, '.' ) )
+    if( s )
+        psz_module = p_demux->psz_demux;
+    else
+        psz_module = p_demux->psz_access;
+
+    if( s && *psz_module == '\0' && strrchr( p_demux->psz_path, '.' ) )
     {
         /* XXX: add only file without any problem here and with strong detection.
          *  - no .mp3, .a52, ... (aac is added as it works only by file ext anyway
@@ -241,9 +108,18 @@ demux_t *__demux2_New( vlc_object_t *p_obj,
     /* Before module_Need (for var_Create...) */
     vlc_object_attach( p_demux, p_obj );
 
-    p_demux->p_module =
-        module_Need( p_demux, "demux2", psz_module,
-                     !strcmp( psz_module, p_demux->psz_demux ) ? VLC_TRUE : VLC_FALSE );
+    if( s )
+    {
+        p_demux->p_module =
+            module_Need( p_demux, "demux2", psz_module,
+                         !strcmp( psz_module, p_demux->psz_demux ) ? VLC_TRUE : VLC_FALSE );
+    }
+    else
+    {
+        p_demux->p_module =
+            module_Need( p_demux, "access_demux", psz_module,
+                         !strcmp( psz_module, p_demux->psz_access ) ? VLC_TRUE : VLC_FALSE );
+    }
 
     if( p_demux->p_module == NULL )
     {
@@ -358,3 +234,263 @@ int demux2_vaControlHelper( stream_t *s,
     }
 }
 
+/****************************************************************************
+ * stream_Demux*: create a demuxer for an outpout stream (allow demuxer chain)
+ ****************************************************************************/
+typedef struct
+{
+    /* Data buffer */
+    vlc_mutex_t lock;
+    int         i_buffer;
+    int         i_buffer_size;
+    uint8_t     *p_buffer;
+
+    int64_t     i_pos;
+
+    /* Demuxer */
+    char        *psz_name;
+    es_out_t    *out;
+    demux_t     *p_demux;
+} d_stream_sys_t;
+
+static int DStreamRead   ( stream_t *, void *p_read, int i_read );
+static int DStreamPeek   ( stream_t *, uint8_t **pp_peek, int i_peek );
+static int DStreamControl( stream_t *, int i_query, va_list );
+static int DStreamThread ( stream_t * );
+
+
+stream_t *__stream_DemuxNew( vlc_object_t *p_obj, char *psz_demux, es_out_t *out )
+{
+    /* We create a stream reader, and launch a thread */
+    stream_t       *s;
+    d_stream_sys_t *p_sys;
+
+    if( psz_demux == NULL || *psz_demux == '\0' )
+    {
+        return NULL;
+    }
+
+    s = vlc_object_create( p_obj, VLC_OBJECT_STREAM );
+    s->pf_block  = NULL;
+    s->pf_read   = DStreamRead;
+    s->pf_peek   = DStreamPeek;
+    s->pf_control= DStreamControl;
+
+    s->p_sys = malloc( sizeof( d_stream_sys_t) );
+    p_sys = (d_stream_sys_t*)s->p_sys;
+
+    vlc_mutex_init( s, &p_sys->lock );
+    p_sys->i_buffer = 0;
+    p_sys->i_buffer_size = 1000000;
+    p_sys->p_buffer = malloc( p_sys->i_buffer_size );
+    p_sys->i_pos = 0;
+    p_sys->psz_name = strdup( psz_demux );
+    p_sys->out = out;
+    p_sys->p_demux = NULL;
+
+    if( vlc_thread_create( s, "stream out", DStreamThread, VLC_THREAD_PRIORITY_INPUT, VLC_FALSE ) )
+    {
+        vlc_mutex_destroy( &p_sys->lock );
+        vlc_object_destroy( s );
+        free( p_sys );
+        return NULL;
+    }
+
+    return s;
+}
+
+void     stream_DemuxSend( stream_t *s, block_t *p_block )
+{
+    d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+
+    if( p_block->i_buffer > 0 )
+    {
+        vlc_mutex_lock( &p_sys->lock );
+        /* Realloc if needed */
+        if( p_sys->i_buffer + p_block->i_buffer > p_sys->i_buffer_size )
+        {
+            if( p_sys->i_buffer_size > 5000000 )
+            {
+                vlc_mutex_unlock( &p_sys->lock );
+                msg_Err( s, "stream_DemuxSend: buffer size > 5000000" );
+                block_Release( p_block );
+                return;
+            }
+            /* I know, it's more than needed but that's perfect */
+            p_sys->i_buffer_size += p_block->i_buffer;
+            /* FIXME won't work with PEEK -> segfault */
+            p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size );
+            msg_Dbg( s, "stream_DemuxSend: realloc to %d", p_sys->i_buffer_size );
+        }
+
+        /* copy data */
+        memcpy( &p_sys->p_buffer[p_sys->i_buffer], p_block->p_buffer, p_block->i_buffer );
+        p_sys->i_buffer += p_block->i_buffer;
+
+        vlc_mutex_unlock( &p_sys->lock );
+    }
+
+    block_Release( p_block );
+}
+
+void     stream_DemuxDelete( stream_t *s )
+{
+    d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+
+    s->b_die = VLC_TRUE;
+
+    vlc_mutex_lock( &p_sys->lock );
+    if( p_sys->p_demux )
+    {
+        p_sys->p_demux->b_die = VLC_TRUE;
+    }
+    vlc_mutex_unlock( &p_sys->lock );
+
+    vlc_thread_join( s );
+
+    if( p_sys->p_demux )
+    {
+        demux2_Delete( p_sys->p_demux );
+    }
+    vlc_mutex_destroy( &p_sys->lock );
+    free( p_sys->psz_name );
+    free( p_sys->p_buffer );
+    free( p_sys );
+    vlc_object_destroy( s );
+}
+
+
+static int      DStreamRead   ( stream_t *s, void *p_read, int i_read )
+{
+    d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+    int           i_copy;
+
+    //msg_Dbg( s, "DStreamRead: wanted %d bytes", i_read );
+    for( ;; )
+    {
+        vlc_mutex_lock( &p_sys->lock );
+        //msg_Dbg( s, "DStreamRead: buffer %d", p_sys->i_buffer );
+        if( p_sys->i_buffer >= i_read || s->b_die )
+        {
+            break;
+        }
+        vlc_mutex_unlock( &p_sys->lock );
+        msleep( 10000 );
+    }
+
+    //msg_Dbg( s, "DStreamRead: read %d buffer %d", i_read, p_sys->i_buffer );
+
+    i_copy = __MIN( i_read, p_sys->i_buffer );
+    if( i_copy > 0 )
+    {
+        if( p_read )
+        {
+            memcpy( p_read, p_sys->p_buffer, i_copy );
+        }
+        p_sys->i_buffer -= i_copy;
+        p_sys->i_pos += i_copy;
+
+        if( p_sys->i_buffer > 0 )
+        {
+            memmove( p_sys->p_buffer, &p_sys->p_buffer[i_copy], p_sys->i_buffer );
+        }
+
+    }
+    vlc_mutex_unlock( &p_sys->lock );
+
+    return i_copy;
+}
+static int      DStreamPeek   ( stream_t *s, uint8_t **pp_peek, int i_peek )
+{
+    d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+    int           i_copy;
+
+    //msg_Dbg( s, "DStreamPeek: wanted %d bytes", i_peek );
+    for( ;; )
+    {
+        vlc_mutex_lock( &p_sys->lock );
+        //msg_Dbg( s, "DStreamPeek: buffer %d", p_sys->i_buffer );
+        if( p_sys->i_buffer >= i_peek || s->b_die )
+        {
+            break;
+        }
+        vlc_mutex_unlock( &p_sys->lock );
+        msleep( 10000 );
+    }
+    *pp_peek = p_sys->p_buffer;
+    i_copy = __MIN( i_peek, p_sys->i_buffer );
+
+    vlc_mutex_unlock( &p_sys->lock );
+
+    return i_copy;
+}
+
+static int      DStreamControl( stream_t *s, int i_query, va_list args )
+{
+    d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+    int64_t    *p_i64;
+    vlc_bool_t *p_b;
+    int        *p_int;
+    switch( i_query )
+    {
+        case STREAM_GET_SIZE:
+            p_i64 = (int64_t*) va_arg( args, int64_t * );
+            *p_i64 = 0;
+            return VLC_SUCCESS;
+
+        case STREAM_CAN_SEEK:
+            p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
+            *p_b = VLC_FALSE;
+            return VLC_SUCCESS;
+
+        case STREAM_CAN_FASTSEEK:
+            p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
+            *p_b = VLC_FALSE;
+            return VLC_SUCCESS;
+
+        case STREAM_GET_POSITION:
+            p_i64 = (int64_t*) va_arg( args, int64_t * );
+            *p_i64 = p_sys->i_pos;
+            return VLC_SUCCESS;
+
+        case STREAM_SET_POSITION:
+            return VLC_EGENERIC;
+
+        case STREAM_GET_MTU:
+            p_int = (int*) va_arg( args, int * );
+            *p_int = 0;
+            return VLC_SUCCESS;
+
+        default:
+            msg_Err( s, "invalid DStreamControl query=0x%x", i_query );
+            return VLC_EGENERIC;
+    }
+}
+
+static int      DStreamThread ( stream_t *s )
+{
+    d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+    demux_t      *p_demux;
+
+    /* Create the demuxer */
+
+    if( ( p_demux = demux2_New( s, "", p_sys->psz_name, "", s, p_sys->out ) ) == NULL )
+    {
+        return VLC_EGENERIC;
+    }
+
+    vlc_mutex_lock( &p_sys->lock );
+    p_sys->p_demux = p_demux;
+    vlc_mutex_unlock( &p_sys->lock );
+
+    /* Main loop */
+    while( !s->b_die && !p_demux->b_die )
+    {
+        if( p_demux->pf_demux( p_demux ) <= 0 )
+        {
+            break;
+        }
+    }
+    p_demux->b_die = VLC_TRUE;
+    return VLC_SUCCESS;
+}
index 23e4546..978c32f 100644 (file)
 #include <vlc/input.h>
 #include <vlc/decoder.h>
 
+#include "input_internal.h"
+
 #include "vlc_playlist.h"
-#include "codecs.h"
 #include "iso_lang.h"
 
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
+typedef struct
+{
+    /* Program ID */
+    int i_id;
+
+    /* Number of es for this pgrm */
+    int i_es;
+
+    vlc_bool_t b_selected;
+
+    /* Clock for this program */
+    input_clock_t clock;
+
+} es_out_pgrm_t;
+
 struct es_out_id_t
 {
-    int             i_channel;
-    es_descriptor_t *p_es;
+    /* ES ID */
+    int       i_id;
+    es_out_pgrm_t *p_pgrm;
+
+    /* Channel in the track type */
+    int         i_channel;
+    es_format_t fmt;
+    char        *psz_description;
+    decoder_t   *p_dec;
 };
 
 struct es_out_sys_t
 {
     input_thread_t *p_input;
 
+    /* all programs */
+    int           i_pgrm;
+    es_out_pgrm_t **pgrm;
+    es_out_pgrm_t *p_pgrm;  /* Master program */
+
     /* all es */
     int         i_id;
-
     int         i_es;
     es_out_id_t **es;
 
@@ -75,16 +102,17 @@ struct es_out_sys_t
 static es_out_id_t *EsOutAdd    ( es_out_t *, es_format_t * );
 static int          EsOutSend   ( es_out_t *, es_out_id_t *, block_t * );
 static void         EsOutDel    ( es_out_t *, es_out_id_t * );
+static void         EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force );
 static int          EsOutControl( es_out_t *, int i_query, va_list );
 
+
+static void EsSelect( es_out_t *out, es_out_id_t *es );
+static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update );
 static char *LanguageGetName( const char *psz_code );
 
-/**
- * Create a new es_out structure
- *
- * \param p_input The related input thread
- * \return the new es_out_t
- */
+/*****************************************************************************
+ * input_EsOutNew:
+ *****************************************************************************/
 es_out_t *input_EsOutNew( input_thread_t *p_input )
 {
     es_out_t     *out = malloc( sizeof( es_out_t ) );
@@ -102,8 +130,12 @@ es_out_t *input_EsOutNew( input_thread_t *p_input )
     p_sys->b_active = VLC_FALSE;
     p_sys->i_mode   = ES_OUT_MODE_AUTO;
 
-    p_sys->i_id    = 1;
 
+    p_sys->i_pgrm   = 0;
+    p_sys->pgrm     = NULL;
+    p_sys->p_pgrm   = NULL;
+
+    p_sys->i_id    = 0;
     p_sys->i_es    = 0;
     p_sys->es      = NULL;
 
@@ -124,12 +156,9 @@ es_out_t *input_EsOutNew( input_thread_t *p_input )
     return out;
 }
 
-/**
- * Deletes an es_out structure
- *
- * \param out  the es_out structure to destroy
- * \return nothing
- */
+/*****************************************************************************
+ * input_EsOutDelete:
+ *****************************************************************************/
 void input_EsOutDelete( es_out_t *out )
 {
     es_out_sys_t *p_sys = out->p_sys;
@@ -137,191 +166,249 @@ void input_EsOutDelete( es_out_t *out )
 
     for( i = 0; i < p_sys->i_es; i++ )
     {
+        if( p_sys->es[i]->p_dec )
+        {
+            input_DecoderDelete( p_sys->es[i]->p_dec );
+        }
+        if( p_sys->es[i]->psz_description )
+            free( p_sys->es[i]->psz_description );
+        es_format_Clean( &p_sys->es[i]->fmt );
+
         free( p_sys->es[i] );
     }
     if( p_sys->es )
-    {
         free( p_sys->es );
+
+    for( i = 0; i < p_sys->i_pgrm; i++ )
+    {
+        free( p_sys->pgrm[i] );
     }
+    if( p_sys->pgrm )
+        free( p_sys->pgrm );
+
     free( p_sys );
     free( out );
 }
 
-/**
- * Add a program
- *
- * \param out the es_out
- * \param i_group ...
- * \return a program descriptor for the new program
- */
-static pgrm_descriptor_t *EsOutAddProgram( es_out_t *out, int i_group )
+es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
 {
-    input_thread_t    *p_input = out->p_sys->p_input;
-    pgrm_descriptor_t *p_pgrm;
-    es_descriptor_t   *p_pmt;
-
-    /* FIXME we should use a object variable but a lot of place in src/input
-     * have to be changed */
-    int               i_select = config_GetInt( p_input, "program" );
+    int i;
+    if( i_id < 0 )
+    {
+        /* Special HACK, -i_id is tha cat of the stream */
+        return (es_out_id_t*)((uint8_t*)NULL-i_id);
+    }
 
-    /* create it */
-    p_pgrm = input_AddProgram( p_input, i_group, 0 );
+    for( i = 0; i < out->p_sys->i_es; i++ )
+    {
+        if( out->p_sys->es[i]->i_id == i_id )
+            return out->p_sys->es[i];
+    }
+    return NULL;
+}
 
-    /* XXX welcome to kludge, add a dummy es, if you want to understand
-     * why have a look at input_SetProgram. Basicaly, it assume the first
-     * es to be the PMT, how that is stupid, nevertheless it is needed for
-     * the old ts demuxer */
-    p_pmt = input_AddES( p_input, p_pgrm, 0, UNKNOWN_ES, NULL, 0 );
-    p_pmt->i_fourcc = VLC_FOURCC( 'n', 'u', 'l', 'l' );
+void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio )
+{
+    es_out_sys_t      *p_sys = out->p_sys;
+    int i;
 
-    /* Select i_select or the first by default */
-    if( p_input->stream.p_selected_program == NULL &&
-        ( i_select <= 0 || i_select == i_group ) )
+    for( i = 0; i < p_sys->i_es; i++ )
     {
-        p_input->stream.p_selected_program = p_pgrm;
-    }
+        es_out_id_t *es = p_sys->es[i];
 
-    return p_pgrm;
+        /* Send a dummy block to let decoder know that
+         * there is a discontinuity */
+        if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
+        {
+            input_DecoderDiscontinuity( es->p_dec );
+        }
+    }
 }
 
-/**
- * Select an ES given the current mode
- * XXX: you need to take a the lock before (stream.stream_lock)
+/*****************************************************************************
  *
- * \param out The es_out structure
- * \param es es_out_id structure
- * \param b_force ...
- * \return nothing
- */
-static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
+ *****************************************************************************/
+static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es )
 {
     es_out_sys_t      *p_sys = out->p_sys;
     input_thread_t    *p_input = p_sys->p_input;
+    vlc_value_t       val, text;
 
-    int i_cat = es->p_es->i_cat;
+    char *psz_var;
 
-    if( !p_sys->b_active ||
-        ( !b_force && es->p_es->fmt.i_priority < 0 ) )
-    {
+    if( es->fmt.i_cat == AUDIO_ES )
+        psz_var = "audio-es";
+    else if( es->fmt.i_cat == VIDEO_ES )
+        psz_var = "video-es";
+    else if( es->fmt.i_cat == SPU_ES )
+        psz_var = "spu-es";
+    else
         return;
+
+    /* Get the number of ES already added */
+    var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
+    if( val.i_int == 0 )
+    {
+        vlc_value_t val2;
+
+        /* First one, we need to add the "Disable" choice */
+        val2.i_int = -1; text.psz_string = _("Disable");
+        var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
+        val.i_int++;
     }
 
-    if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
+    /* Take care of the ES description */
+    if( es->psz_description && *es->psz_description )
     {
-        if( !es->p_es->p_dec )
-        {
-            input_SelectES( p_input, es->p_es );
-        }
+        text.psz_string = strdup( es->psz_description );
     }
-    else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
+    else
     {
-        int i_wanted  = -1;
+        text.psz_string = malloc( strlen( _("Track %i") ) + 20 );
+        sprintf( text.psz_string, _("Track %i"), val.i_int );
+    }
 
-        if( es->p_es->p_pgrm != NULL &&
-            es->p_es->p_pgrm != p_input->stream.p_selected_program )
-        {
-            return;
-        }
+    val.i_int = es->i_id;
+    var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
 
-        if( i_cat == AUDIO_ES )
-        {
-            if( p_sys->p_es_audio &&
-                p_sys->p_es_audio->p_es->fmt.i_priority >=
-                    es->p_es->fmt.i_priority )
-            {
-                return;
-            }
-            i_wanted  = p_sys->i_audio_last >= 0 ?
-                            p_sys->i_audio_last : es->i_channel;
-        }
-        else if( i_cat == SPU_ES )
-        {
-            if( p_sys->p_es_sub &&
-                p_sys->p_es_sub->p_es->fmt.i_priority >=
-                    es->p_es->fmt.i_priority )
-            {
-                return;
-            }
-            i_wanted  = p_sys->i_sub_last;
-        }
-        else if( i_cat == VIDEO_ES )
-        {
-            i_wanted  = es->i_channel;
-        }
+    free( text.psz_string );
+
+    var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
+}
+
+/* EsOutProgramSelect:
+ *  Select a program and update the object variable
+ */
+static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
+{
+    es_out_sys_t      *p_sys = out->p_sys;
+    input_thread_t    *p_input = p_sys->p_input;
+    vlc_value_t       val;
+    int               i;
+
+    if( p_sys->p_pgrm == p_pgrm )
+        return; /* Nothing to do */
+
+    if( p_sys->p_pgrm )
+    {
+        es_out_pgrm_t *old = p_sys->p_pgrm;
+        msg_Dbg( p_input, "Unselecting program id=%d", old->i_id );
 
-        if( i_wanted == es->i_channel && es->p_es->p_dec == NULL )
+        for( i = 0; i < p_sys->i_es; i++ )
         {
-            input_SelectES( p_input, es->p_es );
+            if( p_sys->es[i]->p_pgrm == old && p_sys->es[i]->p_dec &&
+                p_sys->i_mode != ES_OUT_MODE_ALL )
+                EsUnselect( out, p_sys->es[i], VLC_TRUE );
         }
     }
 
-    /* FIXME TODO handle priority here */
-    if( es->p_es->p_dec )
+    msg_Dbg( p_input, "Selecting program id=%d", p_pgrm->i_id );
+
+    /* Mark it selected */
+    p_pgrm->b_selected = VLC_TRUE;
+
+    /* Switch master stream */
+    if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master )
     {
-        if( i_cat == AUDIO_ES )
-        {
-            if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
-                p_sys->p_es_audio && p_sys->p_es_audio->p_es->p_dec )
-            {
-                input_UnselectES( p_input, p_sys->p_es_audio->p_es );
-            }
-            p_sys->p_es_audio = es;
-        }
-        else if( i_cat == SPU_ES )
-        {
-            if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
-                p_sys->p_es_sub && p_sys->p_es_sub->p_es->p_dec )
-            {
-                input_UnselectES( p_input, p_sys->p_es_sub->p_es );
-            }
-            p_sys->p_es_sub = es;
-        }
-        else if( i_cat == VIDEO_ES )
-        {
-            p_sys->p_es_video = es;
-        }
+        p_sys->p_pgrm->clock.b_master = VLC_FALSE;
+    }
+    p_pgrm->clock.b_master = VLC_TRUE;
+    p_sys->p_pgrm = p_pgrm;
+
+    /* Update "program" */
+    val.i_int = p_pgrm->i_id;
+    var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
+
+    /* Update "es-*" */
+    var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
+    var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
+    var_Change( p_input, "spu-es",   VLC_VAR_CLEARCHOICES, NULL, NULL );
+    for( i = 0; i < p_sys->i_es; i++ )
+    {
+        EsOutESVarUpdate( out, p_sys->es[i] );
+        EsOutSelect( out, p_sys->es[i], VLC_FALSE );
+    }
+
+    var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
+}
+
+/* EsOutAddProgram:
+ *  Add a program
+ */
+static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
+{
+    es_out_sys_t      *p_sys = out->p_sys;
+    input_thread_t    *p_input = p_sys->p_input;
+    vlc_value_t       val;
+
+    es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
+
+    /* Init */
+    p_pgrm->i_id = i_group;
+    p_pgrm->i_es = 0;
+    p_pgrm->b_selected = VLC_FALSE;
+    input_ClockInit( &p_pgrm->clock, VLC_FALSE, p_input->input.i_cr_average );
+
+    /* Append it */
+    TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
+
+    /* Update "program" variable */
+    val.i_int = i_group;
+    var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
+
+    if( i_group == var_GetInteger( p_input, "program" ) )
+    {
+        EsOutProgramSelect( out, p_pgrm );
+    }
+    else
+    {
+        var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
     }
+    return p_pgrm;
 }
 
-/**
- * Add an es_out
- *
- * \param out the es_out to add
- * \param fmt the es_format of the es_out
- * \return an es_out id
+/* EsOutAdd:
+ *  Add an es_out
  */
 static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
 {
     es_out_sys_t      *p_sys = out->p_sys;
     input_thread_t    *p_input = p_sys->p_input;
+
     es_out_id_t       *es = malloc( sizeof( es_out_id_t ) );
-    pgrm_descriptor_t *p_pgrm = NULL;
-    char              psz_cat[sizeof( _("Stream ") ) + 10];
-    char              *psz_description;
+    es_out_pgrm_t     *p_pgrm = NULL;
+    int i;
 
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-    if( fmt->i_group >= 0 )
+    if( fmt->i_group < 0 )
     {
-        /* search program */
-        p_pgrm = input_FindProgram( p_input, fmt->i_group );
+        msg_Err( p_input, "invakud group number" );
+        return NULL;
+    }
 
-        if( p_pgrm == NULL )
+    /* Search the program */
+    for( i = 0; i < p_sys->i_pgrm; i++ )
+    {
+        if( fmt->i_group == p_sys->pgrm[i]->i_id )
         {
-            /* Create it */
-            p_pgrm = EsOutAddProgram( out, fmt->i_group );
+            p_pgrm = p_sys->pgrm[i];
+            break;
         }
     }
-    if( fmt->i_id < 0 )
+    if( p_pgrm == NULL )
     {
-        fmt->i_id = out->p_sys->i_id - 1;
+        /* Create a new one */
+        p_pgrm = EsOutProgramAdd( out, fmt->i_group );
     }
 
-    psz_description = LanguageGetName( fmt->psz_language );
-    es->p_es = input_AddES( p_input, p_pgrm, fmt->i_id + 1,
-                            fmt->i_cat, psz_description, 0 );
-    es->p_es->i_stream_id = fmt->i_id;
-    es->p_es->i_fourcc = fmt->i_codec;
+    /* Increase ref count for program */
+    p_pgrm->i_es++;
 
+    /* Set up ES */
+    if( fmt->i_id < 0 )
+        fmt->i_id = out->p_sys->i_id;
+    es->i_id = fmt->i_id;
+    es->p_pgrm = p_pgrm;
+    es_format_Copy( &es->fmt, fmt );
     switch( fmt->i_cat )
     {
     case AUDIO_ES:
@@ -340,9 +427,14 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
         es->i_channel = 0;
         break;
     }
+    es->psz_description = LanguageGetName( fmt->psz_language );
+    es->p_dec = NULL;
+
+    if( es->p_pgrm == p_sys->p_pgrm )
+        EsOutESVarUpdate( out, es );
 
+#if 0
     /* Add stream info */
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
     sprintf( psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
 
     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
@@ -406,19 +498,12 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
     default:
         break;
     }
-
-    vlc_mutex_lock( &p_input->stream.stream_lock );
     free( psz_description );
+#endif
 
-    es_format_Copy( &es->p_es->fmt, fmt );
+    /* Select it if needed */
+    EsOutSelect( out, es, VLC_FALSE );
 
-    /* Apply mode
-     * XXX change that when we do group too */
-    if( 1 )
-    {
-        EsOutSelect( out, es, VLC_FALSE );
-    }
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
 
     TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
     p_sys->i_id++;  /* always incremented */
@@ -438,6 +523,186 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
     return es;
 }
 
+static void EsSelect( es_out_t *out, es_out_id_t *es )
+{
+    es_out_sys_t   *p_sys = out->p_sys;
+    input_thread_t *p_input = p_sys->p_input;
+    vlc_value_t    val;
+    char           *psz_var;
+
+    if( es->p_dec )
+    {
+        msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
+        return;
+    }
+
+    if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
+    {
+        if( !var_GetBool( p_input, "video" ) || ( p_input->p_sout && !var_GetBool( p_input, "sout-video" ) ) )
+        {
+            msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x", es->i_id );
+            return;
+        }
+    }
+    else if( es->fmt.i_cat == AUDIO_ES )
+    {
+        var_Get( p_input, "audio", &val );
+        if( !var_GetBool( p_input, "audio" ) || ( p_input->p_sout && !var_GetBool( p_input, "sout-audio" ) ) )
+        {
+            msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x", es->i_id );
+            return;
+        }
+    }
+
+    es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
+    if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
+        return;
+
+    if( es->fmt.i_cat == VIDEO_ES )
+        psz_var = "video-es";
+    else if( es->fmt.i_cat == AUDIO_ES )
+        psz_var = "audio-es";
+    else if( es->fmt.i_cat == SPU_ES )
+        psz_var = "spu-es";
+    else
+        return;
+
+    /* Mark it as selected */
+    val.i_int = es->i_id;
+    var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
+
+
+    var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
+}
+
+static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update )
+{
+    es_out_sys_t   *p_sys = out->p_sys;
+    input_thread_t *p_input = p_sys->p_input;
+    vlc_value_t    val;
+    char           *psz_var;
+
+    if( es->p_dec == NULL )
+    {
+        msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
+        return;
+    }
+
+    input_DecoderDelete( es->p_dec );
+    es->p_dec = NULL;
+
+    if( !b_update )
+        return;
+
+    /* Update var */
+    if( es->p_dec == NULL )
+        return;
+    if( es->fmt.i_cat == VIDEO_ES )
+        psz_var = "video-es";
+    else if( es->fmt.i_cat == AUDIO_ES )
+        psz_var = "audio-es";
+    else if( es->fmt.i_cat == SPU_ES )
+        psz_var = "spu-es";
+    else
+        return;
+
+    /* Mark it as selected */
+    val.i_int = -1;
+    var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
+
+    var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
+}
+
+/**
+ * Select an ES given the current mode
+ * XXX: you need to take a the lock before (stream.stream_lock)
+ *
+ * \param out The es_out structure
+ * \param es es_out_id structure
+ * \param b_force ...
+ * \return nothing
+ */
+static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
+{
+    es_out_sys_t      *p_sys = out->p_sys;
+
+    int i_cat = es->fmt.i_cat;
+
+    if( !p_sys->b_active ||
+        ( !b_force && es->fmt.i_priority < 0 ) )
+    {
+        return;
+    }
+
+    if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
+    {
+        if( !es->p_dec )
+            EsSelect( out, es );
+    }
+    else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
+    {
+        int i_wanted  = -1;
+
+        if( es->p_pgrm != p_sys->p_pgrm )
+            return;
+
+        if( i_cat == AUDIO_ES )
+        {
+            if( p_sys->p_es_audio &&
+                p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
+            {
+                return;
+            }
+            i_wanted  = p_sys->i_audio_last >= 0 ?
+                            p_sys->i_audio_last : es->i_channel;
+        }
+        else if( i_cat == SPU_ES )
+        {
+            if( p_sys->p_es_sub &&
+                p_sys->p_es_sub->fmt.i_priority >=
+                    es->fmt.i_priority )
+            {
+                return;
+            }
+            i_wanted  = p_sys->i_sub_last;
+        }
+        else if( i_cat == VIDEO_ES )
+        {
+            i_wanted  = es->i_channel;
+        }
+
+        if( i_wanted == es->i_channel && es->p_dec == NULL )
+            EsSelect( out, es );
+    }
+
+    /* FIXME TODO handle priority here */
+    if( es->p_dec )
+    {
+        if( i_cat == AUDIO_ES )
+        {
+            if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
+                p_sys->p_es_audio && p_sys->p_es_audio->p_dec )
+            {
+                EsUnselect( out, p_sys->p_es_audio, VLC_FALSE );
+            }
+            p_sys->p_es_audio = es;
+        }
+        else if( i_cat == SPU_ES )
+        {
+            if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
+                p_sys->p_es_sub && p_sys->p_es_sub->p_dec )
+            {
+                EsUnselect( out, p_sys->p_es_sub, VLC_FALSE );
+            }
+            p_sys->p_es_sub = es;
+        }
+        else if( i_cat == VIDEO_ES )
+        {
+            p_sys->p_es_video = es;
+        }
+    }
+}
+
 /**
  * Send a block for the given es_out
  *
@@ -448,37 +713,30 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
 {
     es_out_sys_t *p_sys = out->p_sys;
-    pgrm_descriptor_t *p_pgrm = es->p_es->p_pgrm;
     input_thread_t    *p_input = p_sys->p_input;
-
-    if( p_pgrm == NULL )
-    {
-        p_pgrm = p_sys->p_input->stream.p_selected_program;
-    }
+    es_out_pgrm_t *p_pgrm = es->p_pgrm;
 
     /* +11 -> avoid null value with non null dts/pts */
-    if( p_block->i_dts > 0 && p_pgrm )
+    if( p_block->i_dts > 0 )
     {
         p_block->i_dts =
-            input_ClockGetTS( p_input, p_pgrm, ( p_block->i_dts + 11 ) * 9 / 100 );
+            input_ClockGetTS( p_input, &p_pgrm->clock, ( p_block->i_dts + 11 ) * 9 / 100 );
     }
-    if( p_block->i_pts > 0 && p_pgrm )
+    if( p_block->i_pts > 0 )
     {
         p_block->i_pts =
-            input_ClockGetTS( p_input, p_pgrm, ( p_block->i_pts + 11 )* 9 / 100 );
+            input_ClockGetTS( p_input, &p_pgrm->clock, ( p_block->i_pts + 11 )* 9 / 100 );
     }
 
-    vlc_mutex_lock( &out->p_sys->p_input->stream.stream_lock );
-    p_block->i_rate = out->p_sys->p_input->stream.control.i_rate;
-    if( es->p_es->p_dec &&
-        (es->p_es->i_cat!=AUDIO_ES || !p_sys->p_input->stream.control.b_mute) )
+    p_block->i_rate = p_input->i_rate;
+
+    /* TODO handle mute */
+    if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES || p_input->i_rate == INPUT_RATE_DEFAULT ) )
     {
-        vlc_mutex_unlock( &out->p_sys->p_input->stream.stream_lock );
-        input_DecodeBlock( es->p_es->p_dec, p_block );
+        input_DecoderDecode( es->p_dec, p_block );
     }
     else
     {
-        vlc_mutex_unlock( &out->p_sys->p_input->stream.stream_lock );
         block_Release( p_block );
     }
 
@@ -492,9 +750,23 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es )
 {
     es_out_sys_t *p_sys = out->p_sys;
 
+    /* We don't try to reselect */
+    if( es->p_dec )
+        EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
+
     TAB_REMOVE( p_sys->i_es, p_sys->es, es );
 
-    switch( es->p_es->i_cat )
+    es->p_pgrm->i_es--;
+    if( es->p_pgrm->i_es == 0 )
+    {
+        msg_Err( p_sys->p_input, "Program doesn't have es anymore, clenaing TODO ?" );
+    }
+
+    if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
+    if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
+    if( p_sys->p_es_sub   == es ) p_sys->p_es_sub   = NULL;
+
+    switch( es->fmt.i_cat )
     {
         case AUDIO_ES:
             p_sys->i_audio--;
@@ -507,30 +779,10 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es )
             break;
     }
 
-    /* We don't try to reselect */
-    vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
-    if( es->p_es->p_dec )
-    {
-        input_UnselectES( p_sys->p_input, es->p_es );
-    }
-
-    if( es->p_es->p_waveformatex )
-    {
-        free( es->p_es->p_waveformatex );
-        es->p_es->p_waveformatex = NULL;
-    }
-    if( es->p_es->p_bitmapinfoheader )
-    {
-        free( es->p_es->p_bitmapinfoheader );
-        es->p_es->p_bitmapinfoheader = NULL;
-    }
-    input_DelES( p_sys->p_input, es->p_es );
+    if( es->psz_description )
+        free( es->psz_description );
 
-    if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
-    if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
-    if( p_sys->p_es_sub   == es ) p_sys->p_es_sub   = NULL;
-
-    vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
+    es_format_Clean( &es->fmt );
 
     free( es );
 }
@@ -554,42 +806,34 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
     switch( i_query )
     {
         case ES_OUT_SET_ES_STATE:
-            vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
-            if( b && es->p_es->p_dec == NULL )
+            if( b && es->p_dec == NULL )
             {
-                input_SelectES( p_sys->p_input, es->p_es );
-                vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
-                return es->p_es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
+                EsSelect( out, es );
+                return es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
             }
-            else if( !b && es->p_es->p_dec )
+            else if( !b && es->p_dec )
             {
-                input_UnselectES( p_sys->p_input, es->p_es );
-                vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
+                EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
                 return VLC_SUCCESS;
             }
-            vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
             return VLC_SUCCESS;
 
         case ES_OUT_GET_ES_STATE:
             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
 
-            *pb = es->p_es->p_dec ? VLC_TRUE : VLC_FALSE;
+            *pb = es->p_dec ? VLC_TRUE : VLC_FALSE;
             return VLC_SUCCESS;
 
         case ES_OUT_SET_ACTIVE:
         {
             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
             p_sys->b_active = b;
-
+            /* Needed ? */
             if( b )
-            {
-                vlc_value_t val;
-                val.b_bool = VLC_TRUE;
-                var_Set( p_sys->p_input, "intf-change", val );
-            }
+                var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
             return VLC_SUCCESS;
         }
 
@@ -603,28 +847,20 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
             if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
                 i == ES_OUT_MODE_AUTO )
             {
-                vlc_value_t val;
-
                 p_sys->i_mode = i;
 
                 /* Reapply policy mode */
-                vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
                 for( i = 0; i < p_sys->i_es; i++ )
                 {
-                    if( p_sys->es[i]->p_es->p_dec )
+                    if( p_sys->es[i]->p_dec )
                     {
-                        input_UnselectES( p_sys->p_input, p_sys->es[i]->p_es );
+                        EsUnselect( out, p_sys->es[i], p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
                     }
                 }
                 for( i = 0; i < p_sys->i_es; i++ )
                 {
                     EsOutSelect( out, p_sys->es[i], VLC_FALSE );
                 }
-                vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
-
-                val.b_bool = VLC_TRUE;
-                var_Set( p_sys->p_input, "intf-change", val );
-
                 return VLC_SUCCESS;
             }
             return VLC_EGENERIC;
@@ -636,65 +872,119 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
 
         case ES_OUT_SET_ES:
             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
+            /* Special case NULL, NULL+i_cat */
             if( es == NULL )
             {
                 for( i = 0; i < p_sys->i_es; i++ )
                 {
-                    vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
-                    if( p_sys->es[i]->p_es->p_dec )
-                    {
-                        input_UnselectES( p_sys->p_input, p_sys->es[i]->p_es );
-                    }
-                    vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
+                    if( p_sys->es[i]->p_dec )
+                        EsUnselect( out, p_sys->es[i],
+                                    p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
+                }
+            }
+            else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
+            {
+                for( i = 0; i < p_sys->i_es; i++ )
+                {
+                    if( p_sys->es[i]->p_dec && p_sys->es[i]->fmt.i_cat == AUDIO_ES )
+                        EsUnselect( out, p_sys->es[i], p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
+                }
+            }
+            else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
+            {
+                for( i = 0; i < p_sys->i_es; i++ )
+                {
+                    if( p_sys->es[i]->p_dec && p_sys->es[i]->fmt.i_cat == VIDEO_ES )
+                        EsUnselect( out, p_sys->es[i], p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
+                }
+            }
+            else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
+            {
+                for( i = 0; i < p_sys->i_es; i++ )
+                {
+                    if( p_sys->es[i]->p_dec && p_sys->es[i]->fmt.i_cat == SPU_ES )
+                        EsUnselect( out, p_sys->es[i], p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
                 }
             }
             else
             {
-                vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
-                EsOutSelect( out, es, VLC_TRUE );
-                vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
+                for( i = 0; i < p_sys->i_es; i++ )
+                {
+                    if( es == p_sys->es[i] )
+                    {
+                        EsOutSelect( out, es, VLC_TRUE );
+                        break;
+                    }
+                }
             }
             return VLC_SUCCESS;
 
         case ES_OUT_SET_PCR:
         case ES_OUT_SET_GROUP_PCR:
         {
-            pgrm_descriptor_t *p_pgrm = NULL;
-            int64_t           i_pcr;
+            es_out_pgrm_t *p_pgrm = NULL;
+            int            i_group = 0;
+            int64_t        i_pcr;
 
             if( i_query == ES_OUT_SET_PCR )
             {
-                p_pgrm = p_sys->p_input->stream.p_selected_program;
+                p_pgrm = p_sys->p_pgrm;
             }
             else
             {
-                int i_group = (int)va_arg( args, int );
-                p_pgrm = input_FindProgram( p_sys->p_input, i_group );
-                if( p_pgrm == NULL )
+                int i;
+                i_group = (int)va_arg( args, int );
+                for( i = 0; i < p_sys->i_pgrm; i++ )
                 {
-                    /* we create the requested program */
-                    p_pgrm = EsOutAddProgram( out, i_group );
+                    if( p_sys->pgrm[i]->i_id == i_group )
+                    {
+                        p_pgrm = p_sys->pgrm[i];
+                        break;
+                    }
                 }
             }
+            if( p_pgrm == NULL )
+                p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
+
             i_pcr = (int64_t)va_arg( args, int64_t );
             /* search program */
-            if( p_pgrm )
-            {
                 /* 11 is a vodoo trick to avoid non_pcr*9/100 to be null */
-                input_ClockManageRef( p_sys->p_input, p_pgrm, (i_pcr + 11 ) * 9 / 100);
-            }
+                input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock, (i_pcr + 11 ) * 9 / 100);
             return VLC_SUCCESS;
         }
 
         case ES_OUT_RESET_PCR:
-            for( i = 0; i < p_sys->p_input->stream.i_pgrm_number; i++ )
+            for( i = 0; i < p_sys->i_pgrm; i++ )
             {
-                p_sys->p_input->stream.pp_programs[i]->i_synchro_state =
-                    SYNCHRO_REINIT;
-                p_sys->p_input->stream.pp_programs[i]->last_pts = 0;
+                p_sys->pgrm[i]->clock.i_synchro_state =  SYNCHRO_REINIT;
+                p_sys->pgrm[i]->clock.last_pts = 0;
             }
             return VLC_SUCCESS;
 
+        case ES_OUT_GET_GROUP:
+            pi = (int*) va_arg( args, int* );
+            if( p_sys->p_pgrm )
+                *pi = p_sys->p_pgrm->i_id;
+            else
+                *pi = -1;    /* FIXME */
+            return VLC_SUCCESS;
+
+        case ES_OUT_SET_GROUP:
+        {
+            int j;
+            i = (int) va_arg( args, int );
+            for( j = 0; j < p_sys->i_pgrm; j++ )
+            {
+                es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
+                if( p_pgrm->i_id == i )
+                {
+                    EsOutProgramSelect( out, p_pgrm );
+                    return VLC_SUCCESS;
+                }
+            }
+            return VLC_EGENERIC;
+        }
+
         default:
             msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
             return VLC_EGENERIC;
index 5e0b231..2374b9f 100644 (file)
@@ -1,12 +1,11 @@
 /*****************************************************************************
  * input.c: input thread
- * Read a stream, demultiplex and parse it before sending it to
- * decoders.
  *****************************************************************************
  * Copyright (C) 1998-2004 VideoLAN
  * $Id$
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
+ *          Laurent Aimar <fenrir@via.ecp.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <vlc/decoder.h>
 #include <vlc/vout.h>
 
-#ifdef HAVE_SYS_TIMES_H
-#   include <sys/times.h>
-#endif
+#include "input_internal.h"
 
 #include "stream_output.h"
 
 #include "vlc_interface.h"
-#include "codecs.h"
 #include "vlc_meta.h"
-#include "../../modules/demux/util/sub.h"
 
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-struct input_thread_sys_t
-{
-    /* subtitles */
-    int              i_sub;
-    subtitle_demux_t **sub;
+static  int Run  ( input_thread_t *p_input );
+
+static  int Init ( input_thread_t *p_input );
+static void Error( input_thread_t *p_input );
+static void End  ( input_thread_t *p_input );
+
+static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * );
+static void       ControlReduce( input_thread_t * );
+static vlc_bool_t Control( input_thread_t *, int, vlc_value_t );
 
-    int64_t          i_stop_time;
-};
 
-static  int RunThread  ( input_thread_t *p_input );
-static  int InitThread ( input_thread_t *p_input );
-static void ErrorThread( input_thread_t *p_input );
-static void EndThread  ( input_thread_t *p_input );
+static void UpdateFromAccess( input_thread_t * );
+static void UpdateFromDemux( input_thread_t * );
 
 static void ParseOption( input_thread_t *p_input, const char *psz_option );
 
 static void DecodeUrl  ( char * );
 
-/*****************************************************************************
- * Callbacks
- *****************************************************************************/
-static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
-                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
-static int TimeCallback    ( vlc_object_t *p_this, char const *psz_cmd,
-                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
-static int StateCallback   ( vlc_object_t *p_this, char const *psz_cmd,
-                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
-static int RateCallback    ( vlc_object_t *p_this, char const *psz_cmd,
-                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
-static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd,
-                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
-
 /*****************************************************************************
  * input_CreateThread: creates a new input thread
  *****************************************************************************
  * This function creates a new input, and returns a pointer
  * to its description. On error, it returns NULL.
+ *
+ * Variables for _public_ use:
+ * * Get and Set:
+ *  - state
+ *  - rate,rate-slower, rate-faster
+ *  - position, position-offset
+ *  - time, time-offset
+ *  - title,title-next,title-prev
+ *  - chapter,chapter-next, chapter-prev
+ *  - program, audio-es, video-es, spu-es
+ *  - bookmark
+ * * Get only:
+ *  - length
+ *  - bookmarks
+ * * For intf callback upon changes
+ *  - intf-change
+ * TODO explain when Callback is called
+ * TODO complete this list (?)
  *****************************************************************************/
 input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
                                       input_item_t *p_item )
 
 {
     input_thread_t *p_input;                        /* thread descriptor */
-    vlc_value_t     val;
     int             i;
 
     /* Allocate descriptor */
@@ -101,8 +99,40 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
         return NULL;
     }
 
-    /* Store pointer to input item descriptor */
-    p_input->p_item = p_item;
+    /* Init Common fields */
+    p_input->b_eof = VLC_FALSE;
+    p_input->b_can_pace_control = VLC_TRUE;
+    p_input->i_start = 0;
+    p_input->i_time  = 0;
+    p_input->i_stop  = 0;
+    p_input->i_title = 0;
+    p_input->title   = NULL;
+    p_input->i_state = INIT_S;
+    p_input->i_rate  = INPUT_RATE_DEFAULT;
+    p_input->i_bookmark = 0;
+    p_input->bookmark = NULL;
+    p_input->p_es_out = NULL;
+    p_input->p_sout  = NULL;
+    p_input->b_out_pace_control = VLC_FALSE;
+    p_input->i_pts_delay = 0;
+
+
+    /* Init Input fields */
+    p_input->input.p_item = p_item;
+    p_input->input.p_access = NULL;
+    p_input->input.p_stream = NULL;
+    p_input->input.p_demux  = NULL;
+    p_input->input.b_title_demux = VLC_FALSE;
+    p_input->input.i_title  = 0;
+    p_input->input.title    = NULL;
+    p_input->input.b_can_pace_control = VLC_TRUE;
+    p_input->input.b_eof = VLC_FALSE;
+    p_input->input.i_cr_average = 0;
+
+    /* Init control buffer */
+    vlc_mutex_init( p_input, &p_input->lock_control );
+    p_input->i_control = 0;
+    p_input->p_sys = NULL;
 
     /* Parse input options */
     vlc_mutex_lock( &p_item->lock );
@@ -113,166 +143,15 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
     }
     vlc_mutex_unlock( &p_item->lock );
 
-    /* Create a few object variables we'll need later on */
-    var_Create( p_input, "video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Create( p_input, "audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Create( p_input, "audio-channel", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
-    var_Create( p_input, "spu-channel", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
-    var_Create( p_input, "sub-file", VLC_VAR_FILE | VLC_VAR_DOINHERIT );
-    var_Create( p_input, "sub-autodetect-file", VLC_VAR_BOOL |
-                VLC_VAR_DOINHERIT );
-    var_Create( p_input, "sub-autodetect-path", VLC_VAR_STRING |
-                VLC_VAR_DOINHERIT );
-    var_Create( p_input, "sub-autodetect-fuzzy", VLC_VAR_INTEGER |
-                VLC_VAR_DOINHERIT );
-
-    var_Create( p_input, "sout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
-    var_Create( p_input, "sout-all",   VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Create( p_input, "sout-audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Create( p_input, "sout-video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Create( p_input, "sout-keep",  VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-
-    /* repeat variable */
-    var_Create( p_input, "input-repeat", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
-
-    /* start/stop time */
-    var_Create( p_input, "start-time", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
-    var_Create( p_input, "stop-time", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
-
-    /* decoders */
-    var_Create( p_input, "minimize-threads", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
-
-    /* play status */
-
-    /* position variable */
-    var_Create( p_input, "position",  VLC_VAR_FLOAT );  /* position 0.0->1.0 */
-    var_Create( p_input, "position-offset",  VLC_VAR_FLOAT );  /* relative */
-    val.f_float = 0.0;
-    var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
-    var_AddCallback( p_input, "position", PositionCallback, NULL );
-    var_AddCallback( p_input, "position-offset", PositionCallback, NULL );
-
-    /* time variable */
-    var_Create( p_input, "time",  VLC_VAR_TIME );
-    var_Create( p_input, "time-offset",  VLC_VAR_TIME );    /* relative */
-    val.i_time = 0;
-    var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
-    var_AddCallback( p_input, "time", TimeCallback, NULL );
-    var_AddCallback( p_input, "time-offset", TimeCallback, NULL );
-
-    /* length variable */
-    var_Create( p_input, "length",  VLC_VAR_TIME );
-    val.i_time = 0;
-    var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
-
-    /* rate variable */
-    var_Create( p_input, "rate", VLC_VAR_INTEGER );
-    var_Create( p_input, "rate-slower", VLC_VAR_VOID );
-    var_Create( p_input, "rate-faster", VLC_VAR_VOID );
-    val.i_int = DEFAULT_RATE;
-    var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
-    var_AddCallback( p_input, "rate", RateCallback, NULL );
-    var_AddCallback( p_input, "rate-slower", RateCallback, NULL );
-    var_AddCallback( p_input, "rate-faster", RateCallback, NULL );
-
-    /* state variable */
-    var_Create( p_input, "state", VLC_VAR_INTEGER );
-    val.i_int = INIT_S;
-    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
-    var_AddCallback( p_input, "state", StateCallback, NULL );
-
-    /* state variable */
-    var_Create( p_input, "demuxed-id3", VLC_VAR_BOOL );
-    val.b_bool = VLC_FALSE;
-    var_Change( p_input, "demuxed-id3", VLC_VAR_SETVALUE, &val, NULL );
-
-    /* Initialize thread properties */
-    p_input->b_eof      = 0;
-    p_input->b_out_pace_control = VLC_FALSE;
-    p_input->p_sys      = NULL;
-
-    /* Set target */
-    vlc_mutex_lock( &p_item->lock );
-    p_input->psz_source = strdup( p_item->psz_uri );
-    vlc_mutex_unlock( &p_item->lock );
-
-    /* Stream */
-    p_input->s = NULL;
-
-    /* es out */
-    p_input->p_es_out = NULL;
-
-    /* Demux */
-    p_input->p_demux   = NULL;
-    p_input->pf_demux  = NULL;
-    p_input->pf_rewind = NULL;
-    p_input->pf_demux_control = demux_vaControlDefault;
-    p_input->i_cr_average = config_GetInt( p_input, "cr-average" );
-
-    /* Access */
-    p_input->p_access = NULL;
-    p_input->pf_access_control = NULL;
-
-    p_input->i_bufsize = 0;
-    p_input->i_mtu = 0;
-    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
-
-    /* Initialize statistics */
-    p_input->c_loops                    = 0;
-    p_input->stream.c_packets_read      = 0;
-    p_input->stream.c_packets_trashed   = 0;
-
-    /* Set locks. */
-    vlc_mutex_init( p_input, &p_input->stream.stream_lock );
-    vlc_cond_init( p_input, &p_input->stream.stream_wait );
-    vlc_mutex_init( p_input, &p_input->stream.control.control_lock );
-
-    /* Initialize stream description */
-    p_input->stream.b_changed = 0;
-    p_input->stream.i_es_number = 0;
-    p_input->stream.i_selected_es_number = 0;
-    p_input->stream.i_pgrm_number = 0;
-    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
-    p_input->stream.b_new_mute = MUTE_NO_CHANGE;
-    p_input->stream.i_mux_rate = 0;
-    p_input->stream.b_seekable = 0;
-    p_input->stream.p_sout = NULL;
-
-    /* no stream, no program, no area, no es */
-    p_input->stream.p_new_program = NULL;
-
-    p_input->stream.i_area_nb = 0;
-    p_input->stream.pp_areas = NULL;
-    p_input->stream.p_selected_area = NULL;
-    p_input->stream.p_new_area = NULL;
-
-    p_input->stream.pp_selected_es = NULL;
-    p_input->stream.p_removed_es = NULL;
-    p_input->stream.p_newly_selected_es = NULL;
-
-    /* By default there is one area in a stream */
-    input_AddArea( p_input, 0, 1 );
-    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
-
-    /* Initialize stream control properties. */
-    p_input->stream.control.i_status = INIT_S;
-    p_input->stream.control.i_rate = DEFAULT_RATE;
-    p_input->stream.control.b_mute = 0;
-    p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale");
-
-    msg_Info( p_input, "playlist item `%s'", p_input->psz_source );
+    /* Create Object Variables for private use only */
+    input_ConfigVarInit( p_input );
 
-    /* Bookmarks */
-    var_Create( p_input, "bookmarks", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
-    var_Create( p_input, "bookmark", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE |
-                VLC_VAR_ISCOMMAND );
-    val.psz_string = _("Bookmark");
-    var_Change( p_input, "bookmark", VLC_VAR_SETTEXT, &val, NULL );
-    var_AddCallback( p_input, "bookmark", BookmarkCallback, NULL );
-
-    p_input->i_bookmarks = 0;
-    p_input->pp_bookmarks = NULL;
+    /* Create Objects variables for public Get and Set */
+    input_ControlVarInit( p_input );
+    p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
 
+#if 0
+    /* TODO */
     var_Get( p_input, "bookmarks", &val );
     if( val.psz_string )
     {
@@ -319,15 +198,18 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
         }
         free( val.psz_string );
     }
+#endif
 
+    /* Now we can attach our new input */
     vlc_object_attach( p_input, p_parent );
 
     /* Create thread and wait for its readiness. */
-    if( vlc_thread_create( p_input, "input", RunThread,
+    if( vlc_thread_create( p_input, "input", Run,
                            VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
     {
         msg_Err( p_input, "cannot create input thread" );
-        free( p_input );
+        vlc_object_detach( p_input );
+        vlc_object_destroy( p_input );
         return NULL;
     }
 
@@ -341,34 +223,40 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
  *****************************************************************************/
 void input_StopThread( input_thread_t *p_input )
 {
-    demux_t  *p_demux;
-    access_t *p_access;
+    vlc_list_t *p_list;
+    int i;
 
-    /* Make the thread exit from a possible vlc_cond_wait() */
-    vlc_mutex_lock( &p_input->stream.stream_lock );
+    /* Set die for input */
+    p_input->b_die = VLC_TRUE;
 
-    /* Request thread destruction */
+    /* We cannot touch p_input fields directly (we can from another thread),
+     * so use the vlc_object_find way, it's perfectly safe */
 
-    /* Temporary demux2 hack */
-    p_demux = (demux_t *)vlc_object_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
-    if( p_demux )
+    /* Set die for all access */
+    p_list = vlc_list_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
+    for( i = 0; i < p_list->i_count; i++ )
     {
-        p_demux->b_die = 1;
-        vlc_object_release( p_demux );
+        p_list->p_values[i].p_object->b_die = VLC_TRUE;
     }
+    vlc_list_release( p_list );
 
-    /* Temporary access2 hack */
-    p_access = (access_t *)vlc_object_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
-    if( p_access )
+    /* Set die for all stream */
+    p_list = vlc_list_find( p_input, VLC_OBJECT_STREAM, FIND_CHILD );
+    for( i = 0; i < p_list->i_count; i++ )
     {
-        p_access->b_die = 1;
-        vlc_object_release( p_access );
+        p_list->p_values[i].p_object->b_die = VLC_TRUE;
     }
+    vlc_list_release( p_list );
 
-    p_input->b_die = 1;
+    /* Set die for all demux */
+    p_list = vlc_list_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
+    for( i = 0; i < p_list->i_count; i++ )
+    {
+        p_list->p_values[i].p_object->b_die = VLC_TRUE;
+    }
+    vlc_list_release( p_list );
 
-    vlc_cond_signal( &p_input->stream.stream_wait );
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
+    input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
 }
 
 /*****************************************************************************
@@ -381,106 +269,192 @@ void input_DestroyThread( input_thread_t *p_input )
     /* Join the thread */
     vlc_thread_join( p_input );
 
-    /* Destroy Mutex locks */
-    vlc_mutex_destroy( &p_input->stream.control.control_lock );
-    vlc_cond_destroy( &p_input->stream.stream_wait );
-    vlc_mutex_destroy( &p_input->stream.stream_lock );
+    /* Delete input lock (only after thread joined) */
+    vlc_mutex_destroy( &p_input->lock_control );
+
+    /* TODO: maybe input_DestroyThread should also delete p_input instead
+     * of the playlist but I'm not sure if it's possible */
 }
 
 /*****************************************************************************
- * RunThread: main thread loop
+ * Run: main thread loop
  *****************************************************************************
  * Thread in charge of processing the network packets and demultiplexing.
  *****************************************************************************/
-static int RunThread( input_thread_t *p_input )
+static int Run( input_thread_t *p_input )
 {
-    vlc_value_t  val;
-    mtime_t      i_update_next = -1;
+    int64_t i_intf_update = 0;
 
-    /* Signal right now, otherwise we'll get stuck in a peek */
+    /* Signal that the thread is launched */
     vlc_thread_ready( p_input );
 
-    if( InitThread( p_input ) )
+    if( Init( p_input ) )
     {
         /* If we failed, wait before we are killed, and exit */
-        p_input->b_error = 1;
+        p_input->b_error = VLC_TRUE;
 
-        ErrorThread( p_input );
+        Error( p_input );
 
         /* Tell we're dead */
-        p_input->b_dead = 1;
+        p_input->b_dead = VLC_TRUE;
 
         return 0;
     }
 
-    /* initialization is complete */
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-    p_input->stream.b_changed        = 1;
-    p_input->stream.control.i_status = PLAYING_S;
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    val.i_int = PLAYING_S;
-    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
-
+    /* Main loop */
     while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
     {
-        unsigned int i, i_count;
-
-        p_input->c_loops++;
-
-        vlc_mutex_lock( &p_input->stream.stream_lock );
+        vlc_bool_t b_force_update = VLC_FALSE;
+        int i_ret;
+        int i_type;
+        vlc_value_t val;
 
-        if( p_input->stream.p_new_program )
+        /* Do the read */
+        if( p_input->i_state != PAUSE_S  )
         {
-            if( p_input->pf_set_program != NULL )
-            {
-
-                /* Reinitialize buffer manager. */
-                input_AccessReinit( p_input );
-
-                p_input->pf_set_program( p_input,
-                                         p_input->stream.p_new_program );
+            if( p_input->i_stop <= 0 || p_input->i_time < p_input->i_stop )
+                i_ret=p_input->input.p_demux->pf_demux(p_input->input.p_demux);
+            else
+                i_ret = 0;  /* EOF */
 
-                /* Escape all decoders for the stream discontinuity they
-                 * will encounter. */
-                input_EscapeDiscontinuity( p_input );
+            if( i_ret > 0 )
+            {
+                /* TODO */
+                if( p_input->input.b_title_demux &&
+                    p_input->input.p_demux->info.i_update )
+                {
+                    UpdateFromDemux( p_input );
+                    b_force_update = VLC_TRUE;
+                }
+                else if( !p_input->input.b_title_demux &&
+                          p_input->input.p_access &&
+                          p_input->input.p_access->info.i_update )
+                {
+                    UpdateFromAccess( p_input );
+                    b_force_update = VLC_TRUE;
+                }
+            }
+            else if( i_ret == 0 )    /* EOF */
+            {
+                vlc_value_t repeat;
 
-                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
+                var_Get( p_input, "input-repeat", &repeat );
+                if( repeat.i_int == 0 )
+                {
+                    /* End of file - we do not set b_die because only the
+                     * playlist is allowed to do so. */
+                    msg_Dbg( p_input, "EOF reached" );
+                    p_input->b_eof = VLC_TRUE;
+                    p_input->input.b_eof = VLC_TRUE;
+                }
+                else
                 {
-                    pgrm_descriptor_t * p_pgrm
-                                            = p_input->stream.pp_programs[i];
+                    msg_Dbg( p_input, "repeating the same input (%d)", repeat.i_int );
+                    if( repeat.i_int > 0 )
+                    {
+                        repeat.i_int--;
+                        var_Set( p_input, "input-repeat", repeat );
+                    }
 
-                    /* Reinitialize synchro. */
-                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
+                    /* Seek to title 0 position 0(start) */
+                    val.i_int = 0;
+                    input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
+                    if( p_input->i_start > 0 )
+                    {
+                        val.i_time = p_input->i_start;
+                        input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
+                                           &val );
+                    }
+                    else
+                    {
+                        val.f_float = 0.0;
+                        input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
+                                           &val );
+                    }
                 }
             }
-            p_input->stream.p_new_program = NULL;
+            else if( i_ret < 0 )
+            {
+                p_input->b_error = VLC_TRUE;
+            }
         }
-
-        if( p_input->stream.p_new_area )
+        else
         {
-            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
-            {
-                input_AccessReinit( p_input );
+            /* Small wait */
+            msleep( 10*1000 );
+        }
 
-                p_input->pf_set_area( p_input, p_input->stream.p_new_area );
+        /* Handle control */
+        vlc_mutex_lock( &p_input->lock_control );
+        ControlReduce( p_input );
+        while( !ControlPopNoLock( p_input, &i_type, &val ) )
+        {
+            msg_Dbg( p_input, "control type=%d", i_type );
+            if( Control( p_input, i_type, val ) )
+                b_force_update = VLC_TRUE;
+        }
+        vlc_mutex_unlock( &p_input->lock_control );
 
-                /* Escape all decoders for the stream discontinuity they
-                 * will encounter. */
-                input_EscapeDiscontinuity( p_input );
+        if( b_force_update ||
+            i_intf_update < mdate() )
+        {
+            vlc_value_t val;
+            double f_pos;
+            int64_t i_time, i_length;
+            /* update input status variables */
+            if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_POSITION, &f_pos ) )
+            {
+                val.f_float = (float)f_pos;
+                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
+            }
+            if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
+            {
+                p_input->i_time = i_time;
+                val.i_time = i_time;
+                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
+            }
+            if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH, &i_length ) )
+            {
+                vlc_value_t old_val;
+                var_Get( p_input, "length", &old_val );
+                val.i_time = i_length;
+                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
 
-                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
+                if( old_val.i_time != val.i_time )
                 {
-                    pgrm_descriptor_t * p_pgrm
-                                            = p_input->stream.pp_programs[i];
+                    /* TODO */
+#if 0
+                    char psz_buffer[MSTRTIME_MAX_SIZE];
 
-                    /* Reinitialize synchro. */
-                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
+                    vlc_mutex_lock( &p_input->p_item->lock );
+                    p_input->p_item->i_duration = i_length;
+                    vlc_mutex_unlock( &p_input->p_item->lock );
+
+                    input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
+                       msecstotimestr( psz_buffer, i_length / 1000 ) );
+#endif
                 }
             }
-            p_input->stream.p_new_area = NULL;
+
+            var_SetBool( p_input, "intf-change", VLC_TRUE );
+            i_intf_update = mdate() + I64C(150000);
         }
+    }
+
+    /* Wait we are asked to die */
+    if( !p_input->b_die )
+    {
+        Error( p_input );
+    }
+
+    /* Clean up */
+    End( p_input );
+
+    return 0;
 
+#if 0
+    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
+    {
         if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
         {
             if( p_input->stream.p_selected_area->i_size > 0 )
@@ -532,66 +506,10 @@ static int RunThread( input_thread_t *p_input )
             p_input->stream.p_selected_area->i_seek = NO_SEEK;
         }
 
-        if( p_input->stream.p_removed_es )
-        {
-            input_UnselectES( p_input, p_input->stream.p_removed_es );
-            p_input->stream.p_removed_es = NULL;
-        }
-
-        if( p_input->stream.p_newly_selected_es )
-        {
-            input_SelectES( p_input, p_input->stream.p_newly_selected_es );
-            p_input->stream.p_newly_selected_es = NULL;
-        }
-
-        if( p_input->stream.b_new_mute != MUTE_NO_CHANGE )
-        {
-            if( p_input->stream.b_new_mute )
-            {
-                input_EscapeAudioDiscontinuity( p_input );
-            }
-
-            vlc_mutex_lock( &p_input->stream.control.control_lock );
-            p_input->stream.control.b_mute = p_input->stream.b_new_mute;
-            vlc_mutex_unlock( &p_input->stream.control.control_lock );
-
-            p_input->stream.b_new_mute = MUTE_NO_CHANGE;
-        }
-
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
-
         /* Read and demultiplex some data. */
         i_count = p_input->pf_demux( p_input );
 
-        if( i_count == 0 )
-        {
-            vlc_value_t repeat;
-
-            var_Get( p_input, "input-repeat", &repeat );
-            if( repeat.i_int == 0 || p_input->stream.i_area_nb <= 0 )
-            {
-                /* End of file - we do not set b_die because only the
-                 * playlist is allowed to do so. */
-                msg_Info( p_input, "EOF reached" );
-                p_input->b_eof = 1;
-            }
-            else
-            {
-                msg_Dbg( p_input, "repeating the same input (%d)", repeat.i_int );
-                if( repeat.i_int > 0 )
-                {
-                    repeat.i_int--;
-                    var_Set( p_input, "input-repeat", repeat );
-                }
-
-                p_input->stream.p_new_area = p_input->stream.pp_areas[0];
-                p_input->stream.p_new_area->i_seek = 0;
-            }
-        }
-        else if( i_count < 0 )
-        {
-            p_input->b_error = 1;
-        }
+        XXXXX
 
         if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
         {
@@ -655,285 +573,363 @@ static int RunThread( input_thread_t *p_input )
     EndThread( p_input );
 
     return 0;
+#endif
 }
 
 /*****************************************************************************
- * InitThread: init the input Thread
+ * Init: init the input Thread
  *****************************************************************************/
-static int InitThread( input_thread_t * p_input )
+static int Init( input_thread_t * p_input )
 {
-    vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
-//    float f_fps;
-    double f_fps;
-    mtime_t i_length;
-
-    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
-    char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
-    vlc_value_t val, val1;
-    int64_t i_microsecondperframe;
-
-    subtitle_demux_t *p_sub_toselect = NULL;
-    char             *psz_sub_file = NULL;
+    char *psz_dup = strdup( p_input->input.p_item->psz_uri );
+    char *psz_access = NULL;
+    char *psz_demux  = NULL;
+    char *psz_path   = NULL;
+    char *psz;
+    vlc_value_t val;
 
-    /* Skip the plug-in names */
-    while( *psz_parser && *psz_parser != ':' )
-    {
-        psz_parser++;
-    }
+    /* Open access/stream/demux */
+    psz = strchr( psz_dup, ':' );
 #if defined( WIN32 ) || defined( UNDER_CE )
-    if( psz_parser - p_input->psz_dupsource == 1 )
-    {
-        msg_Warn( p_input, "drive letter %c: found in source string",
-                           p_input->psz_dupsource[0] ) ;
-        psz_parser = "";
-    }
-#endif
-
-    if( !*psz_parser )
+    if( psz - psz_dup == 1 )
     {
-        p_input->psz_access = p_input->psz_demux = "";
-        p_input->psz_name = p_input->psz_source;
-        free( p_input->psz_dupsource );
-        p_input->psz_dupsource = NULL;
+        msg_Warn( p_input, "drive letter %c: found in source string", psz_dup[0] );
     }
     else
+#endif
+    if( psz )
     {
-        *psz_parser++ = '\0';
-
-        /* let's skip '//' */
-        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
-        {
-            psz_parser += 2 ;
-        }
+        *psz++ = '\0';
+        if( psz[0] == '/' && psz[1] == '/' )
+            psz += 2;
 
-        p_input->psz_name = psz_parser ;
+        psz_path = psz;
 
-        /* Come back to parse the access and demux plug-ins */
-        psz_parser = p_input->psz_dupsource;
-
-        if( !*psz_parser )
-        {
-            /* No access */
-            p_input->psz_access = "";
-        }
-        else if( *psz_parser == '/' )
-        {
-            /* No access */
-            p_input->psz_access = "";
-            psz_parser++;
-        }
-        else
+        psz = strchr( psz_dup, '/' );
+        if( psz )
         {
-            p_input->psz_access = psz_parser;
-
-            while( *psz_parser && *psz_parser != '/' )
-            {
-                psz_parser++;
-            }
-
-            if( *psz_parser == '/' )
-            {
-                *psz_parser++ = '\0';
-            }
+            *psz++ = '\0';
+            psz_demux = psz;
         }
 
-        if( !*psz_parser )
-        {
-            /* No demux */
-            p_input->psz_demux = "";
-        }
-        else
-        {
-            p_input->psz_demux = psz_parser;
-        }
+        psz_access = psz_dup;
     }
-
-    msg_Dbg( p_input, "access `%s', demux `%s', name `%s'",
-             p_input->psz_access, p_input->psz_demux, p_input->psz_name );
-
-    if( input_AccessInit( p_input ) == -1 )
+    else
     {
-        free( p_input->psz_source );
-        if( p_input->psz_dupsource != NULL )
-        {
-            free( p_input->psz_dupsource );
-        }
-
-        return VLC_EGENERIC;
+        psz_path = psz_dup;
     }
 
-    /* Initialize optional stream output. (before demuxer)*/
-    var_Get( p_input, "sout", &val );
-    if( val.psz_string != NULL )
+    if( psz_access == NULL ) psz_access = "";
+    if( psz_demux == NULL )  psz_demux = "";
+    if( psz_path == NULL )   psz_path = "";
+
+    msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
+            p_input->input.p_item->psz_uri,
+             psz_access, psz_demux, psz_path );
+
+    /* Initialize optional stream output. (before access/demuxer) */
+    psz = var_GetString( p_input, "sout" );
+    if( *psz )
     {
-        if ( *val.psz_string && (p_input->stream.p_sout =
-             sout_NewInstance( p_input, val.psz_string )) == NULL )
+        p_input->p_sout = sout_NewInstance( p_input, psz );
+        if( p_input->p_sout == NULL )
         {
             msg_Err( p_input, "cannot start stream output instance, aborting" );
-            free( val.psz_string );
+            free( psz );
+            free( psz_dup );
 
-            input_AccessEnd( p_input );
-            free( p_input->psz_source );
-            if( p_input->psz_dupsource != NULL )
-            {
-                free( p_input->psz_dupsource );
-            }
             return VLC_EGENERIC;
         }
-        free( val.psz_string );
     }
+    free( psz );
 
+    /* Create es out */
     p_input->p_es_out = input_EsOutNew( p_input );
     es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE );
     es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
 
-    /* Find and open appropriate access module */
-    p_input->p_access = module_Need( p_input, "access",
-                                     p_input->psz_access, VLC_TRUE );
-
-    /* Maybe we had an encoded url */
-    if( !p_input->p_access && strchr( p_input->psz_name, '%' ) )
+    /* Try access_demux if no demux given */
+    if( *psz_access && *psz_demux == '\0' )
     {
-        DecodeUrl( p_input->psz_name );
+        p_input->input.p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
+                                             NULL, p_input->p_es_out );
+    }
 
-        msg_Dbg( p_input, "retying with %s", p_input->psz_name );
-        p_input->p_access = module_Need( p_input, "access",
-                                         p_input->psz_access, VLC_TRUE );
+    if( p_input->input.p_demux )
+    {
+        /* Get infos from access_demux */
+        demux2_Control( p_input->input.p_demux,
+                        DEMUX_GET_PTS_DELAY, &p_input->i_pts_delay );
+        p_input->input.b_title_demux = VLC_TRUE;
+        if( demux2_Control( p_input->input.p_demux,
+                            DEMUX_GET_TITLE_INFO,
+                            &p_input->input.title, &p_input->input.i_title ) )
+        {
+            p_input->input.i_title = 0;
+            p_input->input.title   = NULL;
+        }
+        demux2_Control( p_input->input.p_demux, DEMUX_CAN_CONTROL_PACE,
+                        &p_input->input.b_can_pace_control );
+        demux2_Control( p_input->input.p_demux, DEMUX_CAN_PAUSE,
+                        &p_input->input.b_can_pause );
     }
+    else
+    {
+        /* Now try a real access */
+        p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
+
+        /* Access failed, URL encoded ? */
+        if( p_input->input.p_access == NULL && strchr( psz_path, '%' ) )
+        {
+            DecodeUrl( psz_path );
+
+            msg_Dbg( p_input, "retying with access `%s' demux `%s' path `%s'",
+                     psz_access, psz_demux, psz_path );
+
+            p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
+        }
 #ifndef WIN32      /* Remove this gross hack from the win32 build as colons
-                    * are forbidden in filenames on Win32. */
+                        * are forbidden in filenames on Win32. */
 
-    /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
-    if ( p_input->p_access == NULL
-          && (*p_input->psz_demux || *p_input->psz_access) )
-    {
-        p_input->psz_access = p_input->psz_demux = "";
-        p_input->psz_name = p_input->psz_source;
-        free( p_input->psz_dupsource);
-        p_input->psz_dupsource = NULL;
+        /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
+        if( p_input->input.p_access == NULL &&
+            *psz_access == '\0' && ( *psz_demux || *psz_path ) )
+        {
+            free( psz_dup );
+            psz_dup = strdup( p_input->input.p_item->psz_uri );
+            psz_access = "";
+            psz_demux = "";
+            psz_path = psz_dup;
 
-        p_input->p_access = module_Need( p_input, "access",
-                                         p_input->psz_access, VLC_TRUE );
-    }
+            p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
+        }
 #endif
-    if( p_input->p_access == NULL )
-    {
-        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
-                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
-        if ( p_input->stream.p_sout != NULL )
+
+        if( p_input->input.p_access == NULL )
         {
-            sout_DeleteInstance( p_input->stream.p_sout );
+            msg_Err( p_input, "no suitable access module for `%s'",
+                     p_input->input.p_item->psz_uri );
+            goto error;
         }
 
-        input_AccessEnd( p_input );
-        free( p_input->psz_source );
-        if( p_input->psz_dupsource != NULL )
+        /* Get infos from access */
+        access2_Control( p_input->input.p_access,
+                         ACCESS_GET_PTS_DELAY, &p_input->i_pts_delay );
+        p_input->input.b_title_demux = VLC_FALSE;
+        if( access2_Control( p_input->input.p_access,
+                             ACCESS_GET_TITLE_INFO,
+                             &p_input->input.title, &p_input->input.i_title ) )
         {
-            free( p_input->psz_dupsource );
+            p_input->input.i_title = 0;
+            p_input->input.title   = NULL;
+        }
+        access2_Control( p_input->input.p_access, ACCESS_CAN_CONTROL_PACE,
+                         &p_input->input.b_can_pace_control );
+        access2_Control( p_input->input.p_access, ACCESS_CAN_PAUSE,
+                         &p_input->input.b_can_pace_control );
+
+        /* Create the stream_t */
+        p_input->input.p_stream = stream_AccessNew( p_input->input.p_access );
+        if( p_input->input.p_stream == NULL )
+        {
+            msg_Warn( p_input, "cannot create a stream_t from access" );
+            goto error;
         }
-        input_EsOutDelete( p_input->p_es_out );
-        return VLC_EGENERIC;
-    }
 
-    /* Waiting for stream. */
-    if( p_input->i_mtu )
-    {
-        p_input->i_bufsize = p_input->i_mtu;
+        /* Open a demuxer */
+        if( *psz_demux == '\0' && *p_input->input.p_access->psz_demux )
+        {
+            psz_demux = p_input->input.p_access->psz_demux;
+        }
+        p_input->input.p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
+                                             p_input->input.p_stream,
+                                             p_input->p_es_out );
+        if( p_input->input.p_demux == NULL )
+        {
+            msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
+                     psz_access, psz_demux, psz_path );
+            goto error;
+        }
+
+        /* TODO get title from demux */
+        if( p_input->input.i_title <= 0 )
+        {
+            if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TITLE_INFO,
+                                &p_input->input.title, &p_input->input.i_title ) )
+            {
+                p_input->input.i_title = 0;
+                p_input->input.title   = NULL;
+            }
+            else
+            {
+                p_input->input.b_title_demux = VLC_TRUE;
+            }
+        }
     }
-    else
+    /* Create global title (for now, just a copy) */
+    p_input->i_title = p_input->input.i_title;
+    if( p_input->i_title > 0 )
     {
-        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
+        int i;
+        p_input->title = malloc( sizeof( input_title_t *) * p_input->i_title );
+        for( i = 0; i < p_input->i_title; i++ )
+        {
+            p_input->title[i] = vlc_input_title_Duplicate( p_input->input.title[i] );
+        }
+
+        /* Setup variables */
+        input_ControlVarNavigation( p_input );
+        input_ControlVarTitle( p_input, 0 );
     }
+    /* Global flag */
+    p_input->b_can_pace_control = p_input->input.b_can_pace_control;
+    p_input->b_can_pause        = p_input->input.b_can_pause;
+
+    /* Fix pts delay */
+    if( p_input->i_pts_delay <= 0 )
+        p_input->i_pts_delay = DEFAULT_PTS_DELAY;
 
     /* If the desynchronisation requested by the user is < 0, we need to
      * cache more data. */
-    var_Create( p_input, "audio-desync", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
     var_Get( p_input, "audio-desync", &val );
     if( val.i_int < 0 )
         p_input->i_pts_delay -= (val.i_int * 1000);
 
-    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
-    {
-        while( !input_FillBuffer( p_input ) )
-        {
-            if( p_input->b_die || p_input->b_error || p_input->b_eof )
-            {
-                module_Unneed( p_input, p_input->p_access );
-                if ( p_input->stream.p_sout != NULL )
-                {
-                    sout_DeleteInstance( p_input->stream.p_sout );
-                }
-                input_AccessEnd( p_input );
-                free( p_input->psz_source );
-                if( p_input->psz_dupsource != NULL )
-                {
-                    free( p_input->psz_dupsource );
-                }
-                input_EsOutDelete( p_input->p_es_out );
-                return VLC_EGENERIC;
-            }
-        }
-    }
+    /* Init input_thread_sys_t */
+    p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
+    p_input->p_sys->i_sub = 0;
+    p_input->p_sys->sub   = NULL;
 
-    /* Create the stream_t facilities */
-    p_input->s = input_StreamNew( p_input );
-    if( p_input->s == NULL )
-    {
-        /* should never occur yet */
+    /* TODO: check meta data from users */
 
-        msg_Err( p_input, "cannot create stream_t" );
+    /* TODO: get meta data from demuxer */
 
-        module_Unneed( p_input, p_input->p_access );
-        if ( p_input->stream.p_sout != NULL )
+    /* Init length */
+    if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH, &val.i_time ) && val.i_time > 0 )
+    {
+        var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
+        /* TODO update playlist meta data */
+    }
+    /* Start time*/
+    /* Set start time */
+    p_input->i_start = (int64_t)var_GetInteger( p_input, "start-time" ) *
+                       I64C(1000000);
+    p_input->i_stop  = (int64_t)var_GetInteger( p_input, "stop-time" ) *
+                       I64C(1000000);
+
+    if( p_input->i_start > 0 )
+    {
+        if( p_input->i_start >= val.i_time )
         {
-            sout_DeleteInstance( p_input->stream.p_sout );
+            msg_Warn( p_input, "invalid start-time ignored" );
         }
-        input_AccessEnd( p_input );
-        free( p_input->psz_source );
-        if( p_input->psz_dupsource != NULL )
+        else
         {
-            free( p_input->psz_dupsource );
+            vlc_value_t s;
+
+            msg_Dbg( p_input, "start-time: %ds",
+                     (int)( p_input->i_start / I64C(1000000) ) );
+
+            s.i_time = p_input->i_start;
+            input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
         }
-        input_EsOutDelete( p_input->p_es_out );
-        return VLC_EGENERIC;
+    }
+    if( p_input->i_stop > 0 && p_input->i_stop <= p_input->i_start )
+    {
+        msg_Warn( p_input, "invalid stop-time ignored" );
+        p_input->i_stop = 0;
     }
 
-    /* Find and open appropriate demux module */
-    p_input->p_demux =
-        module_Need( p_input, "demux",
-                     (p_input->psz_demux && *p_input->psz_demux) ?
-                     p_input->psz_demux : "$demux",
-                     (p_input->psz_demux && *p_input->psz_demux) ?
-                     VLC_TRUE : VLC_FALSE );
 
-    if( p_input->p_demux == NULL )
-    {
-        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
-                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
+    /* TODO: do subtitle loading */
 
-        input_StreamDelete( p_input->s );
-        module_Unneed( p_input, p_input->p_access );
-        if ( p_input->stream.p_sout != NULL )
-        {
-            sout_DeleteInstance( p_input->stream.p_sout );
-        }
-        input_AccessEnd( p_input );
-        free( p_input->psz_source );
-        if( p_input->psz_dupsource != NULL )
-        {
-            free( p_input->psz_dupsource );
+
+    /* Set up es_out */
+    es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
+    val.b_bool =  VLC_FALSE;
+    if( p_input->p_sout )
+    {
+        var_Get( p_input, "sout-all", &val );
+    }
+    es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE,
+                    val.b_bool ? ES_OUT_MODE_ALL : ES_OUT_MODE_AUTO );
+
+    /* TODO select forced subs */
+#if 0
+    if( p_sub_toselect )
+    {
+        es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
+                        p_sub_toselect->p_es, VLC_TRUE );
+    }
+#endif
+
+    if( p_input->p_sout )
+    {
+        if( p_input->p_sout->i_out_pace_nocontrol > 0 )
+        {
+            p_input->b_out_pace_control = VLC_FALSE;
         }
-        input_EsOutDelete( p_input->p_es_out );
-        return VLC_EGENERIC;
+        else
+        {
+            p_input->b_out_pace_control = VLC_TRUE;
+        }
+        msg_Dbg( p_input, "starting in %s mode",
+                 p_input->b_out_pace_control ? "asynch" : "synch" );
     }
 
+    msg_Dbg( p_input, "`%s' sucessfully opened",
+             p_input->input.p_item->psz_uri );
+
+    /* initialization is complete */
+    p_input->i_state = PLAYING_S;
+
+    val.i_int = PLAYING_S;
+    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
+
+    return VLC_SUCCESS;
+
+error:
+    if( p_input->input.p_demux )
+        demux2_Delete( p_input->input.p_demux );
+
+    if( p_input->input.p_stream )
+        stream_AccessDelete( p_input->input.p_stream );
+
+    if( p_input->input.p_access )
+        access2_Delete( p_input->input.p_access );
+
+    if( p_input->p_es_out )
+        input_EsOutDelete( p_input->p_es_out );
+
+    if( p_input->p_sout )
+        sout_DeleteInstance( p_input->p_sout );
+
+    /* Mark them deleted */
+    p_input->input.p_demux = NULL;
+    p_input->input.p_stream = NULL;
+    p_input->input.p_access = NULL;
+    p_input->p_es_out = NULL;
+    p_input->p_sout = NULL;
+
+    return VLC_EGENERIC;
+
+#if 0
+    vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
+//    float f_fps;
+    double f_fps;
+    mtime_t i_length;
+
+    FIXME
+    p_input->input.i_cr_average = config_GetInt( p_input, "cr-average" );
+    p_input->stream.control.i_status = INIT_S;
+    p_input->stream.control.i_rate = DEFAULT_RATE;
+
+
     /* Init input_thread_sys_t */
     p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
     p_input->p_sys->i_sub = 0;
     p_input->p_sys->sub   = NULL;
 
-    p_input->p_sys->i_stop_time = 0;
-
     /* Get meta information from user */
     var_Create( p_input, "meta-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
     var_Create( p_input, "meta-author", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
@@ -948,37 +944,37 @@ static int InitThread( input_thread_t * p_input )
         vlc_value_t val;
 
         var_Get( p_input, "meta-title", &val );
-        if( val.psz_string && *val.psz_string )
+        if( *val.psz_string )
             vlc_meta_Add( p_meta_user, VLC_META_TITLE, val.psz_string );
-        if( val.psz_string ) free( val.psz_string );
+        free( val.psz_string );
         var_Get( p_input, "meta-author", &val );
-        if( val.psz_string && *val.psz_string )
+        if( *val.psz_string )
             vlc_meta_Add( p_meta_user, VLC_META_AUTHOR, val.psz_string );
-        if( val.psz_string ) free( val.psz_string );
+        free( val.psz_string );
         var_Get( p_input, "meta-artist", &val );
-        if( val.psz_string && *val.psz_string )
+        if( *val.psz_string )
             vlc_meta_Add( p_meta_user, VLC_META_ARTIST, val.psz_string );
-        if( val.psz_string ) free( val.psz_string );
+        free( val.psz_string );
         var_Get( p_input, "meta-genre", &val );
-        if( val.psz_string && *val.psz_string )
+        if( *val.psz_string )
             vlc_meta_Add( p_meta_user, VLC_META_GENRE, val.psz_string );
-        if( val.psz_string ) free( val.psz_string );
+        free( val.psz_string );
         var_Get( p_input, "meta-copyright", &val );
-        if( val.psz_string && *val.psz_string )
+        if( *val.psz_string )
             vlc_meta_Add( p_meta_user, VLC_META_COPYRIGHT, val.psz_string );
-        if( val.psz_string ) free( val.psz_string );
+        free( val.psz_string );
         var_Get( p_input, "meta-description", &val );
-        if( val.psz_string && *val.psz_string )
+        if( *val.psz_string )
             vlc_meta_Add( p_meta_user, VLC_META_DESCRIPTION, val.psz_string );
-        if( val.psz_string ) free( val.psz_string );
+        free( val.psz_string );
         var_Get( p_input, "meta-date", &val );
-        if( val.psz_string && *val.psz_string )
+        if( *val.psz_string )
             vlc_meta_Add( p_meta_user, VLC_META_DATE, val.psz_string );
-        if( val.psz_string ) free( val.psz_string );
+        free( val.psz_string );
         var_Get( p_input, "meta-url", &val );
-        if( val.psz_string && *val.psz_string )
+        if( *val.psz_string )
             vlc_meta_Add( p_meta_user, VLC_META_URL, val.psz_string );
-        if( val.psz_string ) free( val.psz_string );
+        free( val.psz_string );
     }
 
     /* Get meta informations from demuxer */
@@ -1077,25 +1073,6 @@ static int InitThread( input_thread_t * p_input )
         }
     }
 
-    /* Set stop-time and check validity */
-    var_Get( p_input, "stop-time", &val );
-    if( val.i_int > 0 )
-    {
-        vlc_value_t start;
-
-        var_Get( p_input, "start-time", &start );
-        if( start.i_int >= val.i_int )
-        {
-            msg_Warn( p_input, "invalid stop-time, ignored (stop-time < "
-                      "start-time)" );
-        }
-        else
-        {
-            p_input->p_sys->i_stop_time = (int64_t)val.i_int * I64C(1000000);
-            msg_Dbg( p_input, "stop-time %ds", val.i_int );
-        }
-    }
-
     /* Get fps */
     if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
     {
@@ -1161,30 +1138,15 @@ static int InitThread( input_thread_t * p_input )
         es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
                         p_sub_toselect->p_es, VLC_TRUE );
     }
-
-    if( p_input->stream.p_sout )
-    {
-        if( p_input->stream.p_sout->i_out_pace_nocontrol > 0 )
-        {
-            p_input->b_out_pace_control = VLC_FALSE;
-        }
-        else
-        {
-            p_input->b_out_pace_control = VLC_TRUE;
-        }
-        msg_Dbg( p_input, "starting in %s mode",
-                 p_input->b_out_pace_control ? "asynch" : "synch" );
-    }
-
-    return VLC_SUCCESS;
+#endif
 }
 
 /*****************************************************************************
- * ErrorThread: RunThread() error loop
+ * Error: RunThread() error loop
  *****************************************************************************
  * This function is called when an error occured during thread main's loop.
  *****************************************************************************/
-static void ErrorThread( input_thread_t *p_input )
+static void Error( input_thread_t *p_input )
 {
     while( !p_input->b_die )
     {
@@ -1194,55 +1156,39 @@ static void ErrorThread( input_thread_t *p_input )
 }
 
 /*****************************************************************************
- * EndThread: end the input thread
+ * End: end the input thread
  *****************************************************************************/
-static void EndThread( input_thread_t * p_input )
+static void End( input_thread_t * p_input )
 {
-    int i, j;
-#ifdef HAVE_SYS_TIMES_H
-    /* Display statistics */
-    struct tms  cpu_usage;
-    times( &cpu_usage );
-
-    msg_Dbg( p_input, "%ld loops consuming user: %ld, system: %ld",
-             p_input->c_loops, cpu_usage.tms_utime, cpu_usage.tms_stime );
-#else
-    msg_Dbg( p_input, "%ld loops", p_input->c_loops );
-#endif
+    vlc_value_t val;
 
+    msg_Dbg( p_input, "closing `%s'",
+             p_input->input.p_item->psz_uri );
 
-    /* DumpStream: printf some info for debugging purpose */
-#define S   p_input->stream
-    msg_Dbg( p_input, "dumping stream ID 0x%x [OK:%ld/D:%ld]", S.i_stream_id,
-             S.c_packets_read, S.c_packets_trashed );
-#undef S
-    for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
-    {
-#define P   p_input->stream.pp_programs[i]
-        msg_Dbg( p_input, "dumping program 0x%x, version %d (%s)",
-                 P->i_number, P->i_version,
-                 P->b_is_ok ? "complete" : "partial" );
-#undef P
-        for( j = 0; j < p_input->stream.pp_programs[i]->i_es_number; j++ )
-        {
-#define ES  p_input->stream.pp_programs[i]->pp_es[j]
-            msg_Dbg( p_input, "ES 0x%x, "
-                     "stream 0x%x, fourcc `%4.4s', %s [OK:%ld/ERR:%ld]",
-                     ES->i_id, ES->i_stream_id, (char*)&ES->i_fourcc,
-                     ES->p_dec != NULL ? "selected" : "not selected",
-                     ES->c_packets, ES->c_invalid_packets );
-#undef ES
-        }
-    }
+    /* We are at the end */
+    p_input->i_state = END_S;
+
+    val.i_int = END_S;
+    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
+
+    /* Clean control variables */
+    input_ControlVarClean( p_input );
 
-    /* Free demultiplexer's data */
-    if( p_input->p_demux ) module_Unneed( p_input, p_input->p_demux );
+    /* Unload all modules */
+    if( p_input->input.p_demux )
+        demux2_Delete( p_input->input.p_demux );
 
-    /* Free all ES and destroy all decoder threads */
-    input_EndStream( p_input );
+    if( p_input->input.p_stream )
+        stream_AccessDelete( p_input->input.p_stream );
+
+    if( p_input->input.p_access )
+        access2_Delete( p_input->input.p_access );
+
+    if( p_input->p_es_out )
+        input_EsOutDelete( p_input->p_es_out );
 
     /* Close optional stream output instance */
-    if( p_input->stream.p_sout )
+    if( p_input->p_sout )
     {
         vlc_object_t *p_pl =
             vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
@@ -1252,20 +1198,20 @@ static void EndThread( input_thread_t * p_input )
         {
             /* attach sout to the playlist */
             msg_Warn( p_input, "keeping sout" );
-            vlc_object_detach( p_input->stream.p_sout );
-            vlc_object_attach( p_input->stream.p_sout, p_pl );
+            vlc_object_detach( p_input->p_sout );
+            vlc_object_attach( p_input->p_sout, p_pl );
         }
         else
         {
             msg_Warn( p_input, "destroying sout" );
-            sout_DeleteInstance( p_input->stream.p_sout );
+            sout_DeleteInstance( p_input->p_sout );
         }
         if( p_pl )
-        {
             vlc_object_release( p_pl );
-        }
     }
 
+    /* TODO subs */
+#if 0
     /* Destroy subtitles demuxers */
     if( p_input->p_sys )
     {
@@ -1278,30 +1224,471 @@ static void EndThread( input_thread_t * p_input )
             free( p_input->p_sys->sub );
         }
 
-        /* Free input_thread_sys_t */
-        free( p_input->p_sys );
     }
+#endif
+
+    /* Free input_thread_sys_t */
+    free( p_input->p_sys );
 
-    /* Destroy the stream_t facilities */
-    if( p_input->s ) input_StreamDelete( p_input->s );
+    /* Tell we're dead */
+    p_input->b_dead = VLC_TRUE;
+}
 
-    /* Destroy es out */
-    if( p_input->p_es_out ) input_EsOutDelete( p_input->p_es_out );
+/*****************************************************************************
+ * Control
+ *****************************************************************************/
+static inline int ControlPopNoLock( input_thread_t *p_input,
+                                    int *pi_type, vlc_value_t *p_val )
+{
+    if( p_input->i_control <= 0 )
+    {
+        return VLC_EGENERIC;
+    }
 
-    /* Close the access plug-in */
-    if( p_input->p_access ) module_Unneed( p_input, p_input->p_access );
+    *pi_type = p_input->control[0].i_type;
+    *p_val   = p_input->control[0].val;
 
-    input_AccessEnd( p_input );
+    p_input->i_control--;
+    if( p_input->i_control > 0 )
+    {
+        int i;
 
-    /* Free info structures XXX destroy es before 'cause vorbis */
-    msg_Dbg( p_input, "freeing info structures...");
+        for( i = 0; i < p_input->i_control; i++ )
+        {
+            p_input->control[i].i_type = p_input->control[i+1].i_type;
+            p_input->control[i].val    = p_input->control[i+1].val;
+        }
+    }
 
-    free( p_input->psz_source );
-    if( p_input->psz_dupsource != NULL ) free( p_input->psz_dupsource );
+    return VLC_SUCCESS;
+}
 
-    /* Tell we're dead */
-    p_input->b_dead = 1;
+static void ControlReduce( input_thread_t *p_input )
+{
+    int i;
+    for( i = 1; i < p_input->i_control; i++ )
+    {
+        const int i_lt = p_input->control[i-1].i_type;
+        const int i_ct = p_input->control[i].i_type;
+
+        /* XXX We can't merge INPUT_CONTROL_SET_ES */
+        msg_Dbg( p_input, "[%d/%d] l=%d c=%d", i, p_input->i_control, i_lt, i_ct );
+        if( i_lt == i_ct &&
+            ( i_ct == INPUT_CONTROL_SET_STATE ||
+              i_ct == INPUT_CONTROL_SET_RATE ||
+              i_ct == INPUT_CONTROL_SET_POSITION ||
+              i_ct == INPUT_CONTROL_SET_TIME ||
+              i_ct == INPUT_CONTROL_SET_PROGRAM ||
+              i_ct == INPUT_CONTROL_SET_TITLE ||
+              i_ct == INPUT_CONTROL_SET_SEEKPOINT ||
+              i_ct == INPUT_CONTROL_SET_BOOKMARK ) )
+        {
+            int j;
+            msg_Dbg( p_input, "merged at %d", i );
+            /* Remove the i-1 */
+            for( j = i; j <  p_input->i_control; j++ )
+                p_input->control[j-1] = p_input->control[j];
+            p_input->i_control--;
+        }
+        else
+        {
+            /* TODO but that's not that important
+                - merge SET_X with SET_X_CMD
+                - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
+                - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
+                - ?
+                */
+        }
+    }
 }
+
+static vlc_bool_t Control( input_thread_t *p_input, int i_type, vlc_value_t val )
+{
+    vlc_bool_t b_force_update = VLC_FALSE;
+
+    switch( i_type )
+    {
+        case INPUT_CONTROL_SET_DIE:
+            msg_Dbg( p_input, "control: INPUT_CONTROL_SET_DIE proceed" );
+            /* Mark all submodules to die */
+            if( p_input->input.p_access )
+                p_input->input.p_access->b_die = VLC_TRUE;
+            if( p_input->input.p_stream )
+                p_input->input.p_stream->b_die = VLC_TRUE;
+            p_input->input.p_demux->b_die = VLC_TRUE;
+
+            p_input->b_die = VLC_TRUE;
+            break;
+
+        case INPUT_CONTROL_SET_POSITION:
+        case INPUT_CONTROL_SET_POSITION_OFFSET:
+        {
+            double f_pos;
+            if( i_type == INPUT_CONTROL_SET_POSITION )
+            {
+                f_pos = val.f_float;
+            }
+            else
+            {
+                /* Should not fail */
+                demux2_Control( p_input->input.p_demux, DEMUX_GET_POSITION, &f_pos );
+                f_pos += val.f_float;
+            }
+            if( f_pos < 0.0 ) f_pos = 0.0;
+            if( f_pos > 1.0 ) f_pos = 1.0;
+            if( demux2_Control( p_input->input.p_demux, DEMUX_SET_POSITION, f_pos ) )
+            {
+                msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) %2.1f%% failed",
+                         f_pos * 100 );
+            }
+            else
+            {
+                input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+                es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+                b_force_update = VLC_TRUE;
+            }
+            break;
+        }
+
+        case INPUT_CONTROL_SET_TIME:
+        case INPUT_CONTROL_SET_TIME_OFFSET:
+        {
+            int64_t i_time;
+            int i_ret;
+
+            if( i_type == INPUT_CONTROL_SET_TIME )
+            {
+                i_time = val.i_time;
+            }
+            else
+            {
+                /* Should not fail */
+                demux2_Control( p_input->input.p_demux,
+                                DEMUX_GET_TIME, &i_time );
+                i_time += val.i_time;
+            }
+            if( i_time < 0 ) i_time = 0;
+            i_ret = demux2_Control( p_input->input.p_demux,
+                                    DEMUX_SET_TIME, i_time );
+            if( i_ret )
+            {
+                int64_t i_length;
+                /* Emulate it with a SET_POS */
+
+                demux2_Control( p_input->input.p_demux,
+                                DEMUX_GET_LENGTH, &i_length );
+                if( i_length > 0 )
+                {
+                    double f_pos = (double)i_time / (double)i_length;
+                    i_ret = demux2_Control( p_input->input.p_demux,
+                                            DEMUX_SET_POSITION, f_pos );
+                }
+            }
+            if( i_ret )
+            {
+                msg_Err( p_input, "INPUT_CONTROL_SET_TIME(_OFFSET) %lld failed",
+                         i_time );
+            }
+            else
+            {
+                input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+
+                es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+                b_force_update = VLC_TRUE;
+            }
+            break;
+        }
+
+        case INPUT_CONTROL_SET_STATE:
+            if( ( val.i_int == PLAYING_S && p_input->i_state == PAUSE_S ) ||
+                ( val.i_int == PAUSE_S && p_input->i_state == PAUSE_S ) )
+            {
+                int i_ret;
+                if( p_input->input.p_access )
+                    i_ret = access2_Control( p_input->input.p_access,
+                                             ACCESS_SET_PAUSE_STATE, VLC_FALSE );
+                else
+                    i_ret = demux2_Control( p_input->input.p_demux,
+                                            DEMUX_SET_PAUSE_STATE, VLC_FALSE );
+
+                if( i_ret )
+                {
+                    /* FIXME What to do ? */
+                    msg_Warn( p_input, "cannot unset pause -> EOF" );
+                    input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
+                }
+
+                b_force_update = VLC_TRUE;
+
+                /* Switch to play */
+                p_input->i_state = PLAYING_S;
+                val.i_int = PLAYING_S;
+                var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
+
+                /* Reset clock */
+                es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+            }
+            else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S && p_input->b_can_pause )
+            {
+                int i_ret;
+                if( p_input->input.p_access )
+                    i_ret = access2_Control( p_input->input.p_access,
+                                             ACCESS_SET_PAUSE_STATE, VLC_TRUE );
+                else
+                    i_ret = demux2_Control( p_input->input.p_demux,
+                                            DEMUX_SET_PAUSE_STATE, VLC_TRUE );
+
+                b_force_update = VLC_TRUE;
+
+                if( i_ret )
+                {
+                    msg_Warn( p_input, "cannot set pause state" );
+                    val.i_int = p_input->i_state;
+                }
+                else
+                {
+                    val.i_int = PAUSE_S;
+                }
+
+                /* Switch to new state */
+                p_input->i_state = val.i_int;
+                var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
+            }
+            else if( val.i_int == PAUSE_S && !p_input->b_can_pause )
+            {
+                b_force_update = VLC_TRUE;
+
+                /* Correct "state" value */
+                val.i_int = p_input->i_state;
+                var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
+            }
+            else if( val.i_int != PLAYING_S && val.i_int != PAUSE_S )
+            {
+                msg_Err( p_input, "invalid state in INPUT_CONTROL_SET_STATE" );
+            }
+            break;
+
+        case INPUT_CONTROL_SET_RATE:
+        case INPUT_CONTROL_SET_RATE_SLOWER:
+        case INPUT_CONTROL_SET_RATE_FASTER:
+        {
+            int i_rate;
+
+            if( i_type == INPUT_CONTROL_SET_RATE_SLOWER )
+                i_rate = p_input->i_rate * 2;
+            else if( i_type == INPUT_CONTROL_SET_RATE_FASTER )
+                i_rate = p_input->i_rate / 2;
+            else
+                i_rate = val.i_int;
+
+            if( i_rate < INPUT_RATE_MIN )
+            {
+                msg_Dbg( p_input, "cannot set rate faster" );
+                i_rate = INPUT_RATE_MIN;
+            }
+            else if( i_rate > INPUT_RATE_MAX )
+            {
+                msg_Dbg( p_input, "cannot set rate slower" );
+                i_rate = INPUT_RATE_MAX;
+            }
+            if( i_rate != INPUT_RATE_DEFAULT &&
+                ( !p_input->b_can_pace_control || !p_input->b_out_pace_control ) )
+            {
+                msg_Dbg( p_input, "cannot change rate" );
+                i_rate = INPUT_RATE_DEFAULT;
+            }
+            if( i_rate != p_input->i_rate )
+            {
+                p_input->i_rate  = i_rate;
+                val.i_int = i_rate;
+                var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
+
+                /* We haven't send data to decoder when rate != default */
+                if( i_rate == INPUT_RATE_DEFAULT )
+                    input_EsOutDiscontinuity( p_input->p_es_out, VLC_TRUE );
+
+                /* Reset clock */
+                es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+
+                b_force_update = VLC_TRUE;
+            }
+            break;
+        }
+
+        case INPUT_CONTROL_SET_PROGRAM:
+            /* No need to force update, es_out does it if needed */
+            es_out_Control( p_input->p_es_out,
+                            ES_OUT_SET_GROUP, val.i_int );
+            break;
+
+        case INPUT_CONTROL_SET_ES:
+            /* No need to force update, es_out does it if needed */
+            es_out_Control( p_input->p_es_out,
+                            ES_OUT_SET_ES, input_EsOutGetFromID( p_input->p_es_out, val.i_int ) );
+            break;
+
+        case INPUT_CONTROL_SET_TITLE:
+        case INPUT_CONTROL_SET_TITLE_NEXT:
+        case INPUT_CONTROL_SET_TITLE_PREV:
+            if( p_input->input.b_title_demux &&
+                p_input->input.i_title > 0 )
+            {
+                /* TODO */
+                /* FIXME handle demux title */
+                demux_t *p_demux = p_input->input.p_demux;
+                int i_title;
+
+                if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
+                    i_title = p_demux->info.i_title - 1;
+                else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
+                    i_title = p_demux->info.i_title + 1;
+                else
+                    i_title = val.i_int;
+
+                if( i_title >= 0 && i_title < p_input->input.i_title )
+                {
+                    demux2_Control( p_demux, DEMUX_SET_TITLE, i_title );
+
+                    input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+                    es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+
+                    input_ControlVarTitle( p_input, i_title );
+                }
+            }
+            else if( p_input->input.i_title > 0 )
+            {
+                access_t *p_access = p_input->input.p_access;
+                int i_title;
+
+                if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
+                    i_title = p_access->info.i_title - 1;
+                else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
+                    i_title = p_access->info.i_title + 1;
+                else
+                    i_title = val.i_int;
+
+                if( i_title >= 0 && i_title < p_input->input.i_title )
+                {
+                    access2_Control( p_access, ACCESS_SET_TITLE, i_title );
+                    stream_AccessReset( p_input->input.p_stream );
+
+                    input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+                    es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+                }
+            }
+            break;
+        case INPUT_CONTROL_SET_SEEKPOINT:
+        case INPUT_CONTROL_SET_SEEKPOINT_NEXT:
+        case INPUT_CONTROL_SET_SEEKPOINT_PREV:
+            if( p_input->input.b_title_demux &&
+                p_input->input.i_title > 0 )
+            {
+                demux_t *p_demux = p_input->input.p_demux;
+                int i_seekpoint;
+
+                if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
+                    i_seekpoint = p_demux->info.i_seekpoint - 1;
+                else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
+                    i_seekpoint = p_demux->info.i_seekpoint + 1;
+                else
+                    i_seekpoint = val.i_int;
+
+                if( i_seekpoint >= 0 &&
+                    i_seekpoint < p_input->input.title[p_demux->info.i_title]->i_seekpoint )
+                {
+                    demux2_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
+
+                    input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+                    es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+                }
+            }
+            else if( p_input->input.i_title > 0 )
+            {
+                access_t *p_access = p_input->input.p_access;
+                int i_seekpoint;
+
+                if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
+                    i_seekpoint = p_access->info.i_seekpoint - 1;
+                else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
+                    i_seekpoint = p_access->info.i_seekpoint + 1;
+                else
+                    i_seekpoint = val.i_int;
+
+                if( i_seekpoint >= 0 &&
+                    i_seekpoint < p_input->input.title[p_access->info.i_title]->i_seekpoint )
+                {
+                    access2_Control( p_access, ACCESS_SET_SEEKPOINT, i_seekpoint );
+                    stream_AccessReset( p_input->input.p_stream );
+
+                    input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+                    es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+                }
+            }
+            break;
+
+        case INPUT_CONTROL_SET_BOOKMARK:
+        default:
+            msg_Err( p_input, "not yet implemented" );
+            break;
+    }
+
+    return b_force_update;
+}
+
+/*****************************************************************************
+ * UpdateFromDemux:
+ *****************************************************************************/
+static void UpdateFromDemux( input_thread_t *p_input )
+{
+    demux_t *p_demux = p_input->input.p_demux;
+    vlc_value_t v;
+
+    if( p_demux->info.i_update & INPUT_UPDATE_TITLE )
+    {
+        v.i_int = p_demux->info.i_title;
+        var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
+
+        input_ControlVarTitle( p_input, p_demux->info.i_title );
+
+        p_demux->info.i_update &= ~INPUT_UPDATE_TITLE;
+    }
+    if( p_demux->info.i_update & INPUT_UPDATE_SEEKPOINT )
+    {
+        v.i_int = p_demux->info.i_seekpoint;
+        var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
+
+        p_demux->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
+    }
+    p_demux->info.i_update &= ~INPUT_UPDATE_SIZE;
+}
+
+/*****************************************************************************
+ * UpdateFromAccess:
+ *****************************************************************************/
+static void UpdateFromAccess( input_thread_t *p_input )
+{
+    access_t *p_access = p_input->input.p_access;
+    vlc_value_t v;
+
+    if( p_access->info.i_update & INPUT_UPDATE_TITLE )
+    {
+        v.i_int = p_access->info.i_title;
+        var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
+
+        input_ControlVarTitle( p_input, p_access->info.i_title );
+
+        p_access->info.i_update &= ~INPUT_UPDATE_TITLE;
+    }
+    if( p_access->info.i_update & INPUT_UPDATE_SEEKPOINT )
+    {
+        v.i_int = p_access->info.i_seekpoint;
+        var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
+
+        p_access->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
+    }
+    p_access->info.i_update &= ~INPUT_UPDATE_SIZE;
+}
+
 /*****************************************************************************
  * DecodeUrl: decode a given encoded url
  *****************************************************************************/
@@ -1438,273 +1825,4 @@ static void ParseOption( input_thread_t *p_input, const char *psz_option )
     return;
 }
 
-/*****************************************************************************
- * input_SetStatus: change the reading status
- *****************************************************************************/
-
-/* Status changing methods */
-enum
-{
-    INPUT_STATUS_END    = 0,
-    INPUT_STATUS_PLAY   = 1,
-    INPUT_STATUS_PAUSE  = 2,
-    INPUT_STATUS_FASTER = 3,
-    INPUT_STATUS_SLOWER = 4
-};
-
-static void input_SetStatus( input_thread_t *p_input, int i_mode )
-{
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-
-    switch( i_mode )
-    {
-    case INPUT_STATUS_END:
-        p_input->stream.i_new_status = PLAYING_S;
-        p_input->b_eof = 1;
-        msg_Dbg( p_input, "end of stream" );
-        break;
-
-    case INPUT_STATUS_PLAY:
-        p_input->stream.i_new_status = PLAYING_S;
-        msg_Dbg( p_input, "playing at normal rate" );
-        break;
-
-    case INPUT_STATUS_PAUSE:
-        /* XXX: we don't need to check i_status, because input_clock.c
-         * does it for us */
-        p_input->stream.i_new_status = PAUSE_S;
-        msg_Dbg( p_input, "toggling pause" );
-        break;
-
-    case INPUT_STATUS_FASTER:
-        if( p_input->stream.control.i_rate * 4 <= DEFAULT_RATE )
-        {
-            msg_Dbg( p_input, "can not play any faster" );
-        }
-        else
-        {
-            p_input->stream.i_new_status = FORWARD_S;
-            p_input->stream.i_new_rate =
-                                    p_input->stream.control.i_rate / 2;
-
-            if ( p_input->stream.i_new_rate < DEFAULT_RATE )
-            {
-                msg_Dbg( p_input, "playing at %i:1 fast forward",
-                     DEFAULT_RATE / p_input->stream.i_new_rate );
-            }
-            else if ( p_input->stream.i_new_rate > DEFAULT_RATE )
-            {
-                msg_Dbg( p_input, "playing at 1:%i slow motion",
-                      p_input->stream.i_new_rate / DEFAULT_RATE );
-            }
-            else if ( p_input->stream.i_new_rate == DEFAULT_RATE )
-            {
-                p_input->stream.i_new_status = PLAYING_S;
-                msg_Dbg( p_input, "playing at normal rate" );
-            }
-        }
-        break;
-
-    case INPUT_STATUS_SLOWER:
-        if( p_input->stream.control.i_rate >= 8 * DEFAULT_RATE )
-        {
-            msg_Dbg( p_input, "can not play any slower" );
-        }
-        else
-        {
-            p_input->stream.i_new_status = FORWARD_S;
-            p_input->stream.i_new_rate =
-                                    p_input->stream.control.i_rate * 2;
-
-            if ( p_input->stream.i_new_rate < DEFAULT_RATE )
-            {
-                msg_Dbg( p_input, "playing at %i:1 fast forward",
-                     DEFAULT_RATE / p_input->stream.i_new_rate );
-            }
-            else if ( p_input->stream.i_new_rate > DEFAULT_RATE )
-            {
-                msg_Dbg( p_input, "playing at 1:%i slow motion",
-                      p_input->stream.i_new_rate / DEFAULT_RATE );
-            }
-            else if ( p_input->stream.i_new_rate == DEFAULT_RATE )
-            {
-                p_input->stream.i_new_status = PLAYING_S;
-                msg_Dbg( p_input, "playing at normal rate" );
-            }
-        }
-        break;
-
-    default:
-        break;
-    }
-
-    vlc_cond_signal( &p_input->stream.stream_wait );
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-}
-/*****************************************************************************
- * input_SetRate:
- *****************************************************************************/
-static void input_SetRate( input_thread_t *p_input, int i_rate )
-{
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-
-    if( i_rate * 8 < DEFAULT_RATE )
-    {
-        msg_Dbg( p_input, "can not play faster than 8x" );
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
-        return;
-    }
-    if( i_rate > DEFAULT_RATE * 8 )
-    {
-        msg_Dbg( p_input, "can not play slower than 1/8x" );
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
-        return;
-    }
-    p_input->stream.i_new_status = FORWARD_S;
-    p_input->stream.i_new_rate = i_rate;
-
-    if ( p_input->stream.i_new_rate < DEFAULT_RATE )
-    {
-        msg_Dbg( p_input, "playing at %i:1 fast forward",
-             DEFAULT_RATE / p_input->stream.i_new_rate );
-    }
-    else if ( p_input->stream.i_new_rate > DEFAULT_RATE )
-    {
-        msg_Dbg( p_input, "playing at 1:%i slow motion",
-              p_input->stream.i_new_rate / DEFAULT_RATE );
-    }
-    else if ( p_input->stream.i_new_rate == DEFAULT_RATE )
-    {
-        p_input->stream.i_new_status = PLAYING_S;
-        msg_Dbg( p_input, "playing at normal rate" );
-    }
-
-    vlc_cond_signal( &p_input->stream.stream_wait );
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-}
-
-/*****************************************************************************
- * Callbacks  (position, time, state, rate )
- *****************************************************************************/
-static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
-                             vlc_value_t oldval, vlc_value_t newval,
-                             void *p_data )
-{
-    input_thread_t *p_input = (input_thread_t *)p_this;
-
-    msg_Dbg( p_input, "cmd=%s old=%f new=%f", psz_cmd,
-             oldval.f_float, newval.f_float );
-
-    if( !strcmp( psz_cmd, "position-offset" ) )
-    {
-        vlc_value_t val;
-        var_Get( p_input, "position", &val );
-
-        newval.f_float += val.f_float;
-    }
-    var_Change( p_input, "position", VLC_VAR_SETVALUE, &newval, NULL );
 
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-    p_input->stream.p_selected_area->i_seek =
-        (int64_t)( newval.f_float *
-                   (double)p_input->stream.p_selected_area->i_size );
-
-    if( p_input->stream.p_selected_area->i_seek < 0 )
-    {
-        p_input->stream.p_selected_area->i_seek = 0;
-    }
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    return VLC_SUCCESS;
-}
-
-static int TimeCallback( vlc_object_t *p_this, char const *psz_cmd,
-                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
-    input_thread_t *p_input = (input_thread_t *)p_this;
-    vlc_value_t     val;
-
-    /* FIXME TODO FIXME */
-    msg_Dbg( p_input, "cmd=%s old=%lld new=%lld", psz_cmd,
-             oldval.i_time, newval.i_time );
-
-    var_Get( p_input, "length", &val );
-    if( val.i_time > 0 )
-    {
-        val.f_float = (double)newval.i_time / (double)val.i_time;
-        if( !strcmp( psz_cmd, "time-offset" ) )
-        {
-            vlc_value_t t;
-            var_Set( p_input, "position-offset", val );
-
-            var_Get( p_input, "time", &t );
-            t.i_time += newval.i_time;
-            var_Change( p_input, "time", VLC_VAR_SETVALUE, &t, NULL );
-        }
-        else
-        {
-            var_Set( p_input, "position", val );
-            var_Change( p_input, "time", VLC_VAR_SETVALUE, &newval, NULL );
-        }
-    }
-    else
-    {
-        msg_Warn( p_input, "TimeCallback: length <= 0 -> can't seek" );
-    }
-    return VLC_SUCCESS;
-}
-
-static int StateCallback( vlc_object_t *p_this, char const *psz_cmd,
-                          vlc_value_t oldval, vlc_value_t newval,
-                          void *p_data )
-{
-    input_thread_t *p_input = (input_thread_t *)p_this;
-
-    msg_Dbg( p_input, "cmd=%s old=%d new=%d",
-             psz_cmd, oldval.i_int, newval.i_int );
-
-    switch( newval.i_int )
-    {
-        case PLAYING_S:
-            input_SetStatus( p_input, INPUT_STATUS_PLAY );
-            return VLC_SUCCESS;
-        case PAUSE_S:
-            input_SetStatus( p_input, INPUT_STATUS_PAUSE );
-            return VLC_SUCCESS;
-        case END_S:
-            input_SetStatus( p_input, INPUT_STATUS_END );
-            return VLC_SUCCESS;
-        default:
-            msg_Err( p_input, "cannot set new state (invalid)" );
-            return VLC_EGENERIC;
-    }
-}
-
-static int RateCallback( vlc_object_t *p_this, char const *psz_cmd,
-                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
-    input_thread_t *p_input = (input_thread_t *)p_this;
-
-    if( !strcmp( psz_cmd, "rate-slower" ) )
-    {
-        input_SetStatus( p_input, INPUT_STATUS_SLOWER );
-    }
-    else if( !strcmp( psz_cmd, "rate-faster" ) )
-    {
-        input_SetStatus( p_input, INPUT_STATUS_FASTER );
-    }
-    else
-    {
-        msg_Dbg( p_input, "cmd=%s old=%d new=%d",
-                 psz_cmd, oldval.i_int, newval.i_int );
-        input_SetRate( p_input, newval.i_int );
-    }
-    return VLC_SUCCESS;
-}
-
-static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd,
-                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
-    input_thread_t *p_input = (input_thread_t *)p_this;
-    return input_Control( p_input, INPUT_SET_BOOKMARK, newval );
-}
diff --git a/src/input/input_clock.c b/src/input/input_clock.c
deleted file mode 100644 (file)
index a5c873f..0000000
+++ /dev/null
@@ -1,354 +0,0 @@
-/*****************************************************************************
- * input_clock.c: Clock/System date convertions, stream management
- *****************************************************************************
- * Copyright (C) 1999-2004 VideoLAN
- * $Id$
- *
- * Authors: Christophe Massiot <massiot@via.ecp.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#include <string.h>                                    /* memcpy(), memset() */
-
-#include <vlc/vlc.h>
-
-#include "stream_control.h"
-#include "input_ext-intf.h"
-#include "input_ext-dec.h"
-#include "input_ext-plugins.h"
-
-/*
- * DISCUSSION : SYNCHRONIZATION METHOD
- *
- * In some cases we can impose the pace of reading (when reading from a
- * file or a pipe), and for the synchronization we simply sleep() until
- * it is time to deliver the packet to the decoders. When reading from
- * the network, we must be read at the same pace as the server writes,
- * otherwise the kernel's buffer will trash packets. The risk is now to
- * overflow the input buffers in case the server goes too fast, that is
- * why we do these calculations :
- *
- * We compute a mean for the pcr because we want to eliminate the
- * network jitter and keep the low frequency variations. The mean is
- * in fact a low pass filter and the jitter is a high frequency signal
- * that is why it is eliminated by the filter/average.
- *
- * The low frequency variations enable us to synchronize the client clock
- * with the server clock because they represent the time variation between
- * the 2 clocks. Those variations (ie the filtered pcr) are used to compute
- * the presentation dates for the audio and video frames. With those dates
- * we can decode (or trash) the MPEG2 stream at "exactly" the same rate
- * as it is sent by the server and so we keep the synchronization between
- * the server and the client.
- *
- * It is a very important matter if you want to avoid underflow or overflow
- * in all the FIFOs, but it may be not enough.
- */
-
-/* p_input->i_cr_average : Maximum number of samples used to compute the
- * dynamic average value.
- * We use the following formula :
- * new_average = (old_average * c_average + new_sample_value) / (c_average +1)
- */
-
-static void ClockNewRef( pgrm_descriptor_t * p_pgrm,
-                         mtime_t i_clock, mtime_t i_sysdate );
-
-/*****************************************************************************
- * Constants
- *****************************************************************************/
-
-/* Maximum gap allowed between two CRs. */
-#define CR_MAX_GAP 2000000
-
-/* Latency introduced on DVDs with CR == 0 on chapter change - this is from
- * my dice --Meuuh */
-#define CR_MEAN_PTS_GAP 300000
-
-/*****************************************************************************
- * ClockToSysdate: converts a movie clock to system date
- *****************************************************************************/
-static mtime_t ClockToSysdate( input_thread_t * p_input,
-                               pgrm_descriptor_t * p_pgrm, mtime_t i_clock )
-{
-    mtime_t     i_sysdate = 0;
-
-    if( p_pgrm->i_synchro_state == SYNCHRO_OK )
-    {
-        i_sysdate = (mtime_t)(i_clock - p_pgrm->cr_ref)
-                        * (mtime_t)p_input->stream.control.i_rate
-                        * (mtime_t)300;
-        i_sysdate /= 27;
-        i_sysdate /= 1000;
-        i_sysdate += (mtime_t)p_pgrm->sysdate_ref;
-    }
-
-    return( i_sysdate );
-}
-
-/*****************************************************************************
- * ClockCurrent: converts current system date to clock units
- *****************************************************************************
- * Caution : the synchro state must be SYNCHRO_OK for this to operate.
- *****************************************************************************/
-static mtime_t ClockCurrent( input_thread_t * p_input,
-                             pgrm_descriptor_t * p_pgrm )
-{
-    return( (mdate() - p_pgrm->sysdate_ref) * 27 * DEFAULT_RATE
-             / p_input->stream.control.i_rate / 300
-             + p_pgrm->cr_ref );
-}
-
-/*****************************************************************************
- * ClockNewRef: writes a new clock reference
- *****************************************************************************/
-static void ClockNewRef( pgrm_descriptor_t * p_pgrm,
-                         mtime_t i_clock, mtime_t i_sysdate )
-{
-    p_pgrm->cr_ref = i_clock;
-    p_pgrm->sysdate_ref = i_sysdate ;
-}
-
-/*****************************************************************************
- * input_ClockInit: reinitializes the clock reference after a stream
- *                  discontinuity
- *****************************************************************************/
-void input_ClockInit( pgrm_descriptor_t * p_pgrm )
-{
-    p_pgrm->last_cr = 0;
-    p_pgrm->last_pts = 0;
-    p_pgrm->cr_ref = 0;
-    p_pgrm->sysdate_ref = 0;
-    p_pgrm->delta_cr = 0;
-    p_pgrm->c_average_count = 0;
-}
-
-/*****************************************************************************
- * input_ClockManageControl: handles the messages from the interface
- *****************************************************************************
- * Returns UNDEF_S if nothing happened, PAUSE_S if the stream was paused
- *****************************************************************************/
-int input_ClockManageControl( input_thread_t * p_input,
-                               pgrm_descriptor_t * p_pgrm, mtime_t i_clock )
-{
-    vlc_value_t val;
-    int i_return_value = UNDEF_S;
-
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-
-    if( p_input->stream.i_new_status == PAUSE_S )
-    {
-        int i_old_status;
-
-        vlc_mutex_lock( &p_input->stream.control.control_lock );
-        i_old_status = p_input->stream.control.i_status;
-        p_input->stream.control.i_status = PAUSE_S;
-        vlc_mutex_unlock( &p_input->stream.control.control_lock );
-
-        vlc_cond_wait( &p_input->stream.stream_wait,
-                       &p_input->stream.stream_lock );
-        ClockNewRef( p_pgrm, i_clock, p_pgrm->last_pts > mdate() ?
-                                      p_pgrm->last_pts : mdate() );
-
-        if( p_input->stream.i_new_status == PAUSE_S )
-        {
-            /* PAUSE_S undoes the pause state: Return to old state. */
-            vlc_mutex_lock( &p_input->stream.control.control_lock );
-            p_input->stream.control.i_status = i_old_status;
-            vlc_mutex_unlock( &p_input->stream.control.control_lock );
-
-            p_input->stream.i_new_status = UNDEF_S;
-            p_input->stream.i_new_rate = UNDEF_S;
-        }
-
-        /* We handle i_new_status != PAUSE_S below... */
-
-        i_return_value = PAUSE_S;
-    }
-
-    if( p_input->stream.i_new_status != UNDEF_S )
-    {
-        vlc_mutex_lock( &p_input->stream.control.control_lock );
-
-        p_input->stream.control.i_status = p_input->stream.i_new_status;
-
-        ClockNewRef( p_pgrm, i_clock,
-                     ClockToSysdate( p_input, p_pgrm, i_clock ) );
-
-        if( p_input->stream.control.i_status == PLAYING_S )
-        {
-            p_input->stream.control.i_rate = DEFAULT_RATE;
-            p_input->stream.control.b_mute = 0;
-        }
-        else
-        {
-            p_input->stream.control.i_rate = p_input->stream.i_new_rate;
-            p_input->stream.control.b_mute = 1;
-
-            /* Feed the audio decoders with a NULL packet to avoid
-             * discontinuities. */
-            input_EscapeAudioDiscontinuity( p_input );
-        }
-
-        val.i_int = p_input->stream.control.i_rate;
-        var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
-
-        val.i_int = p_input->stream.control.i_status;
-        var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
-
-        p_input->stream.i_new_status = UNDEF_S;
-        p_input->stream.i_new_rate = UNDEF_S;
-
-        vlc_mutex_unlock( &p_input->stream.control.control_lock );
-    }
-
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    return( i_return_value );
-}
-
-/*****************************************************************************
- * input_ClockManageRef: manages a clock reference
- *****************************************************************************/
-void input_ClockManageRef( input_thread_t * p_input,
-                           pgrm_descriptor_t * p_pgrm, mtime_t i_clock )
-{
-    /* take selected program if none specified */
-    if( !p_pgrm )
-    {
-        p_pgrm = p_input->stream.p_selected_program;
-    }
-
-    if( ( p_pgrm->i_synchro_state != SYNCHRO_OK ) ||
-        ( i_clock == 0 && p_pgrm->last_cr != 0 ) )
-    {
-        /* Feed synchro with a new reference point. */
-        ClockNewRef( p_pgrm, i_clock,
-                     p_pgrm->last_pts + CR_MEAN_PTS_GAP > mdate() ?
-                     p_pgrm->last_pts + CR_MEAN_PTS_GAP : mdate() );
-        p_pgrm->i_synchro_state = SYNCHRO_OK;
-
-        if( p_input->stream.b_pace_control
-             && p_input->stream.p_selected_program == p_pgrm )
-        {
-            p_pgrm->last_cr = i_clock;
-            if( !p_input->b_out_pace_control )
-            {
-                mtime_t i_wakeup = ClockToSysdate( p_input, p_pgrm, i_clock );
-                while( (i_wakeup - mdate()) / CLOCK_FREQ > 1 )
-                {
-                    msleep( CLOCK_FREQ );
-                    if( p_input->b_die ) i_wakeup = mdate();
-                }
-                mwait( i_wakeup );
-            }
-        }
-        else
-        {
-            p_pgrm->last_cr = 0;
-            p_pgrm->delta_cr = 0;
-            p_pgrm->c_average_count = 0;
-        }
-    }
-    else
-    {
-        if ( p_pgrm->last_cr != 0 &&
-               (    (p_pgrm->last_cr - i_clock) > CR_MAX_GAP
-                 || (p_pgrm->last_cr - i_clock) < - CR_MAX_GAP ) )
-        {
-            /* Stream discontinuity, for which we haven't received a
-             * warning from the stream control facilities (dd-edited
-             * stream ?). */
-            msg_Warn( p_input, "clock gap, unexpected stream discontinuity" );
-            input_ClockInit( p_pgrm );
-            p_pgrm->i_synchro_state = SYNCHRO_START;
-            input_EscapeDiscontinuity( p_input );
-        }
-
-        p_pgrm->last_cr = i_clock;
-
-        if( p_input->stream.b_pace_control
-             && p_input->stream.p_selected_program == p_pgrm )
-        {
-            /* Wait a while before delivering the packets to the decoder.
-             * In case of multiple programs, we arbitrarily follow the
-             * clock of the selected program. */
-            if( !p_input->b_out_pace_control )
-            {
-                mtime_t i_wakeup = ClockToSysdate( p_input, p_pgrm, i_clock );
-                while( (i_wakeup - mdate()) / CLOCK_FREQ > 1 )
-                {
-                    msleep( CLOCK_FREQ );
-                    if( p_input->b_die ) i_wakeup = mdate();
-                }
-                mwait( i_wakeup );
-            }
-
-            /* Now take into account interface changes. */
-            input_ClockManageControl( p_input, p_pgrm, i_clock );
-        }
-        else
-        {
-            /* Smooth clock reference variations. */
-            mtime_t     i_extrapoled_clock = ClockCurrent( p_input, p_pgrm );
-
-            /* Bresenham algorithm to smooth variations. */
-            if( p_pgrm->c_average_count == p_input->i_cr_average )
-            {
-                p_pgrm->delta_cr = ( p_pgrm->delta_cr
-                                        * (p_input->i_cr_average - 1)
-                                      + ( i_extrapoled_clock - i_clock ) )
-                                    / p_input->i_cr_average;
-            }
-            else
-            {
-                p_pgrm->delta_cr = ( p_pgrm->delta_cr
-                                        * p_pgrm->c_average_count
-                                      + ( i_extrapoled_clock - i_clock ) )
-                                    / (p_pgrm->c_average_count + 1);
-                p_pgrm->c_average_count++;
-            }
-        }
-    }
-}
-
-/*****************************************************************************
- * input_ClockGetTS: manages a PTS or DTS
- *****************************************************************************/
-mtime_t input_ClockGetTS( input_thread_t * p_input,
-                          pgrm_descriptor_t * p_pgrm, mtime_t i_ts )
-{
-    /* take selected program if none specified */
-    if( !p_pgrm )
-    {
-        p_pgrm = p_input->stream.p_selected_program;
-    }
-
-    if( p_pgrm->i_synchro_state == SYNCHRO_OK )
-    {
-        p_pgrm->last_pts = ClockToSysdate( p_input, p_pgrm,
-                                           i_ts + p_pgrm->delta_cr );
-        return( p_pgrm->last_pts + p_input->i_pts_delay );
-    }
-    else
-    {
-        return 0;
-    }
-}
-
diff --git a/src/input/input_dec.c b/src/input/input_dec.c
deleted file mode 100644 (file)
index 98647b2..0000000
+++ /dev/null
@@ -1,924 +0,0 @@
-/*****************************************************************************
- * input_dec.c: Functions for the management of decoders
- *****************************************************************************
- * Copyright (C) 1999-2004 VideoLAN
- * $Id$
- *
- * Authors: Christophe Massiot <massiot@via.ecp.fr>
- *          Gildas Bazin <gbazin@netcourrier.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#include <stdlib.h>
-#include <string.h>                                    /* memcpy(), memset() */
-
-#include <vlc/vlc.h>
-#include <vlc/decoder.h>
-#include <vlc/vout.h>
-
-#include "stream_output.h"
-
-#include "input_ext-intf.h"
-#include "input_ext-plugins.h"
-
-#include "codecs.h"
-
-static void input_NullPacket( input_thread_t *, es_descriptor_t * );
-
-static decoder_t * CreateDecoder( input_thread_t *, es_descriptor_t *, int );
-static int         DecoderThread( decoder_t * );
-static int         DecoderDecode( decoder_t * p_dec, block_t *p_block );
-static void        DeleteDecoder( decoder_t * );
-
-/* Buffers allocation callbacks for the decoders */
-static aout_buffer_t *aout_new_buffer( decoder_t *, int );
-static void aout_del_buffer( decoder_t *, aout_buffer_t * );
-
-static picture_t *vout_new_buffer( decoder_t * );
-static void vout_del_buffer( decoder_t *, picture_t * );
-static void vout_link_picture( decoder_t *, picture_t * );
-static void vout_unlink_picture( decoder_t *, picture_t * );
-
-static es_format_t null_es_format = {0};
-
-struct decoder_owner_sys_t
-{
-    vlc_bool_t      b_own_thread;
-
-    input_thread_t  *p_input;
-
-    aout_instance_t *p_aout;
-    aout_input_t    *p_aout_input;
-
-    vout_thread_t   *p_vout;
-
-    sout_instance_t         *p_sout;
-    sout_packetizer_input_t *p_sout_input;
-
-    /* Some decoders require already packetized data (ie. not truncated) */
-    decoder_t *p_packetizer;
-
-    /* Current format in use by the output */
-    video_format_t video;
-    audio_format_t audio;
-    es_format_t    sout;
-
-    /* fifo */
-    block_fifo_t *p_fifo;
-
-    /* */
-    input_buffers_t *p_method_data;
-    es_descriptor_t *p_es_descriptor;
-};
-
-
-/**
- * Spawns a new decoder thread
- *
- * \param p_input the input thread
- * \param p_es the es descriptor
- * \return the spawned decoder object
- */
-decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
-{
-    decoder_t   *p_dec = NULL;
-    vlc_value_t val;
-
-    /* If we are in sout mode, search for packetizer module */
-    if( !p_es->b_force_decoder && p_input->stream.p_sout )
-    {
-        /* Create the decoder configuration structure */
-        p_dec = CreateDecoder( p_input, p_es, VLC_OBJECT_PACKETIZER );
-        if( p_dec == NULL )
-        {
-            msg_Err( p_input, "could not create packetizer" );
-            return NULL;
-        }
-    }
-    else
-    {
-        /* Create the decoder configuration structure */
-        p_dec = CreateDecoder( p_input, p_es, VLC_OBJECT_DECODER );
-        if( p_dec == NULL )
-        {
-            msg_Err( p_input, "could not create decoder" );
-            return NULL;
-        }
-    }
-
-    if( !p_dec->p_module )
-    {
-        msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n"
-                 "VLC probably does not support this sound or video format.",
-                 (char*)&p_dec->fmt_in.i_codec );
-
-        DeleteDecoder( p_dec );
-        vlc_object_destroy( p_dec );
-        return NULL;
-    }
-
-    if( !p_es->b_force_decoder && p_input->stream.p_sout && p_input->stream.b_pace_control )
-    {
-        msg_Dbg( p_input, "stream out mode -> no decoder thread" );
-        p_dec->p_owner->b_own_thread = VLC_FALSE;
-    }
-    else
-    {
-        var_Get( p_input, "minimize-threads", &val );
-        p_dec->p_owner->b_own_thread = !val.b_bool;
-    }
-
-    if( p_dec->p_owner->b_own_thread )
-    {
-        int i_priority;
-        if ( p_es->i_cat == AUDIO_ES )
-        {
-            i_priority = VLC_THREAD_PRIORITY_AUDIO;
-        }
-        else
-        {
-            i_priority = VLC_THREAD_PRIORITY_VIDEO;
-        }
-
-        /* Spawn the decoder thread */
-        if( vlc_thread_create( p_dec, "decoder", DecoderThread,
-                               i_priority, VLC_FALSE ) )
-        {
-            msg_Err( p_dec, "cannot spawn decoder thread \"%s\"",
-                             p_dec->p_module->psz_object_name );
-            module_Unneed( p_dec, p_dec->p_module );
-            DeleteDecoder( p_dec );
-            vlc_object_destroy( p_dec );
-            return NULL;
-        }
-    }
-
-    /* Select a new ES */
-    INSERT_ELEM( p_input->stream.pp_selected_es,
-                 p_input->stream.i_selected_es_number,
-                 p_input->stream.i_selected_es_number,
-                 p_es );
-
-    p_input->stream.b_changed = 1;
-
-    return p_dec;
-}
-
-/**
- * Kills a decoder thread and waits until it's finished
- *
- * \param p_input the input thread
- * \param p_es the es descriptor
- * \return nothing
- */
-void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
-{
-    decoder_t *p_dec = p_es->p_dec;
-
-    p_dec->b_die = VLC_TRUE;
-
-    if( p_dec->p_owner->b_own_thread )
-    {
-        /* Make sure the thread leaves the function by
-         * sending it an empty block. */
-        block_t *p_block = block_New( p_dec, 0 );
-        input_DecodeBlock( p_dec, p_block );
-
-        vlc_thread_join( p_dec );
-
-        /* Don't module_Unneed() here because of the dll loader that wants
-         * close() in the same thread than open()/decode() */
-    }
-    else
-    {
-        module_Unneed( p_dec, p_dec->p_module );
-    }
-
-    /* Delete decoder configuration */
-    DeleteDecoder( p_dec );
-
-    /* Delete the decoder */
-    vlc_object_destroy( p_dec );
-
-    /* Tell the input there is no more decoder */
-    p_es->p_dec = NULL;
-
-    p_input->stream.b_changed = 1;
-}
-
-/**
- * Put a PES in the decoder's fifo.
- *
- * \param p_dec the decoder object
- * \param p_pes the pes packet
- * \return nothing
- */
-void input_DecodePES( decoder_t * p_dec, pes_packet_t * p_pes )
-{
-    data_packet_t *p_data;
-    int     i_size = 0;
-
-    for( p_data = p_pes->p_first; p_data != NULL; p_data = p_data->p_next )
-    {
-        i_size += p_data->p_payload_end - p_data->p_payload_start;
-    }
-    if( i_size > 0 )
-    {
-        block_t *p_block = block_New( p_dec, i_size );
-        if( p_block )
-        {
-            uint8_t *p_buffer = p_block->p_buffer;
-
-            for( p_data = p_pes->p_first; p_data; p_data = p_data->p_next )
-            {
-                int i_copy = p_data->p_payload_end - p_data->p_payload_start;
-
-                memcpy( p_buffer, p_data->p_payload_start, i_copy );
-
-                p_buffer += i_copy;
-            }
-            p_block->i_pts = p_pes->i_pts;
-            p_block->i_dts = p_pes->i_dts;
-            if( p_pes->b_discontinuity )
-                p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
-            p_block->i_rate = p_pes->i_rate;
-
-            input_DecodeBlock( p_dec, p_block );
-        }
-    }
-
-    input_DeletePES( p_dec->p_owner->p_method_data, p_pes );
-}
-
-/**
- * Put a block_t in the decoder's fifo.
- *
- * \param p_dec the decoder object
- * \param p_block the data block
- */
-void input_DecodeBlock( decoder_t * p_dec, block_t *p_block )
-{
-    if( p_dec->p_owner->b_own_thread )
-    {
-        block_FifoPut( p_dec->p_owner->p_fifo, p_block );
-
-        if( p_dec->p_owner->p_input->b_out_pace_control )
-        {
-            /* FIXME !!!!! */
-            while( !p_dec->b_die && !p_dec->b_error &&
-                   p_dec->p_owner->p_fifo->i_depth > 10 )
-            {
-                msleep( 1000 );
-            }
-        }
-    }
-    else
-    {
-        if( p_dec->b_error || p_block->i_buffer <= 0 )
-        {
-            block_Release( p_block );
-        }
-        else
-        {
-            DecoderDecode( p_dec, p_block );
-        }
-    }
-}
-
-/**
- * Create a NULL packet for padding in case of a data loss
- *
- * \param p_input the input thread
- * \param p_es es descriptor
- * \return nothing
- */
-static void input_NullPacket( input_thread_t * p_input,
-                              es_descriptor_t * p_es )
-{
-    block_t *p_block = block_New( p_input, PADDING_PACKET_SIZE );
-    if( p_block )
-    {
-        memset( p_block->p_buffer, 0, PADDING_PACKET_SIZE );
-        p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
-
-        block_FifoPut( p_es->p_dec->p_owner->p_fifo, p_block );
-    }
-}
-
-/**
- * Send a NULL packet to the decoders
- *
- * \param p_input the input thread
- * \return nothing
- */
-void input_EscapeDiscontinuity( input_thread_t * p_input )
-{
-    unsigned int i_es, i;
-
-    for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
-    {
-        es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
-
-        if( p_es->p_dec != NULL )
-        {
-            for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
-            {
-                input_NullPacket( p_input, p_es );
-            }
-        }
-    }
-}
-
-/**
- * Send a NULL packet to the audio decoders
- *
- * \param p_input the input thread
- * \return nothing
- */
-void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
-{
-    unsigned int i_es, i;
-
-    for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
-    {
-        es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es];
-
-        if( p_es->p_dec != NULL && p_es->i_cat == AUDIO_ES )
-        {
-            for( i = 0; i < PADDING_PACKET_NUMBER; i++ )
-            {
-                input_NullPacket( p_input, p_es );
-            }
-        }
-    }
-}
-
-/**
- * Create a decoder object
- *
- * \param p_input the input thread
- * \param p_es the es descriptor
- * \param i_object_type Object type as define in include/vlc_objects.h
- * \return the decoder object
- */
-static decoder_t * CreateDecoder( input_thread_t * p_input,
-                                  es_descriptor_t * p_es, int i_object_type )
-{
-    decoder_t *p_dec;
-
-    p_dec = vlc_object_create( p_input, i_object_type );
-    if( p_dec == NULL )
-    {
-        msg_Err( p_input, "out of memory" );
-        return NULL;
-    }
-
-    p_dec->pf_decode_audio = 0;
-    p_dec->pf_decode_video = 0;
-    p_dec->pf_decode_sub = 0;
-    p_dec->pf_packetize = 0;
-
-    /* Initialize the decoder fifo */
-    p_dec->p_module = NULL;
-
-    es_format_Copy( &p_dec->fmt_in, &p_es->fmt );
-
-    if( p_es->p_waveformatex )
-    {
-#define p_wf ((WAVEFORMATEX *)p_es->p_waveformatex)
-        p_dec->fmt_in.audio.i_channels = p_wf->nChannels;
-        p_dec->fmt_in.audio.i_rate = p_wf->nSamplesPerSec;
-        p_dec->fmt_in.i_bitrate = p_wf->nAvgBytesPerSec * 8;
-        p_dec->fmt_in.audio.i_blockalign = p_wf->nBlockAlign;
-        p_dec->fmt_in.audio.i_bitspersample = p_wf->wBitsPerSample;
-        p_dec->fmt_in.i_extra = p_wf->cbSize;
-        p_dec->fmt_in.p_extra = NULL;
-        if( p_wf->cbSize )
-        {
-            p_dec->fmt_in.p_extra = malloc( p_wf->cbSize );
-            memcpy( p_dec->fmt_in.p_extra, &p_wf[1], p_wf->cbSize );
-        }
-    }
-
-    if( p_es->p_bitmapinfoheader )
-    {
-#define p_bih ((BITMAPINFOHEADER *) p_es->p_bitmapinfoheader)
-        p_dec->fmt_in.i_extra = p_bih->biSize - sizeof(BITMAPINFOHEADER);
-        p_dec->fmt_in.p_extra = NULL;
-        if( p_dec->fmt_in.i_extra )
-        {
-            p_dec->fmt_in.p_extra = malloc( p_dec->fmt_in.i_extra );
-            memcpy( p_dec->fmt_in.p_extra, &p_bih[1], p_dec->fmt_in.i_extra );
-        }
-
-        p_dec->fmt_in.video.i_width = p_bih->biWidth;
-        p_dec->fmt_in.video.i_height = p_bih->biHeight;
-    }
-
-    /* FIXME
-     *  - 1: beurk
-     *  - 2: I'm not sure there isn't any endian problem here (spu)... */
-    if( p_es->i_cat == SPU_ES && p_es->p_demux_data )
-    {
-        if( ( p_es->i_fourcc == VLC_FOURCC( 's', 'p', 'u', ' ' ) ||
-              p_es->i_fourcc == VLC_FOURCC( 's', 'p', 'u', 'b' ) ) &&
-            *((uint32_t*)p_es->p_demux_data) == 0xBeef )
-        {
-            memcpy( p_dec->fmt_in.subs.spu.palette,
-                    p_es->p_demux_data, 17 * 4 );
-        }
-        else if( p_es->i_fourcc == VLC_FOURCC( 'd', 'v', 'b', 's' ) &&
-                 p_es->p_spuinfo )
-        {
-            dvb_spuinfo_t *p_dvbs = (dvb_spuinfo_t*)p_es->p_spuinfo;
-            p_dec->fmt_in.subs.dvb.i_id = p_dvbs->i_id;
-        }
-    }
-
-    p_dec->fmt_in.i_cat = p_es->i_cat;
-    p_dec->fmt_in.i_codec = p_es->i_fourcc;
-
-    p_dec->fmt_out = null_es_format;
-
-    /* Allocate our private structure for the decoder */
-    p_dec->p_owner = (decoder_owner_sys_t*)malloc(sizeof(decoder_owner_sys_t));
-    if( p_dec->p_owner == NULL )
-    {
-        msg_Err( p_dec, "out of memory" );
-        return NULL;
-    }
-    p_dec->p_owner->b_own_thread = VLC_TRUE;
-    p_dec->p_owner->p_input = p_input;
-    p_dec->p_owner->p_aout = NULL;
-    p_dec->p_owner->p_aout_input = NULL;
-    p_dec->p_owner->p_vout = NULL;
-    p_dec->p_owner->p_sout = p_input->stream.p_sout;
-    p_dec->p_owner->p_sout_input = NULL;
-    p_dec->p_owner->p_packetizer = NULL;
-    p_dec->p_owner->p_es_descriptor = p_es;
-
-
-    /* decoder fifo */
-    if( ( p_dec->p_owner->p_fifo = block_FifoNew( p_dec ) ) == NULL )
-    {
-        msg_Err( p_dec, "out of memory" );
-        return NULL;
-    }
-    p_dec->p_owner->p_method_data = p_input->p_method_data;
-
-    /* Set buffers allocation callbacks for the decoders */
-    p_dec->pf_aout_buffer_new = aout_new_buffer;
-    p_dec->pf_aout_buffer_del = aout_del_buffer;
-    p_dec->pf_vout_buffer_new = vout_new_buffer;
-    p_dec->pf_vout_buffer_del = vout_del_buffer;
-    p_dec->pf_picture_link    = vout_link_picture;
-    p_dec->pf_picture_unlink  = vout_unlink_picture;
-
-    vlc_object_attach( p_dec, p_input );
-
-    /* Find a suitable decoder/packetizer module */
-    if( i_object_type == VLC_OBJECT_DECODER )
-        p_dec->p_module = module_Need( p_dec, "decoder", "$codec", 0 );
-    else
-        p_dec->p_module = module_Need( p_dec, "packetizer", "$packetizer", 0 );
-
-    /* Check if decoder requires already packetized data */
-    if( i_object_type == VLC_OBJECT_DECODER &&
-        p_dec->b_need_packetized && !p_dec->fmt_in.b_packetized )
-    {
-        p_dec->p_owner->p_packetizer =
-            vlc_object_create( p_input, VLC_OBJECT_PACKETIZER );
-        if( p_dec->p_owner->p_packetizer )
-        {
-            p_dec->p_owner->p_packetizer->fmt_in = null_es_format;
-            p_dec->p_owner->p_packetizer->fmt_out = null_es_format;
-            es_format_Copy( &p_dec->p_owner->p_packetizer->fmt_in,
-                            &p_dec->fmt_in );
-
-            vlc_object_attach( p_dec->p_owner->p_packetizer, p_input );
-
-            p_dec->p_owner->p_packetizer->p_module =
-                module_Need( p_dec->p_owner->p_packetizer,
-                             "packetizer", "$packetizer", 0 );
-
-            if( !p_dec->p_owner->p_packetizer->p_module )
-            {
-                es_format_Clean( &p_dec->p_owner->p_packetizer->fmt_in );
-                vlc_object_detach( p_dec->p_owner->p_packetizer );
-                vlc_object_destroy( p_dec->p_owner->p_packetizer );
-            }
-        }
-    }
-
-    return p_dec;
-}
-
-/**
- * The decoding main loop
- *
- * \param p_dec the decoder
- * \return 0
- */
-static int DecoderThread( decoder_t * p_dec )
-{
-    block_t *p_block;
-
-    /* The decoder's main loop */
-    while( !p_dec->b_die && !p_dec->b_error )
-    {
-        if( ( p_block = block_FifoGet( p_dec->p_owner->p_fifo ) ) == NULL )
-        {
-            p_dec->b_error = 1;
-            break;
-        }
-        if( DecoderDecode( p_dec, p_block ) != VLC_SUCCESS )
-        {
-            break;
-        }
-    }
-
-    while( !p_dec->b_die )
-    {
-        /* Trash all received PES packets */
-        p_block = block_FifoGet( p_dec->p_owner->p_fifo );
-        if( p_block ) block_Release( p_block );
-    }
-
-    /* We do it here because of the dll loader that wants close() in the
-     * same thread than open()/decode() */
-    module_Unneed( p_dec, p_dec->p_module );
-
-    return 0;
-}
-
-/**
- * Decode a block
- *
- * \param p_dec the decoder object
- * \param p_block the block to decode
- * \return VLC_SUCCESS or an error code
- */
-static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
-{
-    if( p_block->i_buffer <= 0 )
-    {
-        block_Release( p_block );
-        return VLC_SUCCESS;
-    }
-
-    if( p_dec->i_object_type == VLC_OBJECT_PACKETIZER )
-    {
-        block_t *p_sout_block;
-
-        while( (p_sout_block = p_dec->pf_packetize( p_dec, &p_block )) )
-        {
-            if( !p_dec->p_owner->p_sout_input )
-            {
-                es_format_Copy( &p_dec->p_owner->sout, &p_dec->fmt_out );
-                if( p_dec->p_owner->p_es_descriptor->p_pgrm )
-                {
-                    p_dec->p_owner->sout.i_group =
-                        p_dec->p_owner->p_es_descriptor->p_pgrm->i_number;
-                }
-                p_dec->p_owner->sout.i_id =
-                    p_dec->p_owner->p_es_descriptor->i_id - 1;
-                if( p_dec->fmt_in.psz_language )
-                {
-                    p_dec->p_owner->sout.psz_language =
-                        strdup( p_dec->fmt_in.psz_language );
-                }
-
-                p_dec->p_owner->p_sout_input =
-                    sout_InputNew( p_dec->p_owner->p_sout,
-                                   &p_dec->p_owner->sout );
-
-                if( p_dec->p_owner->p_sout_input == NULL )
-                {
-                    msg_Err( p_dec, "cannot create packetizer output" );
-                    p_dec->b_error = VLC_TRUE;
-
-                    while( p_sout_block )
-                    {
-                        block_t *p_next = p_sout_block->p_next;
-                        block_Release( p_sout_block );
-                        p_sout_block = p_next;
-                    }
-                    break;
-                }
-            }
-
-            while( p_sout_block )
-            {
-                block_t       *p_next = p_sout_block->p_next;
-
-                p_sout_block->p_next = NULL;
-
-                sout_InputSendBuffer( p_dec->p_owner->p_sout_input,
-                                      p_sout_block );
-
-                p_sout_block = p_next;
-            }
-
-            /* For now it's enough, as only sout inpact on this flag */
-            if( p_dec->p_owner->p_sout->i_out_pace_nocontrol > 0 &&
-                p_dec->p_owner->p_input->b_out_pace_control )
-            {
-                msg_Dbg( p_dec, "switching to synch mode" );
-                p_dec->p_owner->p_input->b_out_pace_control = VLC_FALSE;
-            }
-            else if( p_dec->p_owner->p_sout->i_out_pace_nocontrol <= 0 &&
-                     !p_dec->p_owner->p_input->b_out_pace_control )
-            {
-                msg_Dbg( p_dec, "switching to asynch mode" );
-                p_dec->p_owner->p_input->b_out_pace_control = VLC_TRUE;
-            }
-        }
-    }
-    else if( p_dec->fmt_in.i_cat == AUDIO_ES )
-    {
-        aout_buffer_t *p_aout_buf;
-
-        if( p_dec->p_owner->p_packetizer )
-        {
-            block_t *p_packetized_block;
-            decoder_t *p_packetizer = p_dec->p_owner->p_packetizer;
-
-            while( (p_packetized_block =
-                    p_packetizer->pf_packetize( p_packetizer, &p_block )) )
-            {
-                while( (p_aout_buf =
-                        p_dec->pf_decode_audio( p_dec, &p_packetized_block )) )
-                {
-                    aout_DecPlay( p_dec->p_owner->p_aout,
-                                  p_dec->p_owner->p_aout_input, p_aout_buf );
-                }
-            }
-        }
-        else while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) )
-        {
-            aout_DecPlay( p_dec->p_owner->p_aout,
-                          p_dec->p_owner->p_aout_input, p_aout_buf );
-        }
-    }
-    else if( p_dec->fmt_in.i_cat == VIDEO_ES )
-    {
-        picture_t *p_pic;
-
-        if( p_dec->p_owner->p_packetizer )
-        {
-            block_t *p_packetized_block;
-            decoder_t *p_packetizer = p_dec->p_owner->p_packetizer;
-
-            while( (p_packetized_block =
-                    p_packetizer->pf_packetize( p_packetizer, &p_block )) )
-            {
-                while( (p_pic =
-                        p_dec->pf_decode_video( p_dec, &p_packetized_block )) )
-                {
-                    vout_DatePicture( p_dec->p_owner->p_vout, p_pic,
-                                      p_pic->date );
-                    vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
-                }
-            }
-        }
-        else while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) )
-        {
-            vout_DatePicture( p_dec->p_owner->p_vout, p_pic, p_pic->date );
-            vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
-        }
-    }
-    else if( p_dec->fmt_in.i_cat == SPU_ES )
-    {
-        p_dec->pf_decode_sub( p_dec, &p_block );
-    }
-    else
-    {
-        msg_Err( p_dec, "unknown ES format" );
-        p_dec->b_error = 1;
-    }
-
-    return p_dec->b_error ? VLC_EGENERIC : VLC_SUCCESS;
-}
-
-/**
- * Destroys a decoder object
- *
- * \param p_dec the decoder object
- * \return nothing
- */
-static void DeleteDecoder( decoder_t * p_dec )
-{
-    vlc_object_detach( p_dec );
-
-    msg_Dbg( p_dec, "killing decoder fourcc `%4.4s', %d PES in FIFO",
-             (char*)&p_dec->fmt_in.i_codec,
-             p_dec->p_owner->p_fifo->i_depth );
-
-    /* Free all packets still in the decoder fifo. */
-    block_FifoEmpty( p_dec->p_owner->p_fifo );
-    block_FifoRelease( p_dec->p_owner->p_fifo );
-
-   /* Cleanup */
-    if( p_dec->p_owner->p_aout_input )
-        aout_DecDelete( p_dec->p_owner->p_aout, p_dec->p_owner->p_aout_input );
-
-    if( p_dec->p_owner->p_vout )
-    {
-        int i_pic;
-
-#define p_pic p_dec->p_owner->p_vout->render.pp_picture[i_pic]
-        /* Hack to make sure all the the pictures are freed by the decoder */
-        for( i_pic = 0; i_pic < p_dec->p_owner->p_vout->render.i_pictures;
-             i_pic++ )
-        {
-            if( p_pic->i_status == RESERVED_PICTURE )
-                vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
-            if( p_pic->i_refcount > 0 )
-                vout_UnlinkPicture( p_dec->p_owner->p_vout, p_pic );
-        }
-#undef p_pic
-
-        /* We are about to die. Reattach video output to p_vlc. */
-        vout_Request( p_dec, p_dec->p_owner->p_vout, 0, 0, 0, 0 );
-    }
-
-    if( p_dec->p_owner->p_sout_input )
-    {
-        sout_InputDelete( p_dec->p_owner->p_sout_input );
-        es_format_Clean( &p_dec->p_owner->sout );
-    }
-
-    es_format_Clean( &p_dec->fmt_in );
-    es_format_Clean( &p_dec->fmt_out );
-
-    if( p_dec->p_owner->p_packetizer )
-    {
-        module_Unneed( p_dec->p_owner->p_packetizer,
-                       p_dec->p_owner->p_packetizer->p_module );
-        es_format_Clean( &p_dec->p_owner->p_packetizer->fmt_in );
-        es_format_Clean( &p_dec->p_owner->p_packetizer->fmt_out );
-        vlc_object_detach( p_dec->p_owner->p_packetizer );
-        vlc_object_destroy( p_dec->p_owner->p_packetizer );
-    }
-
-    free( p_dec->p_owner );
-}
-
-/*****************************************************************************
- * Buffers allocation callbacks for the decoders
- *****************************************************************************/
-static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples )
-{
-    decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner;
-    aout_buffer_t *p_buffer;
-
-    if( p_sys->p_aout_input != NULL &&
-        ( p_dec->fmt_out.audio.i_rate != p_sys->audio.i_rate ||
-          p_dec->fmt_out.audio.i_original_channels !=
-              p_sys->audio.i_original_channels ||
-          p_dec->fmt_out.audio.i_bytes_per_frame !=
-              p_sys->audio.i_bytes_per_frame ) )
-    {
-        /* Parameters changed, restart the aout */
-        aout_DecDelete( p_sys->p_aout, p_sys->p_aout_input );
-        p_sys->p_aout_input = NULL;
-    }
-
-    if( p_sys->p_aout_input == NULL )
-    {
-        p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
-        p_sys->audio = p_dec->fmt_out.audio;
-        p_sys->p_aout_input =
-            aout_DecNew( p_dec, &p_sys->p_aout, &p_sys->audio );
-        if( p_sys->p_aout_input == NULL )
-        {
-            msg_Err( p_dec, "failed to create audio output" );
-            p_dec->b_error = VLC_TRUE;
-            return NULL;
-        }
-        p_dec->fmt_out.audio.i_bytes_per_frame =
-            p_sys->audio.i_bytes_per_frame;
-    }
-
-    p_buffer = aout_DecNewBuffer( p_sys->p_aout, p_sys->p_aout_input,
-                                  i_samples );
-
-    return p_buffer;
-}
-
-static void aout_del_buffer( decoder_t *p_dec, aout_buffer_t *p_buffer )
-{
-    aout_DecDeleteBuffer( p_dec->p_owner->p_aout,
-                          p_dec->p_owner->p_aout_input, p_buffer );
-}
-
-static picture_t *vout_new_buffer( decoder_t *p_dec )
-{
-    decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner;
-    picture_t *p_pic;
-
-    if( p_sys->p_vout == NULL ||
-        p_dec->fmt_out.video.i_width != p_sys->video.i_width ||
-        p_dec->fmt_out.video.i_height != p_sys->video.i_height ||
-        p_dec->fmt_out.video.i_chroma != p_sys->video.i_chroma ||
-        p_dec->fmt_out.video.i_aspect != p_sys->video.i_aspect )
-    {
-        if( !p_dec->fmt_out.video.i_width ||
-            !p_dec->fmt_out.video.i_height )
-        {
-            /* Can't create a new vout without display size */
-            return NULL;
-        }
-
-        p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
-        p_sys->video = p_dec->fmt_out.video;
-
-        p_sys->p_vout = vout_Request( p_dec, p_sys->p_vout,
-                                      p_sys->video.i_width,
-                                      p_sys->video.i_height,
-                                      p_sys->video.i_chroma,
-                                      p_sys->video.i_aspect );
-
-        if( p_sys->p_vout == NULL )
-        {
-            msg_Err( p_dec, "failed to create video output" );
-            p_dec->b_error = VLC_TRUE;
-            return NULL;
-        }
-    }
-
-    /* Get a new picture */
-    while( !(p_pic = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 ) ) )
-    {
-        int i_pic, i_ready_pic = 0;
-
-        if( p_dec->b_die || p_dec->b_error )
-        {
-            return NULL;
-        }
-
-#define p_pic p_dec->p_owner->p_vout->render.pp_picture[i_pic]
-        /* Check the decoder doesn't leak pictures */
-        for( i_pic = 0; i_pic < p_dec->p_owner->p_vout->render.i_pictures;
-             i_pic++ )
-        {
-            if( p_pic->i_status == READY_PICTURE && i_ready_pic++ > 0 ) break;
-
-            if( p_pic->i_status != DISPLAYED_PICTURE &&
-                p_pic->i_status != RESERVED_PICTURE &&
-                p_pic->i_status != READY_PICTURE ) break;
-
-            if( !p_pic->i_refcount ) break;
-        }
-        if( i_pic == p_dec->p_owner->p_vout->render.i_pictures )
-        {
-            msg_Err( p_dec, "decoder is leaking pictures, resetting the heap" );
-
-            /* Just free all the pictures */
-            for( i_pic = 0; i_pic < p_dec->p_owner->p_vout->render.i_pictures;
-                 i_pic++ )
-            {
-                if( p_pic->i_status == RESERVED_PICTURE )
-                    vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
-                if( p_pic->i_refcount > 0 )
-                vout_UnlinkPicture( p_dec->p_owner->p_vout, p_pic );
-            }
-        }
-#undef p_pic
-
-        msleep( VOUT_OUTMEM_SLEEP );
-    }
-
-    return p_pic;
-}
-
-static void vout_del_buffer( decoder_t *p_dec, picture_t *p_pic )
-{
-    vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
-}
-
-static void vout_link_picture( decoder_t *p_dec, picture_t *p_pic )
-{
-    vout_LinkPicture( p_dec->p_owner->p_vout, p_pic );
-}
-
-static void vout_unlink_picture( decoder_t *p_dec, picture_t *p_pic )
-{
-    vout_UnlinkPicture( p_dec->p_owner->p_vout, p_pic );
-}
diff --git a/src/input/input_ext-plugins.c b/src/input/input_ext-plugins.c
deleted file mode 100644 (file)
index c0ee28c..0000000
+++ /dev/null
@@ -1,658 +0,0 @@
-/*****************************************************************************
- * input_ext-plugins.c: useful functions for access and demux plug-ins
- *****************************************************************************
- * Copyright (C) 2001-2004 VideoLAN
- * $Id$
- *
- * Authors: Christophe Massiot <massiot@via.ecp.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#include <stdlib.h>
-#include <string.h>
-
-#include <vlc/vlc.h>
-
-#include "stream_control.h"
-#include "input_ext-intf.h"
-#include "input_ext-dec.h"
-#include "input_ext-plugins.h"
-
-
-/*
- * Buffers management : internal functions
- *
- * All functions are static, but exported versions with mutex protection
- * start with input_*. Not all of these exported functions are actually used,
- * but they are included here for completeness.
- */
-
-#define BUFFERS_CACHE_SIZE 500
-#define DATA_CACHE_SIZE 1000
-#define PES_CACHE_SIZE 1000
-
-/*****************************************************************************
- * data_buffer_t: shared data type
- *****************************************************************************/
-struct data_buffer_t
-{
-    data_buffer_t * p_next;
-
-    /* number of data packets this buffer is referenced from - when it falls
-     * down to 0, the buffer is freed */
-    int i_refcount;
-
-    /* size of the current buffer (starting right after this byte) */
-    size_t i_size;
-};
-
-/*****************************************************************************
- * 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;
-
-struct input_buffers_t
-{
-    vlc_mutex_t lock;
-    PACKETS_LIFO( pes_packet_t, pes )
-    PACKETS_LIFO( data_packet_t, data )
-    PACKETS_LIFO( data_buffer_t, buffers )
-    size_t i_allocated;
-};
-
-
-/*****************************************************************************
- * input_BuffersInit: initialize the cache structures, return a pointer to it
- *****************************************************************************/
-void * __input_BuffersInit( vlc_object_t *p_this )
-{
-    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_this, &p_buffers->lock );
-
-    return p_buffers;
-}
-
-/*****************************************************************************
- * input_BuffersEnd: free all cached structures
- *****************************************************************************/
-#define BUFFERS_END_PACKETS_LOOP                                            \
-    while( p_packet != NULL )                                               \
-    {                                                                       \
-        p_next = p_packet->p_next;                                          \
-        free( p_packet );                                                   \
-        p_packet = p_next;                                                  \
-    }
-
-void input_BuffersEnd( input_thread_t * p_input, input_buffers_t * p_buffers )
-{
-    if( p_buffers != NULL )
-    {
-        msg_Dbg( p_input, "pes: %d packets", p_buffers->pes.i_depth );
-        msg_Dbg( p_input, "data: %d packets", p_buffers->data.i_depth );
-        msg_Dbg( p_input, "buffers: %d packets", p_buffers->buffers.i_depth );
-
-        {
-            /* Free PES */
-            pes_packet_t * p_next, * p_packet = p_buffers->pes.p_stack;
-            BUFFERS_END_PACKETS_LOOP;
-        }
-
-        {
-            /* Free data packets */
-            data_packet_t * p_next, * p_packet = p_buffers->data.p_stack;
-            BUFFERS_END_PACKETS_LOOP;
-        }
-
-        {
-            /* Free buffers */
-            data_buffer_t * p_next, * p_buf = p_buffers->buffers.p_stack;
-            while( p_buf != NULL )
-            {
-                p_next = p_buf->p_next;
-                p_buffers->i_allocated -= p_buf->i_size;
-                free( p_buf );
-                p_buf = p_next;
-            }
-        }
-
-        if( p_buffers->i_allocated )
-        {
-            msg_Warn( p_input, "%u bytes have not been freed, "
-                              "expect memory leak", p_buffers->i_allocated );
-        }
-
-        vlc_mutex_destroy( &p_buffers->lock );
-        free( p_buffers );
-    }
-}
-
-/*****************************************************************************
- * input_NewBuffer: return a pointer to a data buffer of the appropriate size
- *****************************************************************************/
-static inline data_buffer_t * NewBuffer( input_buffers_t * p_buffers,
-                                         size_t i_size )
-{
-    data_buffer_t * p_buf;
-
-    /* Safety check */
-    if( p_buffers->i_allocated > INPUT_MAX_ALLOCATION )
-    {
-        return NULL;
-    }
-
-    if( p_buffers->buffers.p_stack != NULL )
-    {
-        /* Take the buffer from the cache */
-        p_buf = p_buffers->buffers.p_stack;
-        p_buffers->buffers.p_stack = p_buf->p_next;
-        p_buffers->buffers.i_depth--;
-
-        /* Reallocate the packet if it is too small or too large */
-        if( p_buf->i_size < i_size || p_buf->i_size > 3 * i_size )
-        {
-            p_buffers->i_allocated -= p_buf->i_size;
-            free( p_buf );
-            p_buf = malloc( sizeof(input_buffers_t) + i_size );
-            if( p_buf == NULL )
-            {
-                return NULL;
-            }
-            p_buf->i_size = i_size;
-            p_buffers->i_allocated += i_size;
-        }
-    }
-    else
-    {
-        /* Allocate a new buffer */
-        p_buf = malloc( sizeof(input_buffers_t) + i_size );
-        if( p_buf == NULL )
-        {
-            return NULL;
-        }
-        p_buf->i_size = i_size;
-        p_buffers->i_allocated += i_size;
-    }
-
-    /* Initialize data */
-    p_buf->p_next = NULL;
-    p_buf->i_refcount = 0;
-
-    return p_buf;
-}
-
-data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
-{
-    data_buffer_t * p_buf;
-
-    vlc_mutex_lock( &p_buffers->lock );
-    p_buf = NewBuffer( p_buffers, i_size );
-    vlc_mutex_unlock( &p_buffers->lock );
-
-    return p_buf;
-}
-
-/*****************************************************************************
- * input_ReleaseBuffer: put a buffer back into the cache
- *****************************************************************************/
-static inline void ReleaseBuffer( input_buffers_t * p_buffers,
-                                  data_buffer_t * p_buf )
-{
-    /* Decrement refcount */
-    if( --p_buf->i_refcount > 0 )
-    {
-        return;
-    }
-
-    if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
-    {
-        /* Cache not full : store the buffer in it */
-        p_buf->p_next = p_buffers->buffers.p_stack;
-        p_buffers->buffers.p_stack = p_buf;
-        p_buffers->buffers.i_depth++;
-    }
-    else
-    {
-        p_buffers->i_allocated -= p_buf->i_size;
-        free( p_buf );
-    }
-}
-
-void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
-{
-    vlc_mutex_lock( &p_buffers->lock );
-    ReleaseBuffer( p_buffers, p_buf );
-    vlc_mutex_unlock( &p_buffers->lock );
-}
-
-/*****************************************************************************
- * input_ShareBuffer: allocate a data_packet_t pointing to a given buffer
- *****************************************************************************/
-static inline data_packet_t * ShareBuffer( input_buffers_t * p_buffers,
-                                           data_buffer_t * p_buf )
-{
-    data_packet_t * p_data;
-
-    if( p_buffers->data.p_stack != NULL )
-    {
-        /* Take the packet from the cache */
-        p_data = p_buffers->data.p_stack;
-        p_buffers->data.p_stack = p_data->p_next;
-        p_buffers->data.i_depth--;
-    }
-    else
-    {
-        /* Allocate a new packet */
-        p_data = malloc( sizeof(data_packet_t) );
-        if( p_data == NULL )
-        {
-            return NULL;
-        }
-    }
-
-    p_data->p_buffer = p_buf;
-    p_data->p_next = NULL;
-    p_data->b_discard_payload = 0;
-    p_data->p_payload_start = p_data->p_demux_start
-                            = (byte_t *)p_buf + sizeof(input_buffers_t);
-    p_data->p_payload_end = p_data->p_demux_start + p_buf->i_size;
-    p_buf->i_refcount++;
-
-    return p_data;
-}
-
-data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
-                                   data_buffer_t * p_buf )
-{
-    data_packet_t * p_data;
-
-    vlc_mutex_lock( &p_buffers->lock );
-    p_data = ShareBuffer( p_buffers, p_buf );
-    vlc_mutex_unlock( &p_buffers->lock );
-
-    return p_data;
-}
-
-/*****************************************************************************
- * input_NewPacket: allocate a packet along with a buffer
- *****************************************************************************/
-static inline data_packet_t * NewPacket( input_buffers_t * p_buffers,
-                                         size_t i_size )
-{
-    data_buffer_t * p_buf;
-    data_packet_t * p_data;
-
-    p_buf = NewBuffer( p_buffers, i_size );
-
-    if( p_buf == NULL )
-    {
-        return NULL;
-    }
-
-    p_data = ShareBuffer( p_buffers, p_buf );
-    if( p_data == NULL )
-    {
-        ReleaseBuffer( p_buffers, p_buf );
-    }
-    return p_data;
-}
-
-data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
-{
-    data_packet_t * p_data;
-
-    vlc_mutex_lock( &p_buffers->lock );
-    p_data = NewPacket( p_buffers, i_size );
-    vlc_mutex_unlock( &p_buffers->lock );
-
-    return p_data;
-}
-
-/*****************************************************************************
- * input_DeletePacket: deallocate a packet and its buffers
- *****************************************************************************/
-static inline void DeletePacket( input_buffers_t * p_buffers,
-                                 data_packet_t * p_data )
-{
-    while( p_data != NULL )
-    {
-        data_packet_t * p_next = p_data->p_next;
-
-        ReleaseBuffer( p_buffers, p_data->p_buffer );
-
-        if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
-        {
-            /* Cache not full : store the packet in it */
-            p_data->p_next = p_buffers->data.p_stack;
-            p_buffers->data.p_stack = p_data;
-            p_buffers->data.i_depth++;
-        }
-        else
-        {
-            free( p_data );
-        }
-
-        p_data = p_next;
-    }
-}
-
-void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
-{
-    vlc_mutex_lock( &p_buffers->lock );
-    DeletePacket( p_buffers, p_data );
-    vlc_mutex_unlock( &p_buffers->lock );
-}
-
-/*****************************************************************************
- * input_NewPES: return a pointer to a new PES packet
- *****************************************************************************/
-static inline pes_packet_t * NewPES( input_buffers_t * p_buffers )
-{
-    pes_packet_t * p_pes;
-
-    if( p_buffers->pes.p_stack != NULL )
-    {
-        /* Take the packet from the cache */
-        p_pes = p_buffers->pes.p_stack;
-        p_buffers->pes.p_stack = p_pes->p_next;
-        p_buffers->pes.i_depth--;
-    }
-    else
-    {
-        /* Allocate a new packet */
-        p_pes = malloc( sizeof(pes_packet_t) );
-        if( p_pes == NULL )
-        {
-            return NULL;
-        }
-    }
-
-    p_pes->p_next = NULL;
-    p_pes->b_data_alignment = p_pes->b_discontinuity = VLC_FALSE;
-    p_pes->i_pts = p_pes->i_dts = 0;
-    p_pes->p_first = p_pes->p_last = NULL;
-    p_pes->i_pes_size = 0;
-    p_pes->i_nb_data = 0;
-
-    return p_pes;
-}
-
-pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
-{
-    pes_packet_t * p_pes;
-
-    vlc_mutex_lock( &p_buffers->lock );
-    p_pes = NewPES( p_buffers );
-    vlc_mutex_unlock( &p_buffers->lock );
-
-    return p_pes;
-}
-
-/*****************************************************************************
- * input_DeletePES: put a pes and all data packets and all buffers back into
- *                  the cache
- *****************************************************************************/
-static inline void DeletePES( input_buffers_t * p_buffers,
-                              pes_packet_t * p_pes )
-{
-    while( p_pes != NULL )
-    {
-        pes_packet_t * p_next = p_pes->p_next;
-
-        /* Delete all data packets */
-        if( p_pes->p_first != NULL )
-        {
-            DeletePacket( p_buffers, p_pes->p_first );
-        }
-
-        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 );
-        }
-
-        p_pes = p_next;
-    }
-}
-
-void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
-{
-    vlc_mutex_lock( &p_buffers->lock );
-    DeletePES( p_buffers, p_pes );
-    vlc_mutex_unlock( &p_buffers->lock );
-}
-
-
-/*
- * Buffers management : external functions
- *
- * These functions make the glu between the access plug-in (pf_read) and
- * the demux plug-in (pf_demux). We fill in a large buffer (approx. 10s kB)
- * with a call to pf_read, then allow the demux plug-in to have a peep at
- * it (input_Peek), and to split it in data_packet_t (input_SplitBuffer).
- */
-/*****************************************************************************
- * input_FillBuffer: fill in p_data_buffer with data from pf_read
- *****************************************************************************/
-ssize_t input_FillBuffer( input_thread_t * p_input )
-{
-    ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
-    data_buffer_t * p_buf = NULL;
-    ssize_t i_ret;
-
-    vlc_mutex_lock( &p_input->p_method_data->lock );
-
-    while( p_buf == NULL )
-    {
-        p_buf = NewBuffer( p_input->p_method_data,
-                           i_remains + p_input->i_bufsize );
-        if( p_buf == NULL )
-        {
-            vlc_mutex_unlock( &p_input->p_method_data->lock );
-            msg_Err( p_input,
-                     "failed allocating a new buffer (decoder stuck?)" );
-            msleep( INPUT_IDLE_SLEEP );
-
-            if( p_input->b_die || p_input->b_error || p_input->b_eof )
-            {
-                return -1;
-            }
-            vlc_mutex_lock( &p_input->p_method_data->lock );
-        }
-    }
-
-    p_buf->i_refcount = 1;
-
-    if( p_input->p_data_buffer != NULL )
-    {
-        if( i_remains )
-        {
-            p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
-                                       p_input->p_current_data,
-                                       (size_t)i_remains );
-        }
-        ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
-    }
-
-    p_input->p_data_buffer = p_buf;
-    p_input->p_current_data = (byte_t *)p_buf + sizeof(data_buffer_t);
-    p_input->p_last_data = p_input->p_current_data + i_remains;
-
-    /* Do not hold the lock during pf_read (blocking call). */
-    vlc_mutex_unlock( &p_input->p_method_data->lock );
-
-    i_ret = p_input->pf_read( p_input,
-                              (byte_t *)p_buf + sizeof(data_buffer_t)
-                               + i_remains,
-                              p_input->i_bufsize );
-    if( i_ret < 0 && i_remains == 0 )
-    {
-        /* Our internal buffers are empty, we can signal the error */
-        return -1;
-    }
-
-    if( i_ret < 0 ) i_ret = 0;
-
-    p_input->p_last_data += i_ret;
-
-    return (ssize_t)i_remains + i_ret;
-}
-
-/*****************************************************************************
- * input_Peek: give a pointer to the next available bytes in the buffer
- *             (min. i_size bytes)
- * Returns the number of bytes read, or -1 in case of error
- *****************************************************************************/
-ssize_t input_Peek( input_thread_t * p_input, byte_t ** pp_byte,
-                    size_t i_size )
-{
-    ssize_t i_data = p_input->p_last_data - p_input->p_current_data;
-
-    while( i_data < (ssize_t)i_size )
-    {
-        /* Go to the next buffer */
-        ssize_t i_ret = input_FillBuffer( p_input );
-
-        if( i_ret < 0 )
-        {
-            return -1;
-        }
-
-        if( i_ret == i_data )
-        {
-            /* We didn't get anymore data, must be the EOF */
-            i_size = i_data;
-            break;
-        }
-
-        i_data = i_ret;
-    }
-
-    *pp_byte = p_input->p_current_data;
-    return i_size;
-}
-
-/*****************************************************************************
- * input_SplitBuffer: give a pointer to a data packet containing i_size bytes
- * Returns the number of bytes read, or -1 in case of error
- *****************************************************************************/
-ssize_t input_SplitBuffer( input_thread_t * p_input,
-                           data_packet_t ** pp_data, size_t i_size )
-{
-    ssize_t i_data = p_input->p_last_data - p_input->p_current_data;
-
-    while( i_data < (ssize_t)i_size )
-    {
-        /* Go to the next buffer */
-        ssize_t i_ret = input_FillBuffer( p_input );
-
-        if( i_ret < 0 )
-        {
-            return -1;
-        }
-
-        if( i_ret == i_data )
-        {
-            /* We didn't get anymore data, must be the EOF */
-            i_size = i_data;
-            break;
-        }
-
-        i_data = i_ret;
-    }
-
-    if( i_size < 0)
-    {
-        return 0;
-    }
-
-    *pp_data = input_ShareBuffer( p_input->p_method_data,
-                                  p_input->p_data_buffer );
-
-    (*pp_data)->p_demux_start = (*pp_data)->p_payload_start
-        = p_input->p_current_data;
-    (*pp_data)->p_payload_end = (*pp_data)->p_demux_start + i_size;
-
-    p_input->p_current_data += i_size;
-
-    /* Update stream position */
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-    p_input->stream.p_selected_area->i_tell += i_size;
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    return i_size;
-}
-
-/*****************************************************************************
- * input_AccessInit: initialize access plug-in wrapper structures
- *****************************************************************************/
-int input_AccessInit( input_thread_t * p_input )
-{
-    p_input->p_method_data = input_BuffersInit( p_input );
-    if( p_input->p_method_data == NULL ) return -1;
-    p_input->p_data_buffer = NULL;
-    p_input->p_current_data = NULL;
-    p_input->p_last_data = NULL;
-    return 0;
-}
-
-/*****************************************************************************
- * input_AccessReinit: reinit structures before a random seek
- *****************************************************************************/
-void input_AccessReinit( input_thread_t * p_input )
-{
-    if( p_input->p_data_buffer != NULL )
-    {
-        ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
-    }
-    p_input->p_data_buffer = NULL;
-    p_input->p_current_data = NULL;
-    p_input->p_last_data = NULL;
-}
-
-/*****************************************************************************
- * input_AccessEnd: free access plug-in wrapper structures
- *****************************************************************************/
-void input_AccessEnd( input_thread_t * p_input )
-{
-    if( p_input->p_data_buffer != NULL )
-    {
-        ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
-    }
-
-    input_BuffersEnd( p_input, p_input->p_method_data );
-}
-
diff --git a/src/input/input_programs.c b/src/input/input_programs.c
deleted file mode 100644 (file)
index fd7ad40..0000000
+++ /dev/null
@@ -1,1268 +0,0 @@
-/*****************************************************************************
- * input_programs.c: es_descriptor_t, pgrm_descriptor_t management
- *****************************************************************************
- * Copyright (C) 1999-2004 VideoLAN
- * $Id$
- *
- * Authors: Christophe Massiot <massiot@via.ecp.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#include <stdlib.h>
-#include <string.h>                                    /* memcpy(), memset() */
-
-#include <vlc/vlc.h>
-
-#include "stream_control.h"
-#include "input_ext-intf.h"
-#include "input_ext-dec.h"
-#include "input_ext-plugins.h"
-
-/*
- * NOTICE : all of these functions expect you to have taken the lock on
- * p_input->stream.lock
- */
-
-/* Navigation callbacks */
-static int ProgramCallback( vlc_object_t *, char const *,
-                            vlc_value_t, vlc_value_t, void * );
-static int TitleCallback( vlc_object_t *, char const *,
-                          vlc_value_t, vlc_value_t, void * );
-static int ChapterCallback( vlc_object_t *, char const *,
-                            vlc_value_t, vlc_value_t, void * );
-static int NavigationCallback( vlc_object_t *, char const *,
-                               vlc_value_t, vlc_value_t, void * );
-static int ESCallback( vlc_object_t *, char const *,
-                       vlc_value_t, vlc_value_t, void * );
-
-/*****************************************************************************
- * input_InitStream: init the stream descriptor of the given input
- *****************************************************************************/
-int input_InitStream( input_thread_t * p_input, size_t i_data_len )
-{
-    vlc_value_t text,val;
-
-    p_input->stream.i_stream_id = 0;
-
-    /* initialized to 0 since we don't give the signal to the interface
-     * before the end of input initialization */
-    p_input->stream.b_changed = 0;
-    p_input->stream.pp_es = NULL;
-    p_input->stream.pp_selected_es = NULL;
-    p_input->stream.p_removed_es = NULL;
-    p_input->stream.p_newly_selected_es = NULL;
-    p_input->stream.i_pgrm_number = 0;
-    p_input->stream.pp_programs = NULL;
-    p_input->stream.p_selected_program = NULL;
-    p_input->stream.p_new_program = NULL;
-
-    if( i_data_len )
-    {
-        if ( (p_input->stream.p_demux_data = malloc( i_data_len )) == NULL )
-        {
-            msg_Err( p_input, "out of memory" );
-            return 1;
-        }
-        memset( p_input->stream.p_demux_data, 0, i_data_len );
-    }
-    else
-    {
-        p_input->stream.p_demux_data = NULL;
-    }
-
-    var_Create( p_input, "intf-change", VLC_VAR_BOOL );
-    val.b_bool = VLC_TRUE;
-    var_Set( p_input, "intf-change", val );
-
-    /* Create a few object variables used for navigation in the interfaces */
-    var_Create( p_input, "program", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE |
-                VLC_VAR_DOINHERIT );
-    var_Get( p_input, "program", &val );
-    if( val.i_int <= 0 )
-        var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
-    text.psz_string = _("Program");
-    var_Change( p_input, "program", VLC_VAR_SETTEXT, &text, NULL );
-
-    var_Create( p_input, "title", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
-    text.psz_string = _("Title");
-    var_Change( p_input, "title", VLC_VAR_SETTEXT, &text, NULL );
-
-    var_Create( p_input, "chapter", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
-    text.psz_string = _("Chapter");
-    var_Change( p_input, "chapter", VLC_VAR_SETTEXT, &text, NULL );
-
-    var_Create( p_input, "navigation", VLC_VAR_VARIABLE | VLC_VAR_HASCHOICE );
-    text.psz_string = _("Navigation");
-    var_Change( p_input, "navigation", VLC_VAR_SETTEXT, &text, NULL );
-
-    var_Create( p_input, "video-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
-    text.psz_string = _("Video Track");
-    var_Change( p_input, "video-es", VLC_VAR_SETTEXT, &text, NULL );
-    var_Create( p_input, "audio-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
-    text.psz_string = _("Audio Track");
-    var_Change( p_input, "audio-es", VLC_VAR_SETTEXT, &text, NULL );
-    var_Create( p_input, "spu-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
-    text.psz_string = _("Subtitles Track");
-    var_Change( p_input, "spu-es", VLC_VAR_SETTEXT, &text, NULL );
-
-    var_AddCallback( p_input, "program", ProgramCallback, NULL );
-    var_AddCallback( p_input, "title", TitleCallback, NULL );
-    var_AddCallback( p_input, "chapter", ChapterCallback, NULL );
-    var_AddCallback( p_input, "video-es", ESCallback, NULL );
-    var_AddCallback( p_input, "audio-es", ESCallback, NULL );
-    var_AddCallback( p_input, "spu-es", ESCallback, NULL );
-
-    return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * input_EndStream: free all stream descriptors
- *****************************************************************************/
-void input_EndStream( input_thread_t * p_input )
-{
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-
-    /* Free all programs and associated ES, and associated decoders. */
-    while( p_input->stream.i_pgrm_number )
-    {
-        input_DelProgram( p_input, p_input->stream.pp_programs[0] );
-    }
-
-    /* Free standalone ES */
-    while( p_input->stream.i_es_number )
-    {
-        input_DelES( p_input, p_input->stream.pp_es[0] );
-    }
-
-    /* Free all areas */
-    while( p_input->stream.i_area_nb )
-    {
-        input_DelArea( p_input, p_input->stream.pp_areas[0] );
-    }
-
-    /* Free selected ES */
-    if( p_input->stream.pp_selected_es != NULL )
-    {
-        free( p_input->stream.pp_selected_es );
-    }
-
-    if( p_input->stream.p_demux_data != NULL )
-    {
-        free( p_input->stream.p_demux_data );
-    }
-
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    /* Free navigation variables */
-    var_Destroy( p_input, "program" );
-    var_Destroy( p_input, "title" );
-    var_Destroy( p_input, "chapter" );
-    var_Destroy( p_input, "video-es" );
-    var_Destroy( p_input, "audio-es" );
-    var_Destroy( p_input, "spu-es" );
-    var_Destroy( p_input, "intf-change" );
-}
-
-/*****************************************************************************
- * input_FindProgram: returns a pointer to a program described by its ID
- *****************************************************************************/
-pgrm_descriptor_t * input_FindProgram( input_thread_t * p_input,
-                                       uint16_t i_pgrm_id )
-{
-    unsigned int i;
-
-    for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
-    {
-        if( p_input->stream.pp_programs[i]->i_number == i_pgrm_id )
-        {
-            return p_input->stream.pp_programs[i];
-        }
-    }
-
-    return NULL;
-}
-
-/*****************************************************************************
- * input_AddProgram: add and init a program descriptor
- *****************************************************************************
- * This program descriptor will be referenced in the given stream descriptor
- *****************************************************************************/
-pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input,
-                                      uint16_t i_pgrm_id, size_t i_data_len )
-{
-    /* Where to add the pgrm */
-    pgrm_descriptor_t * p_pgrm = malloc( sizeof(pgrm_descriptor_t) );
-    vlc_value_t val;
-
-    if( p_pgrm == NULL )
-    {
-        msg_Err( p_input, "out of memory" );
-        return NULL;
-    }
-
-    /* Init this entry */
-    p_pgrm->i_number = i_pgrm_id;
-    p_pgrm->b_is_ok = 0;
-    p_pgrm->i_version = 0;
-
-    p_pgrm->i_es_number = 0;
-    p_pgrm->pp_es = NULL;
-
-    input_ClockInit( p_pgrm );
-
-    p_pgrm->i_synchro_state = SYNCHRO_START;
-
-    if( i_data_len )
-    {
-        p_pgrm->p_demux_data = malloc( i_data_len );
-        if( p_pgrm->p_demux_data == NULL )
-        {
-            msg_Err( p_input, "out of memory" );
-            return NULL;
-        }
-        memset( p_pgrm->p_demux_data, 0, i_data_len );
-    }
-    else
-    {
-        p_pgrm->p_demux_data = NULL;
-    }
-
-    /* Add an entry to the list of program associated with the stream */
-    INSERT_ELEM( p_input->stream.pp_programs,
-                 p_input->stream.i_pgrm_number,
-                 p_input->stream.i_pgrm_number,
-                 p_pgrm );
-
-    val.i_int = i_pgrm_id;
-    var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
-
-    return p_pgrm;
-}
-
-/*****************************************************************************
- * input_DelProgram: destroy a program descriptor
- *****************************************************************************
- * All ES descriptions referenced in the descriptor will be deleted.
- *****************************************************************************/
-void input_DelProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
-{
-    unsigned int i_pgrm_index;
-    vlc_value_t val;
-
-    /* Find the program in the programs table */
-    for( i_pgrm_index = 0; i_pgrm_index < p_input->stream.i_pgrm_number;
-         i_pgrm_index++ )
-    {
-        if( p_input->stream.pp_programs[i_pgrm_index] == p_pgrm )
-            break;
-    }
-
-    /* If the program wasn't found, do nothing */
-    if( i_pgrm_index == p_input->stream.i_pgrm_number )
-    {
-        msg_Err( p_input, "program does not belong to this input" );
-        return;
-    }
-
-    val.i_int = p_input->stream.pp_programs[i_pgrm_index]->i_number;
-    var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
-
-    /* Free the structures that describe the es that belongs to that program */
-    while( p_pgrm->i_es_number )
-    {
-        input_DelES( p_input, p_pgrm->pp_es[0] );
-    }
-
-    /* Free the demux data */
-    if( p_pgrm->p_demux_data != NULL )
-    {
-        free( p_pgrm->p_demux_data );
-    }
-
-    /* Remove this program from the stream's list of programs */
-    REMOVE_ELEM( p_input->stream.pp_programs,
-                 p_input->stream.i_pgrm_number,
-                 i_pgrm_index );
-
-    if( p_pgrm == p_input->stream.p_selected_program )
-        p_input->stream.p_selected_program = NULL;
-
-    /* Free the description of this program */
-    free( p_pgrm );
-}
-
-/****************************************************************************
- * input_ChangeProgram: interface request a program change (internal)
- ****************************************************************************/
-static int input_ChangeProgram( input_thread_t * p_input, uint16_t i_program_number )
-{
-    pgrm_descriptor_t *       p_program;
-    vlc_value_t val;
-
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-
-    p_program = input_FindProgram( p_input, i_program_number );
-
-    if ( p_program == NULL )
-    {
-        msg_Err( p_input, "could not find selected program" );
-        return -1;
-    }
-
-    p_input->stream.p_new_program = p_program;
-
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    /* Update the navigation variables without triggering a callback */
-    val.i_int = i_program_number;
-    var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
-
-    return 0;
-}
-
-/*****************************************************************************
- * input_AddArea: add and init an area descriptor
- *****************************************************************************
- * This area descriptor will be referenced in the given stream descriptor
- *****************************************************************************/
-input_area_t * input_AddArea( input_thread_t * p_input,
-                              uint16_t i_area_id, uint16_t i_part_nb )
-{
-    /* Where to add the pgrm */
-    input_area_t * p_area = malloc( sizeof(input_area_t) );
-    vlc_value_t val;
-    int i;
-
-    if( p_area == NULL )
-    {
-        msg_Err( p_input, "out of memory" );
-        return NULL;
-    }
-
-    /* Init this entry */
-    p_area->i_id = i_area_id;
-    p_area->i_part_nb = i_part_nb;
-    p_area->i_part= 0;
-    p_area->i_start = 0;
-    p_area->i_size = 0;
-    p_area->i_tell = 0;
-    p_area->i_seek = NO_SEEK;
-
-    /* Add an entry to the list of program associated with the stream */
-    INSERT_ELEM( p_input->stream.pp_areas,
-                 p_input->stream.i_area_nb,
-                 p_input->stream.i_area_nb,
-                 p_area );
-
-    /* Don't add empty areas */
-    if( i_part_nb == 0 )
-        return NULL;
-
-    /* Take care of the navigation variables */
-    val.i_int = i_area_id;
-    var_Change( p_input, "title", VLC_VAR_ADDCHOICE, &val, NULL );
-
-    val.psz_string = malloc( sizeof("title ") + 5 );
-    if( val.psz_string )
-    {
-        vlc_value_t val2, text, text2;
-
-        sprintf( val.psz_string, "title %2i", i_area_id );
-        var_Destroy( p_input, val.psz_string );
-        var_Create( p_input, val.psz_string, VLC_VAR_INTEGER |
-                    VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
-        var_AddCallback( p_input, val.psz_string, NavigationCallback,
-                         (void *)(int)i_area_id );
-
-        text.psz_string = malloc( strlen( _("Title %i") ) + 20 );
-        if( text.psz_string )
-            sprintf( text.psz_string, _("Title %i"), i_area_id );
-
-        var_Change( p_input, "navigation", VLC_VAR_ADDCHOICE, &val, &text );
-
-        if( text.psz_string ) free( text.psz_string );
-
-        text2.psz_string = malloc( strlen( _("Chapter %i") ) + 20 );
-
-        for( i = 1; i <= i_part_nb; i++ )
-        {
-            val2.i_int = i;
-
-            if( text2.psz_string )
-                sprintf( text2.psz_string, _("Chapter %i"), i );
-
-            var_Change( p_input, val.psz_string,
-                        VLC_VAR_ADDCHOICE, &val2, &text2 );
-        }
-
-        if( text2.psz_string ) free( text2.psz_string );
-        free( val.psz_string );
-    }
-
-    if( p_input->stream.i_area_nb == 2 )
-    {
-        vlc_value_t text;
-
-        /* Add another bunch of navigation object variables */
-        var_Create( p_input, "next-title", VLC_VAR_VOID );
-        text.psz_string = _("Next title");
-        var_Change( p_input, "next-title", VLC_VAR_SETTEXT, &text, NULL );
-        var_Create( p_input, "prev-title", VLC_VAR_VOID );
-        text.psz_string = _("Previous title");
-        var_Change( p_input, "prev-title", VLC_VAR_SETTEXT, &text, NULL );
-        var_AddCallback( p_input, "next-title", TitleCallback, NULL );
-        var_AddCallback( p_input, "prev-title", TitleCallback, NULL );
-
-        var_Create( p_input, "next-chapter", VLC_VAR_VOID );
-        text.psz_string = _("Next chapter");
-        var_Change( p_input, "next-chapter", VLC_VAR_SETTEXT, &text, NULL );
-        var_Create( p_input, "prev-chapter", VLC_VAR_VOID );
-        text.psz_string = _("Previous chapter");
-        var_Change( p_input, "prev-chapter", VLC_VAR_SETTEXT, &text, NULL );
-        var_AddCallback( p_input, "next-chapter", ChapterCallback, NULL );
-        var_AddCallback( p_input, "prev-chapter", ChapterCallback, NULL );
-    }
-
-    return p_area;
-}
-
-/*****************************************************************************
- * input_SetProgram: changes the current program
- *****************************************************************************/
-int input_SetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_new_prg )
-{
-    unsigned int i_es_index;
-    int i_required_audio_es;
-    int i_required_spu_es;
-    int i_audio_es = 0;
-    int i_spu_es = 0;
-    vlc_value_t val;
-
-    if ( p_input->stream.p_selected_program )
-    {
-        for ( i_es_index = 1 ; /* 0 should be the PMT */
-                i_es_index < p_input->stream.p_selected_program->
-                i_es_number ;
-                i_es_index ++ )
-        {
-#define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
-            if ( p_es->p_dec ) /* if the ES was selected */
-            {
-                input_UnselectES( p_input , p_es );
-            }
-#undef p_es
-        }
-    }
-
-    /* Get the number of the required audio stream */
-    var_Get( p_input, "audio", &val );
-    if( val.b_bool )
-    {
-        /* Default is the first one */
-        var_Get( p_input, "audio-channel", &val );
-        i_required_audio_es = val.i_int;
-        if( i_required_audio_es < 0 )
-        {
-            i_required_audio_es = 1;
-        }
-    }
-    else
-    {
-        i_required_audio_es = 0;
-    }
-
-    /* Same thing for subtitles */
-    var_Get( p_input, "video", &val );
-    if( val.b_bool )
-    {
-        /* for spu, default is none */
-        var_Get( p_input, "spu-channel", &val );
-        i_required_spu_es = val.i_int;
-        if( i_required_spu_es < 0 )
-        {
-            i_required_spu_es = 0;
-        }
-    }
-    else
-    {
-        i_required_spu_es = 0;
-    }
-
-    for( i_es_index = 0 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
-    {
-        switch( p_new_prg->pp_es[i_es_index]->i_cat )
-        {
-            case VIDEO_ES:
-                msg_Dbg( p_input, "selecting video ES %x",
-                         p_new_prg->pp_es[i_es_index]->i_id );
-                input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
-                break;
-            case AUDIO_ES:
-                i_audio_es += 1;
-                if( i_audio_es <= i_required_audio_es )
-                {
-                    msg_Dbg( p_input, "selecting audio ES %x",
-                             p_new_prg->pp_es[i_es_index]->i_id );
-                    input_SelectES( p_input, p_new_prg->pp_es[i_es_index]);
-                }
-                break;
-            /* Not sure this one is fully specification-compliant */
-            case SPU_ES :
-                i_spu_es += 1;
-                if( i_spu_es <= i_required_spu_es )
-                {
-                    msg_Dbg( p_input, "selecting spu ES %x",
-                             p_new_prg->pp_es[i_es_index]->i_id );
-                    input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
-                }
-            break;
-            default :
-                msg_Dbg( p_input, "ES %x has unknown type",
-                         p_new_prg->pp_es[i_es_index]->i_id );
-                break;
-        }
-
-    }
-
-    p_input->stream.p_selected_program = p_new_prg;
-
-    /* Update the navigation variables without triggering a callback */
-    val.i_int = p_new_prg->i_number;
-    var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
-
-    return( 0 );
-}
-
-/*****************************************************************************
- * input_DelArea: destroy a area descriptor
- *****************************************************************************
- * All ES descriptions referenced in the descriptor will be deleted.
- *****************************************************************************/
-void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
-{
-    unsigned int i_area_index;
-    vlc_value_t val;
-
-    /* Find the area in the areas table */
-    for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
-         i_area_index++ )
-    {
-        if( p_input->stream.pp_areas[i_area_index] == p_area )
-            break;
-    }
-
-    /* If the area wasn't found, do nothing */
-    if( i_area_index == p_input->stream.i_area_nb )
-    {
-        msg_Err( p_input, "area does not belong to this input" );
-        return;
-    }
-
-    /* Take care of the navigation variables */
-    val.psz_string = malloc( sizeof("title ") + 5 );
-    if( val.psz_string )
-    {
-        sprintf( val.psz_string, "title %i", p_area->i_id );
-        var_Change( p_input, "navigation", VLC_VAR_DELCHOICE, &val, NULL );
-        var_Destroy( p_input, val.psz_string );
-
-        free( val.psz_string );
-    }
-
-    /* Remove this area from the stream's list of areas */
-    REMOVE_ELEM( p_input->stream.pp_areas,
-                 p_input->stream.i_area_nb,
-                 i_area_index );
-
-    /* Free the description of this area */
-    free( p_area );
-
-    if( p_input->stream.i_area_nb == 1 )
-    {
-        /* Del unneeded navigation object variables */
-        var_Destroy( p_input, "next-title" );
-        var_Destroy( p_input, "prev-title" );
-        var_Destroy( p_input, "next-chapter" );
-        var_Destroy( p_input, "prev-chapter" );
-    }
-}
-
-/****************************************************************************
- * input_ChangeArea: interface request an area change (internal)
- ****************************************************************************/
-static int input_ChangeArea( input_thread_t * p_input, input_area_t * p_area )
-{
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-
-    p_input->stream.p_new_area = p_area;
-
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    return 0;
-}
-
-/*****************************************************************************
- * input_FindES: returns a pointer to an ES described by its ID
- *****************************************************************************/
-es_descriptor_t * input_FindES( input_thread_t * p_input, uint16_t i_es_id )
-{
-    unsigned int i;
-
-    for( i = 0; i < p_input->stream.i_es_number; i++ )
-    {
-        if( p_input->stream.pp_es[i]->i_id == i_es_id )
-        {
-            return p_input->stream.pp_es[i];
-        }
-    }
-
-    return NULL;
-}
-
-/*****************************************************************************
- * input_AddES:
- *****************************************************************************
- * Reserve a slot in the table of ES descriptors for the ES and add it to the
- * list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
- * alone (PSI ?)
- *****************************************************************************/
-es_descriptor_t * input_AddES( input_thread_t * p_input,
-                               pgrm_descriptor_t * p_pgrm, uint16_t i_es_id,
-                               int i_category, char const *psz_desc,
-                               size_t i_data_len )
-{
-    es_descriptor_t * p_es;
-    vlc_value_t val, text;
-    char *psz_var = NULL;
-
-    p_es = (es_descriptor_t *)malloc( sizeof(es_descriptor_t) );
-    if( p_es == NULL )
-    {
-        msg_Err( p_input, "out of memory" );
-        return( NULL);
-    }
-
-    INSERT_ELEM( p_input->stream.pp_es,
-                 p_input->stream.i_es_number,
-                 p_input->stream.i_es_number,
-                 p_es );
-
-    /* Init its values */
-    p_es->i_id = i_es_id;
-    p_es->i_stream_id = 0;
-    p_es->p_pes = NULL;
-    p_es->p_dec = NULL;
-    p_es->i_cat = i_category;
-    p_es->i_demux_fd = 0;
-    p_es->c_packets = 0;
-    p_es->c_invalid_packets = 0;
-    p_es->b_force_decoder = VLC_FALSE;
-    es_format_Init( &p_es->fmt, UNKNOWN_ES, 0 );
-    p_es->fmt.b_packetized = VLC_FALSE; /* Only there for old mpeg demuxers */
-
-    if( i_data_len )
-    {
-        p_es->p_demux_data = malloc( i_data_len );
-        if( p_es->p_demux_data == NULL )
-        {
-            msg_Err( p_input, "out of memory" );
-            return( NULL );
-        }
-        memset( p_es->p_demux_data, 0, i_data_len );
-    }
-    else
-    {
-        p_es->p_demux_data = NULL;
-    }
-    p_es->p_waveformatex     = NULL;
-    p_es->p_bitmapinfoheader = NULL;
-    p_es->p_spuinfo = NULL;
-
-    /* Add this ES to the program definition if one is given */
-    if( p_pgrm )
-    {
-        INSERT_ELEM( p_pgrm->pp_es,
-                     p_pgrm->i_es_number,
-                     p_pgrm->i_es_number,
-                     p_es );
-        p_es->p_pgrm = p_pgrm;
-    }
-    else
-    {
-        p_es->p_pgrm = NULL;
-    }
-
-    switch( i_category )
-    {
-    case AUDIO_ES:
-        psz_var = "audio-es";
-        break;
-    case SPU_ES:
-        psz_var = "spu-es";
-        break;
-    case VIDEO_ES:
-        psz_var = "video-es";
-        break;
-    }
-
-    if( psz_var )
-    {
-        /* Get the number of ES already added */
-        var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
-        if( val.i_int == 0 )
-        {
-            vlc_value_t val2;
-
-            /* First one, we need to add the "Disable" choice */
-            val2.i_int = -1; text.psz_string = _("Disable");
-            var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
-            val.i_int++;
-        }
-
-        /* Take care of the ES description */
-        if( psz_desc && *psz_desc )
-        {
-            p_es->psz_desc = strdup( psz_desc );
-        }
-        else
-        {
-            p_es->psz_desc = malloc( strlen( _("Track %i") ) + 20 );
-            if( p_es->psz_desc )
-                sprintf( p_es->psz_desc, _("Track %i"), val.i_int );
-        }
-
-        val.i_int = p_es->i_id;
-        text.psz_string = p_es->psz_desc;
-        var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
-    }
-    else p_es->psz_desc = NULL;
-
-    return p_es;
-}
-
-/*****************************************************************************
- * input_DelES:
- *****************************************************************************/
-void input_DelES( input_thread_t * p_input, es_descriptor_t * p_es )
-{
-    unsigned int            i_index, i_es_index;
-    pgrm_descriptor_t *     p_pgrm;
-    char *                  psz_var = NULL;
-    vlc_value_t             val;
-
-    /* Find the ES in the ES table */
-    for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
-         i_es_index++ )
-    {
-        if( p_input->stream.pp_es[i_es_index] == p_es )
-            break;
-    }
-
-    /* If the ES wasn't found, do nothing */
-    if( i_es_index == p_input->stream.i_es_number )
-    {
-        msg_Err( p_input, "ES does not belong to this input" );
-        return;
-    }
-
-    /* Remove es from its associated variable */
-    switch( p_es->i_cat )
-    {
-    case AUDIO_ES:
-        psz_var = "audio-es";
-        break;
-    case SPU_ES:
-        psz_var = "spu-es";
-        break;
-    case VIDEO_ES:
-        psz_var = "video-es";
-        break;
-    }
-
-    if( psz_var )
-    {
-        val.i_int = p_es->i_id;
-        var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
-
-        /* Remove the "Disable" entry if needed */
-        var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
-        if( val.i_int == 1 )
-        {
-            val.i_int = -1;
-            var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
-        }
-    }
-
-    /* Kill associated decoder, if any. */
-    if( p_es->p_dec != NULL )
-    {
-        input_UnselectES( p_input, p_es );
-    }
-
-    /* Remove this ES from the description of the program if it is associated
-     * to one */
-    p_pgrm = p_es->p_pgrm;
-    if( p_pgrm )
-    {
-        for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
-        {
-            if( p_pgrm->pp_es[i_index] == p_es )
-            {
-                REMOVE_ELEM( p_pgrm->pp_es,
-                             p_pgrm->i_es_number,
-                             i_index );
-                break;
-            }
-        }
-    }
-
-    /* Free the demux data */
-    if( p_es->p_demux_data != NULL )
-    {
-        free( p_es->p_demux_data );
-    }
-    if( p_es->p_waveformatex )
-    {
-        free( p_es->p_waveformatex );
-    }
-    if( p_es->p_bitmapinfoheader )
-    {
-        free( p_es->p_bitmapinfoheader );
-    }
-    if( p_es->p_spuinfo )
-    {
-        free( p_es->p_spuinfo );
-    }
-
-    /* Free the description string */
-    if( p_es->psz_desc != NULL )
-    {
-        free( p_es->psz_desc );
-    }
-
-    /* Clean the es format */
-    es_format_Clean( &p_es->fmt );
-
-    /* Find the ES in the ES table */
-    for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
-         i_es_index++ )
-    {
-        if( p_input->stream.pp_es[i_es_index] == p_es )
-            break;
-    }
-
-    /* Remove this ES from the stream's list of ES */
-    REMOVE_ELEM( p_input->stream.pp_es,
-                 p_input->stream.i_es_number,
-                 i_es_index );
-
-    /* Free the ES */
-    free( p_es );
-}
-
-/*****************************************************************************
- * input_SelectES: selects an ES and spawns the associated decoder
- *****************************************************************************
- * Remember we are still supposed to have stream_lock when entering this
- * function ?
- *****************************************************************************/
-int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
-{
-    vlc_value_t val;
-    char *psz_var = NULL;
-
-    if( p_es == NULL )
-    {
-        msg_Err( p_input, "nothing to do in input_SelectES" );
-        return -1;
-    }
-
-    if( p_es->i_cat == VIDEO_ES || p_es->i_cat == SPU_ES )
-    {
-        var_Get( p_input, "video", &val );
-        if( val.b_bool && p_input->stream.p_sout )
-        {
-            var_Get( p_input, "sout-video", &val );
-        }
-        if( !val.b_bool )
-        {
-            msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
-                     p_es->i_id );
-            return -1;
-        }
-    }
-
-    if( p_es->i_cat == AUDIO_ES )
-    {
-        var_Get( p_input, "audio", &val );
-        if( val.b_bool && p_input->stream.p_sout )
-        {
-            var_Get( p_input, "sout-audio", &val );
-        }
-        if( !val.b_bool )
-        {
-            msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
-                     p_es->i_id );
-            return -1;
-        }
-    }
-
-    msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
-
-    if( p_es->p_dec != NULL )
-    {
-        msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
-        return -1;
-    }
-
-    /* Release the lock, not to block the input thread during
-     * the creation of the thread. */
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-    p_es->p_dec = input_RunDecoder( p_input, p_es );
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-
-    if( p_es->p_dec == NULL )
-    {
-        return -1;
-    }
-
-    /* Update the es variable without triggering a callback */
-    switch( p_es->i_cat )
-    {
-    case AUDIO_ES:
-        psz_var = "audio-es";
-        break;
-    case SPU_ES:
-        psz_var = "spu-es";
-        break;
-    case VIDEO_ES:
-        psz_var = "video-es";
-        break;
-    }
-
-    if( psz_var )
-    {
-        val.i_int = p_es->i_id;
-        var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
-    }
-
-    return 0;
-}
-
-/*****************************************************************************
- * input_UnselectES: removes an ES from the list of selected ES
- *****************************************************************************/
-int input_UnselectES( input_thread_t * p_input, es_descriptor_t * p_es )
-{
-    unsigned int i_index = 0;
-    vlc_value_t val;
-    char *psz_var = NULL;
-
-    if( p_es == NULL )
-    {
-        msg_Err( p_input, "nothing to do in input_UnselectES" );
-        return -1;
-    }
-
-    msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
-
-    if( p_es->p_dec == NULL )
-    {
-        msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
-        return( -1 );
-    }
-
-    /* Update the es variable without triggering a callback */
-    switch( p_es->i_cat )
-    {
-    case AUDIO_ES:
-        psz_var = "audio-es";
-        break;
-    case SPU_ES:
-        psz_var = "spu-es";
-        break;
-    case VIDEO_ES:
-        psz_var = "video-es";
-        break;
-    }
-
-    if( psz_var )
-    {
-        val.i_int = -1;
-        var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
-    }
-
-    /* FIXME: input_UnselectES() shouldn't actually be entered with the
-     * input lock, the locking should be done here and only where necessary. */
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-    /* Actually unselect the ES */
-    input_EndDecoder( p_input, p_es );
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-
-    p_es->p_pes = NULL;
-
-    if( ( p_es->p_dec == NULL ) &&
-        ( p_input->stream.i_selected_es_number > 0 ) )
-    {
-        while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
-               ( p_input->stream.pp_selected_es[i_index] != p_es ) )
-        {
-            i_index++;
-        }
-
-        /* XXX: no need to memmove, we have unsorted data */
-        REMOVE_ELEM( p_input->stream.pp_selected_es,
-                     p_input->stream.i_selected_es_number,
-                     i_index );
-
-        if( p_input->stream.i_selected_es_number == 0 )
-        {
-            msg_Dbg( p_input, "no more selected ES" );
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
-/*****************************************************************************
- * Navigation callback: a bunch of navigation variables are used as an
- *  alternative to the navigation API.
- *****************************************************************************/
-static int ProgramCallback( vlc_object_t *p_this, char const *psz_cmd,
-                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
-    input_thread_t *p_input = (input_thread_t *)p_this;
-    vlc_value_t val;
-
-    if( oldval.i_int == newval.i_int )
-       return VLC_SUCCESS;
-
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-    if( ( newval.i_int > 0 ) )
-    {
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
-        input_ChangeProgram( p_input, (uint16_t)newval.i_int );
-        var_SetInteger( p_input, "state", PLAYING_S );
-        vlc_mutex_lock( &p_input->stream.stream_lock );
-    }
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    val.b_bool = VLC_TRUE;
-    var_Set( p_input, "intf-change", val );
-
-    return VLC_SUCCESS;
-}
-
-static int TitleCallback( vlc_object_t *p_this, char const *psz_cmd,
-                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
-    input_thread_t *p_input = (input_thread_t *)p_this;
-    input_area_t *p_area;
-    vlc_value_t val, val_list;
-    int i, i_step = 0;
-
-    if( !strcmp( psz_cmd, "next-title" ) ) i_step++;
-    else if( !strcmp( psz_cmd, "prev-title" ) ) i_step--;
-
-    if( !i_step && oldval.i_int == newval.i_int ) return VLC_SUCCESS;
-
-    /* Sanity check should have already been done by var_Set(). */
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-
-    if( i_step )
-    {
-        var_Get( p_this, "title", &newval );
-        var_Change( p_this, "title", VLC_VAR_GETCHOICES, &val_list, NULL );
-        for( i = 0; i < val_list.p_list->i_count; i++ )
-        {
-            if( val_list.p_list->p_values[i].i_int == newval.i_int &&
-                i + i_step >= 0 && i + i_step < val_list.p_list->i_count )
-            {
-                newval.i_int = val_list.p_list->p_values[i + i_step].i_int;
-                break;
-            }
-        }
-        var_Change( p_this, "title", VLC_VAR_FREELIST, &val_list, NULL );
-    }
-
-    p_area = p_input->stream.pp_areas[newval.i_int];
-    p_area->i_part = 1;
-
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    input_ChangeArea( p_input, p_area );
-    var_SetInteger( p_input, "state", PLAYING_S );
-
-    val.b_bool = VLC_TRUE;
-    var_Set( p_input, "intf-change", val );
-
-    return VLC_SUCCESS;
-}
-
-static int ChapterCallback( vlc_object_t *p_this, char const *psz_cmd,
-                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
-    input_thread_t *p_input = (input_thread_t *)p_this;
-    input_area_t *p_area;
-    vlc_value_t val, val_list;
-    int i, i_step = 0;
-
-    if( !strcmp( psz_cmd, "next-chapter" ) ) i_step++;
-    else if( !strcmp( psz_cmd, "prev-chapter" ) ) i_step--;
-
-    if( !i_step && oldval.i_int == newval.i_int ) return VLC_SUCCESS;
-
-    /* Sanity check should have already been done by var_Set(). */
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-
-    if( i_step )
-    {
-        var_Get( p_this, "chapter", &newval );
-        var_Change( p_this, "chapter", VLC_VAR_GETCHOICES, &val_list, NULL );
-        for( i = 0; i < val_list.p_list->i_count; i++ )
-        {
-            if( val_list.p_list->p_values[i].i_int == newval.i_int &&
-                i + i_step >= 0 && i + i_step < val_list.p_list->i_count )
-            {
-                newval.i_int = val_list.p_list->p_values[i + i_step].i_int;
-                break;
-            }
-        }
-        var_Change( p_this, "chapter", VLC_VAR_FREELIST, &val_list, NULL );
-    }
-
-    p_area = p_input->stream.p_selected_area;
-    p_input->stream.p_selected_area->i_part = newval.i_int;
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    input_ChangeArea( p_input, p_area );
-    var_SetInteger( p_input, "state", PLAYING_S );
-
-    val.b_bool = VLC_TRUE;
-    var_Set( p_input, "intf-change", val );
-
-    return VLC_SUCCESS;
-}
-
-static int NavigationCallback( vlc_object_t *p_this, char const *psz_cmd,
-                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
-    input_thread_t *p_input = (input_thread_t *)p_this;
-    uint16_t i_area_id = (int)p_data;
-    vlc_value_t val;
-
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-
-    if( p_input->stream.p_selected_area->i_id == i_area_id &&
-        oldval.i_int == newval.i_int )
-    {
-        /* Nothing to do */
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
-        return VLC_SUCCESS;
-    }
-
-    if( ( i_area_id < p_input->stream.i_area_nb ) && ( newval.i_int > 0 ) &&
-        ( (uint16_t)newval.i_int <=
-          p_input->stream.pp_areas[i_area_id]->i_part_nb ) )
-    {
-        input_area_t *p_area = p_input->stream.pp_areas[i_area_id];
-        p_area->i_part = newval.i_int;
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
-        input_ChangeArea( p_input, p_area );
-        var_SetInteger( p_input, "state", PLAYING_S );
-        vlc_mutex_lock( &p_input->stream.stream_lock );
-    }
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    val.b_bool = VLC_TRUE;
-    var_Set( p_input, "intf-change", val );
-
-    return VLC_SUCCESS;
-}
-
-static int ESCallback( vlc_object_t *p_this, char const *psz_cmd,
-                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
-    input_thread_t *p_input = (input_thread_t *)p_this;
-    unsigned int i;
-    vlc_value_t val;
-    unsigned int i_cat = UNKNOWN_ES;
-    es_descriptor_t *p_es = NULL;
-
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-
-    /* First search old es type */
-    for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
-    {
-        if( p_input->stream.pp_es[i]->i_id == oldval.i_int )
-        {
-            i_cat = p_input->stream.pp_es[i]->i_cat;
-        }
-    }
-
-    /* Unselect all old ES */
-    for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
-    {
-        if( p_input->stream.pp_es[i]->i_cat == i_cat &&
-            p_input->stream.pp_es[i]->i_id != newval.i_int &&
-            p_input->stream.pp_es[i]->p_dec != NULL )
-        {
-            input_UnselectES( p_input, p_input->stream.pp_es[i] );
-        }
-    }
-
-    /* Select new ES */
-    for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
-    {
-        if( p_input->stream.pp_es[i]->i_id == newval.i_int )
-        {
-            p_es = p_input->stream.pp_es[i];
-            if( p_es->p_dec == NULL )
-            {
-                input_SelectES( p_input, p_es );
-            }
-        }
-    }
-
-    if( p_es )
-    {
-        /* Fix value (mainly for multiple selected ES */
-        val.i_int = p_es->i_id;
-        switch( p_es->i_cat )
-        {
-        case AUDIO_ES:
-            var_Change( p_input, "audio-es", VLC_VAR_SETVALUE, &val, NULL );
-            break;
-        case SPU_ES:
-            var_Change( p_input, "spu-es", VLC_VAR_SETVALUE, &val, NULL );
-            break;
-        case VIDEO_ES:
-            var_Change( p_input, "video-es", VLC_VAR_SETVALUE, &val, NULL );
-            break;
-        }
-    }
-
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    val.b_bool = VLC_TRUE;
-    var_Set( p_input, "intf-change", val );
-
-    return VLC_SUCCESS;
-}
index 72b2f20..cfd6532 100644 (file)
 #include <vlc/vlc.h>
 #include <vlc/input.h>
 
-#include "ninput.h"
+#include "input_internal.h"
 
-/****************************************************************************
- * stream_ReadLine:
- ****************************************************************************/
-/**
- * Read from the stream untill first newline.
- * \param s Stream handle to read from
- * \return A null-terminated string. This must be freed,
+/* TODO:
+ *  - tune the 2 methods
+ *  - compute cost for seek
+ *  - improve stream mode seeking with closest segments
+ *  - ...
  */
-/* FIXME don't use stupid MAX_LINE -> do the same than net_ReadLine */
-#define MAX_LINE 1024
-char *stream_ReadLine( stream_t *s )
+
+/* Two methods:
+ *  - using pf_block
+ *      One linked list of data read
+ *  - using pf_read
+ *      More complex scheme using mutliple track to avoid seeking
+ */
+
+/* How many track we have, currently only used for stream mode */
+#define STREAM_CACHE_TRACK 3
+/* Max size of our cache 4Mo per track */
+#define STREAM_CACHE_SIZE  (4*STREAM_CACHE_TRACK*1024*1024)
+  /* How many data we try to prebuffer */
+#define STREAM_CACHE_PREBUFFER_SIZE (32767)
+
+#define STREAM_CACHE_PREBUFFER_LENGTH (100*1000)    /* Maximum time we take to pre-buffer */
+
+
+/* Method1: Simple, for pf_block.
+ *  We get blocks and put them in the linked list.
+ *  We release blocks once the total size is bigger than CACHE_BLOCK_SIZE
+ */
+#define STREAM_DATA_WAIT 40000                     /* Time between before a pf_block retry */
+
+/* Method2: A bit more complex, for pf_read
+ *  - We use ring buffers, only one if unseekable, all if seekable
+ *  - Upon seek date current ring, then search if one ring match the pos,
+ *      yes: switch to it, seek the access to match the end of the ring
+ *      no: search the ring with i_end the closer to i_pos,
+ *          if close enough, read data and use this ring
+ *          else use the oldest ring, seek and use it.
+ *
+ *  TODO: - with access non seekable: use all space available for only one ring, but
+ *          we have to support seekable/non-seekable switch on the fly.
+ *        - compute a good value for i_read_size
+ *        - ?
+ */
+#define STREAM_READ_ATONCE 32767
+#define STREAM_CACHE_TRACK_SIZE (STREAM_CACHE_SIZE/STREAM_CACHE_TRACK)
+
+typedef struct
 {
-    uint8_t *p_data;
-    char    *p_line;
-    int      i_data;
-    int      i = 0;
-    i_data = stream_Peek( s, &p_data, MAX_LINE );
+    int64_t i_date;
 
-    while( i < i_data && p_data[i] != '\n' &&  p_data[i] != '\r' )
+    int64_t i_start;
+    int64_t i_end;
+
+    uint8_t *p_buffer;
+} stream_track_t;
+
+struct stream_sys_t
+{
+    access_t    *p_access;
+
+    vlc_bool_t  b_block;    /* Block method (1) or stream */
+
+    int64_t     i_pos;      /* Current reading offset */
+
+    /* Method 1: pf_block */
+    struct
     {
-        i++;
-    }
-    if( i_data <= 0 )
+        int64_t i_start;        /* Offset of block for p_first */
+        int     i_offset;       /* Offset for data in p_current */
+        block_t *p_current;     /* Current block */
+
+        int     i_size;         /* Total amount of data in the list */
+        block_t *p_first;
+        block_t **pp_last;
+    } block;
+
+    /* Method 2: for pf_read */
+    struct
     {
-        return NULL;
-    }
-    else
+        int i_offset;   /* Buffer ofset in the current track */
+        int i_tk;       /* Current track */
+        stream_track_t tk[STREAM_CACHE_TRACK];
+
+        /* Global buffer */
+        uint8_t *p_buffer;
+
+        /* */
+        int i_used; /* Used since last read */
+        int i_read_size;
+    } stream;
+
+    /* Peek temporary buffer */
+    int     i_peek;
+    uint8_t *p_peek;
+
+    /* Stat for both method */
+    struct
     {
-        p_line = malloc( i + 1 );
-        if( p_line == NULL )
-        {
-            msg_Err( s, "out of memory" );
-            return NULL;
-        }
-        i = stream_Read( s, p_line, i + 1 );
-        p_line[ i - 1 ] = '\0';
+        vlc_bool_t b_fastseek;  /* From access */
 
-        return p_line;
-    }
-}
+        /* Stat about reading data */
+        int64_t i_read_count;
+        int64_t i_bytes;
+        int64_t i_read_time;
 
+        /* Stat about seek */
+        int     i_seek_count;
+        int64_t i_seek_time;
+    } stat;
+};
 
+/* Method 1: */
+static int  AStreamReadBlock( stream_t *, void *p_read, int i_read );
+static int  AStreamPeekBlock( stream_t *, uint8_t **p_peek, int i_read );
+static int  AStreamSeekBlock( stream_t *s, int64_t i_pos );
+static void AStreamPrebufferBlock( stream_t * );
 
-/* TODO: one day we should create a special module stream
- * when we would have a access wrapper, and stream filter
- * (like caching, progessive, gunzip, ... )
- */
+/* Method 2 */
+static int  AStreamReadStream( stream_t *, void *p_read, int i_read );
+static int  AStreamPeekStream( stream_t *, uint8_t **pp_peek, int i_read );
+static int  AStreamSeekStream( stream_t *s, int64_t i_pos );
+static void AStreamPrebufferStream( stream_t * );
 
-/* private stream_sys_t for input_Stream* */
-typedef struct
-{
-    input_thread_t *p_input;
-} input_stream_sys_t;
+/* Common */
+static int AStreamControl( stream_t *, int i_query, va_list );
 
-/* private pf_* functions declarations */
-static int      IStreamRead   ( stream_t *, void *p_read, int i_read );
-static int      IStreamPeek   ( stream_t *, uint8_t **pp_peek, int i_peek );
-static int      IStreamControl( stream_t *, int i_query, va_list );
 
 /****************************************************************************
- * input_StreamNew: create a wrapper for p_input access
+ * stream_AccessNew: create a stream from a access
  ****************************************************************************/
-stream_t *input_StreamNew( input_thread_t *p_input )
+stream_t *stream_AccessNew( access_t *p_access )
 {
-    stream_t *s = vlc_object_create( p_input, sizeof( stream_t ) );
-    input_stream_sys_t *p_sys;
-    if( s )
+    stream_t *s = vlc_object_create( p_access, VLC_OBJECT_STREAM );
+    stream_sys_t *p_sys;
+
+    if( !s )
+        return NULL;
+
+    /* Attach it now, needed for b_die */
+    vlc_object_attach( s, p_access );
+
+    s->pf_block  = NULL;
+    s->pf_read   = NULL;    /* Set up later */
+    s->pf_peek   = NULL;
+    s->pf_control= AStreamControl;
+
+    s->p_sys = p_sys = malloc( sizeof( stream_sys_t ) );
+
+    /* Common field */
+    p_sys->p_access = p_access;
+    p_sys->b_block = p_access->pf_block ? VLC_TRUE : VLC_FALSE;
+    p_sys->i_pos = p_access->info.i_pos;
+
+    /* Stats */
+    access2_Control( p_access, ACCESS_CAN_FASTSEEK, &p_sys->stat.b_fastseek );
+    p_sys->stat.i_bytes = 0;
+    p_sys->stat.i_read_time = 0;
+    p_sys->stat.i_read_count = 0;
+    p_sys->stat.i_seek_count = 0;
+    p_sys->stat.i_seek_time = 0;
+
+    /* Peek */
+    p_sys->i_peek = 0;
+    p_sys->p_peek = NULL;
+
+    if( p_sys->b_block )
+    {
+        s->pf_read = AStreamReadBlock;
+        s->pf_peek = AStreamPeekBlock;
+
+        /* Init all fields of p_sys->block */
+        p_sys->block.i_start = p_sys->i_pos;
+        p_sys->block.i_offset = 0;
+        p_sys->block.p_current = NULL;
+        p_sys->block.i_size = 0;
+        p_sys->block.p_first = NULL;
+        p_sys->block.pp_last = &p_sys->block.p_first;
+
+        /* Do the prebuffering */
+        AStreamPrebufferBlock( s );
+
+        if( p_sys->block.i_size <= 0 )
+        {
+            msg_Err( s, "cannot pre fill buffer" );
+            goto error;
+        }
+    }
+    else
     {
-        s->pf_block  = NULL;
-        s->pf_read   = IStreamRead;
-        s->pf_peek   = IStreamPeek;
-        s->pf_control= IStreamControl;
+        int i;
+
+        s->pf_read = AStreamReadStream;
+        s->pf_peek = AStreamPeekStream;
+
+        /* Allocate/Setup our tracks */
+        p_sys->stream.i_offset = 0;
+        p_sys->stream.i_tk     = 0;
+        p_sys->stream.p_buffer = malloc( STREAM_CACHE_SIZE );
+        p_sys->stream.i_used   = 0;
+        access2_Control( p_access, ACCESS_GET_MTU, &p_sys->stream.i_read_size );
+        if( p_sys->stream.i_read_size <= 0 )
+            p_sys->stream.i_read_size = STREAM_READ_ATONCE;
+        else if( p_sys->stream.i_read_size <= 256 )
+            p_sys->stream.i_read_size = 256;
+
+        for( i = 0; i < STREAM_CACHE_TRACK; i++ )
+        {
+            p_sys->stream.tk[i].i_date  = 0;
+            p_sys->stream.tk[i].i_start = p_sys->i_pos;
+            p_sys->stream.tk[i].i_end   = p_sys->i_pos;
+            p_sys->stream.tk[i].p_buffer=
+                &p_sys->stream.p_buffer[i * STREAM_CACHE_TRACK_SIZE];
+        }
+
+        /* Do the prebuffering */
+        AStreamPrebufferStream( s );
 
-        s->p_sys = malloc( sizeof( input_stream_sys_t ) );
-        p_sys = (input_stream_sys_t*)s->p_sys;
-        p_sys->p_input = p_input;
+        if( p_sys->stream.tk[p_sys->stream.i_tk].i_end <= 0 )
+        {
+            msg_Err( s, "cannot pre fill buffer" );
+            goto error;
+        }
     }
+
+
     return s;
+
+error:
+    if( p_sys->b_block )
+    {
+        /* Nothing yet */
+    }
+    else
+    {
+        free( p_sys->stream.p_buffer );
+    }
+    free( s->p_sys );
+    vlc_object_detach( s );
+    vlc_object_destroy( s );
+    return NULL;
 }
 
 /****************************************************************************
- * input_StreamDelete:
+ * stream_AccessDelete:
  ****************************************************************************/
-void input_StreamDelete( stream_t *s )
+void stream_AccessDelete( stream_t *s )
 {
+    stream_sys_t *p_sys = s->p_sys;
+
+    vlc_object_detach( s );
+
+    if( p_sys->b_block )
+    {
+        block_ChainRelease( p_sys->block.p_first );
+    }
+    else
+    {
+        free( p_sys->stream.p_buffer );
+    }
+
+    if( p_sys->p_peek )
+        free( p_sys->p_peek );
+
     free( s->p_sys );
     vlc_object_destroy( s );
 }
 
+/****************************************************************************
+ * stream_AccessReset:
+ ****************************************************************************/
+void stream_AccessReset( stream_t *s )
+{
+    stream_sys_t *p_sys = s->p_sys;
+
+    p_sys->i_pos = p_sys->p_access->info.i_pos;
+
+    if( p_sys->b_block )
+    {
+        block_ChainRelease( p_sys->block.p_first );
+
+        /* Init all fields of p_sys->block */
+        p_sys->block.i_start = p_sys->i_pos;
+        p_sys->block.i_offset = 0;
+        p_sys->block.p_current = NULL;
+        p_sys->block.i_size = 0;
+        p_sys->block.p_first = NULL;
+        p_sys->block.pp_last = &p_sys->block.p_first;
+
+        /* Do the prebuffering */
+        AStreamPrebufferBlock( s );
+    }
+    else
+    {
+        int i;
+
+        /* Setup our tracks */
+        p_sys->stream.i_offset = 0;
+        p_sys->stream.i_tk     = 0;
+        p_sys->stream.i_used   = 0;
+
+        for( i = 0; i < STREAM_CACHE_TRACK; i++ )
+        {
+            p_sys->stream.tk[i].i_date  = 0;
+            p_sys->stream.tk[i].i_start = p_sys->i_pos;
+            p_sys->stream.tk[i].i_end   = p_sys->i_pos;
+        }
+
+        /* Do the prebuffering */
+        AStreamPrebufferStream( s );
+    }
+}
 
 /****************************************************************************
- * IStreamControl:
+ * AStreamControl:
  ****************************************************************************/
-static int IStreamControl( stream_t *s, int i_query, va_list args )
+static int AStreamControl( stream_t *s, int i_query, va_list args )
 {
-    input_stream_sys_t * p_sys = (input_stream_sys_t*)s->p_sys;
-    input_thread_t *p_input = p_sys->p_input;
+    stream_sys_t *p_sys = s->p_sys;
+    access_t     *p_access = p_sys->p_access;
 
-    vlc_bool_t *p_b;
-    int64_t    *p_i64, i64;
-    int        *p_int;
+    vlc_bool_t *p_bool;
+    int64_t    *pi_64, i_64;
+    int        i_int;
 
     switch( i_query )
     {
         case STREAM_GET_SIZE:
-            p_i64 = (int64_t*) va_arg( args, int64_t * );
-
-            vlc_mutex_lock( &p_input->stream.stream_lock );
-            *p_i64 = p_input->stream.p_selected_area->i_size;
-            vlc_mutex_unlock( &p_input->stream.stream_lock );
-            return VLC_SUCCESS;
+            pi_64 = (int64_t*)va_arg( args, int64_t * );
+            *pi_64 = p_access->info.i_size;
+            break;
 
         case STREAM_CAN_SEEK:
-            p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
-
-            vlc_mutex_lock( &p_input->stream.stream_lock );
-            *p_b = p_input->stream.b_seekable;
-            vlc_mutex_unlock( &p_input->stream.stream_lock );
-            return VLC_SUCCESS;
+            p_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
+            access2_Control( p_access, ACCESS_CAN_SEEK, p_bool );
+            break;
 
         case STREAM_CAN_FASTSEEK:
-            p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
-
-            vlc_mutex_lock( &p_input->stream.stream_lock );
-            *p_b = p_input->stream.b_seekable &&
-                   p_input->stream.i_method == INPUT_METHOD_FILE;
-            vlc_mutex_unlock( &p_input->stream.stream_lock );
-            return VLC_SUCCESS;
+            p_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
+            access2_Control( p_access, ACCESS_CAN_FASTSEEK, p_bool );
+            break;
 
         case STREAM_GET_POSITION:
-            p_i64 = (int64_t*) va_arg( args, int64_t * );
-
-            vlc_mutex_lock( &p_input->stream.stream_lock );
-            *p_i64 = p_input->stream.p_selected_area->i_tell;
-            vlc_mutex_unlock( &p_input->stream.stream_lock );
-            return VLC_SUCCESS;
+            pi_64 = (int64_t*)va_arg( args, int64_t * );
+            *pi_64 = p_sys->i_pos;
+            break;
 
         case STREAM_SET_POSITION:
-        {
-            int64_t i_skip;
-            i64 = (int64_t) va_arg( args, int64_t );
-
-            vlc_mutex_lock( &p_input->stream.stream_lock );
-            if( i64 < 0 ||
-                ( p_input->stream.p_selected_area->i_size > 0 &&
-                  p_input->stream.p_selected_area->i_size < i64 ) )
-            {
-                vlc_mutex_unlock( &p_input->stream.stream_lock );
-                msg_Warn( s, "seek out of bound" );
-                return VLC_EGENERIC;
-            }
-
-            i_skip = i64 - p_input->stream.p_selected_area->i_tell;
-
-            if( i_skip == 0 )
-            {
-                vlc_mutex_unlock( &p_input->stream.stream_lock );
-                return VLC_SUCCESS;
-            }
-
-            if( i_skip > 0 && i_skip < p_input->p_last_data -
-                            p_input->p_current_data - 1 )
-            {
-                /* We can skip without reading/seeking */
-                p_input->p_current_data += i_skip;
-                p_input->stream.p_selected_area->i_tell = i64;
-                vlc_mutex_unlock( &p_input->stream.stream_lock );
-                return VLC_SUCCESS;
-            }
-            vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-            if( p_input->stream.b_seekable &&
-                ( p_input->stream.i_method == INPUT_METHOD_FILE ||
-                  i_skip < 0 || i_skip >= ( p_input->i_mtu > 0 ?
-                                            p_input->i_mtu : 4096 ) ) )
-            {
-                input_AccessReinit( p_input );
-                p_input->pf_seek( p_input, i64 );
-                return VLC_SUCCESS;
-            }
-
-            if( i_skip > 0 )
-            {
-                data_packet_t *p_data;
-
-                if( i_skip > 1000 )
-                {
-                    msg_Warn( s, "will skip "I64Fd" bytes, slow", i_skip );
-                }
-
-                while( i_skip > 0 )
-                {
-                    int i_read;
-
-                    i_read = input_SplitBuffer( p_input, &p_data,
-                                 __MIN( (int)p_input->i_bufsize, i_skip ) );
-                    if( i_read < 0 )
-                    {
-                        return VLC_EGENERIC;
-                    }
-                    i_skip -= i_read;
-
-                    input_DeletePacket( p_input->p_method_data, p_data );
-                    if( i_read == 0 && i_skip > 0 )
-                    {
-                        return VLC_EGENERIC;
-                    }
-                }
-            }
-            return VLC_SUCCESS;
-        }
+            i_64 = (int64_t)va_arg( args, int64_t );
+            if( p_sys->b_block )
+                return AStreamSeekBlock( s, i_64 );
+            else
+                return AStreamSeekStream( s, i_64 );
 
         case STREAM_GET_MTU:
-            p_int = (int*) va_arg( args, int * );
-            *p_int = p_input->i_mtu;
-            return VLC_SUCCESS;
+            return VLC_EGENERIC;
 
         case STREAM_CONTROL_ACCESS:
-        {
-            int i_int = (int) va_arg( args, int );
+            i_int = (int) va_arg( args, int );
             if( i_int != ACCESS_SET_PRIVATE_ID_STATE )
             {
                 msg_Err( s, "Hey, what are you thinking ?"
                             "DON'T USE STREAM_CONTROL_ACCESS !!!" );
                 return VLC_EGENERIC;
             }
-            if( p_input->pf_access_control )
-            {
-                return p_input->pf_access_control( p_input, i_int, args );
-            }
-            return VLC_EGENERIC;
-        }
+            return access2_Control( p_access, i_int, args );
 
         default:
             msg_Err( s, "invalid stream_vaControl query=0x%x", i_query );
             return VLC_EGENERIC;
     }
+    return VLC_SUCCESS;
 }
 
+
+
 /****************************************************************************
- * IStreamRead:
+ * Method 1:
  ****************************************************************************/
-static int IStreamRead( stream_t *s, void *p_data, int i_data )
+static void AStreamPrebufferBlock( stream_t *s )
 {
-    input_stream_sys_t * p_sys = (input_stream_sys_t*)s->p_sys;
-    input_thread_t *p_input = p_sys->p_input;
-    uint8_t *p = (uint8_t*)p_data;
+    stream_sys_t *p_sys = s->p_sys;
+    access_t     *p_access = p_sys->p_access;
 
-    int i_read = 0;
+    int64_t i_first = 0;
+    int64_t i_start;
 
-    if( p_data == NULL && i_data > 0 )
+    msg_Dbg( s, "pre buffering" );
+    i_start = mdate();
+    for( ;; )
     {
-        int64_t i_pos;
+        int64_t i_date = mdate();
+        block_t *b;
 
-        stream_Control( s, STREAM_GET_POSITION, &i_pos );
+        if( s->b_die ||
+            p_sys->block.i_size > STREAM_CACHE_PREBUFFER_SIZE ||
+            ( i_first > 0 && i_first + STREAM_CACHE_PREBUFFER_LENGTH < i_date ) )
+        {
+            int64_t i_byterate;
+
+            /* Update stat */
+            p_sys->stat.i_bytes = p_sys->block.i_size;
+            p_sys->stat.i_read_time = i_date - i_start;
+            i_byterate = ( I64C(1000000) * p_sys->stat.i_bytes ) /
+                         (p_sys->stat.i_read_time+1);
+
+            msg_Dbg( s, "prebuffering done %lld bytes in %llds - %lld kbytes/s",
+                     p_sys->stat.i_bytes,
+                     p_sys->stat.i_read_time / I64C(1000000),
+                     i_byterate / 1024 );
+            break;
+        }
 
-        i_pos += i_data;
-        if( stream_Control( s, STREAM_SET_POSITION, i_pos ) )
+        /* Fetch a block */
+        if( ( b = p_access->pf_block( p_access ) ) == NULL )
         {
-            return 0;
+            if( p_access->info.b_eof )
+                break;
+
+            msleep( STREAM_DATA_WAIT );
+            continue;
         }
-        return i_data;
+
+        if( i_first == 0 )
+            i_first = mdate();
+
+        /* Append the block */
+        p_sys->block.i_size += b->i_buffer;
+        *p_sys->block.pp_last = b;
+        p_sys->block.pp_last = &b->p_next;
+
+        p_sys->stat.i_read_count++;
     }
 
-    while( i_data > 0 && !p_input->b_die )
+    p_sys->block.p_current = p_sys->block.p_first;
+}
+
+static int AStreamRefillBlock( stream_t *s );
+
+static int AStreamReadBlock( stream_t *s, void *p_read, int i_read )
+{
+    stream_sys_t *p_sys = s->p_sys;
+
+    uint8_t *p_data= (uint8_t*)p_read;
+    int     i_data = 0;
+
+    /* It means EOF */
+    if( p_sys->block.p_current == NULL )
+        return 0;
+
+    while( i_data < i_read )
     {
-        ssize_t i_count = p_input->p_last_data - p_input->p_current_data;
+        int i_current = p_sys->block.p_current->i_buffer - p_sys->block.i_offset;
+        int i_copy = __MIN( i_current, i_read - i_data);
 
-        if( i_count <= 0 )
+        /* Copy data */
+        if( p_data )
         {
-            /* Go to the next buffer */
-            i_count = input_FillBuffer( p_input );
+            memcpy( p_data, &p_sys->block.p_current->p_buffer[p_sys->block.i_offset], i_copy );
+            p_data += i_copy;
+        }
+        i_data += i_copy;
 
-            if( i_count < 0 ) return -1;
-            else if( i_count == 0 )
+        p_sys->block.i_offset += i_copy;
+        if( p_sys->block.i_offset >= p_sys->block.p_current->i_buffer )
+        {
+            /* Current block is now empty, switch to next */
+            if( p_sys->block.p_current )
+            {
+                p_sys->block.i_offset = 0;
+                p_sys->block.p_current = p_sys->block.p_current->p_next;
+            }
+            /*Get a new block */
+            if( AStreamRefillBlock( s ) )
             {
-                /* We reached the EOF */
                 break;
             }
         }
-
-        i_count = __MIN( i_data, i_count );
-        memcpy( p, p_input->p_current_data, i_count );
-        p_input->p_current_data += i_count;
-        p += i_count;
-        i_data -= i_count;
-        i_read += i_count;
-
-        /* Update stream position */
-        vlc_mutex_lock( &p_input->stream.stream_lock );
-        p_input->stream.p_selected_area->i_tell += i_count;
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
     }
 
-    return i_read;
+    p_sys->i_pos += i_data;
+    return i_data;
 }
 
-/****************************************************************************
- * IStreamPeek:
- ****************************************************************************/
-static int IStreamPeek( stream_t *s, uint8_t **pp_peek, int i_peek )
+static int AStreamPeekBlock( stream_t *s, uint8_t **pp_peek, int i_read )
 {
-    input_stream_sys_t * p_sys = (input_stream_sys_t*)s->p_sys;
-    return input_Peek( p_sys->p_input, pp_peek, i_peek );
+    stream_sys_t *p_sys = s->p_sys;
+    uint8_t *p_data;
+    int      i_data = 0;
+    block_t *b;
+    int      i_offset;
+
+    if( p_sys->block.p_current == NULL )
+        return 0; /* EOF */
+
+    /* We can directly give a pointer over our buffer */
+    if( i_read <= p_sys->block.p_current->i_buffer - p_sys->block.i_offset )
+    {
+        *pp_peek = &p_sys->block.p_current->p_buffer[p_sys->block.i_offset];
+        return i_read;
+    }
+
+    /* We need to create a local copy */
+    if( p_sys->i_peek < i_read )
+    {
+        if( p_sys->p_peek )
+            free( p_sys->p_peek );
+        p_sys->i_peek = i_read;
+        p_sys->p_peek = malloc( p_sys->i_peek );
+    }
+
+    /* Fill enough data */
+    while( p_sys->block.i_size - (p_sys->i_pos - p_sys->block.i_start) < i_read )
+    {
+        block_t **pp_last = p_sys->block.pp_last;
+
+        if( AStreamRefillBlock( s ) )
+            break;
+
+        /* Our buffer are probably filled enough, don't try anymore */
+        if( pp_last == p_sys->block.pp_last )
+            break;
+    }
+
+    /* Copy what we have */
+    b = p_sys->block.p_current;
+    i_offset = p_sys->block.i_offset;
+    p_data = p_sys->p_peek;
+
+    while( b && i_data < i_read )
+    {
+        int i_current = b->i_buffer - i_offset;
+        int i_copy = __MIN( i_current, i_read - i_data );
+
+        memcpy( p_data, &b->p_buffer[i_offset], i_copy );
+        i_data += i_copy;
+        p_data += i_copy;
+        i_offset += i_copy;
+
+        if( i_offset >= b->i_buffer )
+        {
+            i_offset = 0;
+            b = b->p_next;
+        }
+    }
+
+    *pp_peek = p_sys->p_peek;
+    return i_data;
 }
 
-/****************************************************************************
- * stream_Demux*: create a demuxer for an outpout stream (allow demuxer chain)
- ****************************************************************************/
-typedef struct
+static int AStreamSeekBlock( stream_t *s, int64_t i_pos )
 {
-    /* Data buffer */
-    vlc_mutex_t lock;
-    int         i_buffer;
-    int         i_buffer_size;
-    uint8_t     *p_buffer;
+    stream_sys_t *p_sys = s->p_sys;
+    access_t   *p_access = p_sys->p_access;
+    int64_t    i_offset = i_pos - p_sys->block.i_start;
+    vlc_bool_t b_seek;
 
-    int64_t     i_pos;
+    /* We already have thoses data, just update p_current/i_offset */
+    if( i_offset >= 0 && i_offset < p_sys->block.i_size )
+    {
+        block_t *b = p_sys->block.p_first;
+        int i_current = 0;
 
-    /* Demuxer */
-    char        *psz_name;
-    es_out_t    *out;
-    demux_t     *p_demux;
-} d_stream_sys_t;
+        while( i_current + b->i_buffer < i_offset )
+        {
+            i_current += b->i_buffer;
+            b = b->p_next;
+        }
 
-static int DStreamRead   ( stream_t *, void *p_read, int i_read );
-static int DStreamPeek   ( stream_t *, uint8_t **pp_peek, int i_peek );
-static int DStreamControl( stream_t *, int i_query, va_list );
-static int DStreamThread ( stream_t * );
+        p_sys->block.p_current = b;
+        p_sys->block.i_offset = i_offset - i_current;
 
+        p_sys->i_pos = i_pos;
 
-stream_t *__stream_DemuxNew( vlc_object_t *p_obj, char *psz_demux, es_out_t *out )
-{
-    /* We create a stream reader, and launch a thread */
-    stream_t       *s;
-    d_stream_sys_t *p_sys;
+        return VLC_SUCCESS;
+    }
 
-    if( psz_demux == NULL || *psz_demux == '\0' )
+    /* We may need to seek or to read data */
+    if( i_offset < 0 )
     {
-        return NULL;
+        vlc_bool_t b_aseek;
+        access2_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
+
+        if( !b_aseek )
+        {
+            msg_Err( s, "backward seek impossible (access non seekable)" );
+            return VLC_EGENERIC;
+        }
+
+        b_seek = VLC_TRUE;
     }
+    else
+    {
+        vlc_bool_t b_aseek, b_aseekfast;
 
-    s = vlc_object_create( p_obj, sizeof( stream_t ) );
-    s->pf_block  = NULL;
-    s->pf_read   = DStreamRead;
-    s->pf_peek   = DStreamPeek;
-    s->pf_control= DStreamControl;
-
-    s->p_sys = malloc( sizeof( d_stream_sys_t) );
-    p_sys = (d_stream_sys_t*)s->p_sys;
-
-    vlc_mutex_init( s, &p_sys->lock );
-    p_sys->i_buffer = 0;
-    p_sys->i_buffer_size = 1000000;
-    p_sys->p_buffer = malloc( p_sys->i_buffer_size );
-    p_sys->i_pos = 0;
-    p_sys->psz_name = strdup( psz_demux );
-    p_sys->out = out;
-    p_sys->p_demux = NULL;
-
-    if( vlc_thread_create( s, "stream out", DStreamThread, VLC_THREAD_PRIORITY_INPUT, VLC_FALSE ) )
-    {
-        vlc_mutex_destroy( &p_sys->lock );
-        vlc_object_destroy( s );
-        free( p_sys );
-        return NULL;
+        access2_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
+        access2_Control( p_access, ACCESS_CAN_FASTSEEK, &b_aseekfast );
+
+        if( !b_aseek )
+        {
+            b_seek = VLC_FALSE;
+            msg_Warn( s, "%lld bytes need to be skipped (access non seekable)",
+                      i_offset - p_sys->block.i_size );
+        }
+        else
+        {
+            int64_t i_skip = i_offset - p_sys->block.i_size;
+
+            /* Avg bytes per packets */
+            int i_avg = p_sys->stat.i_bytes / p_sys->stat.i_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 = VLC_FALSE;
+            else
+                b_seek = VLC_TRUE;
+
+            msg_Dbg( s, "b_seek=%d th*avg=%d skip=%lld",
+                     b_seek, i_th*i_avg, i_skip );
+        }
     }
 
-    return s;
-}
+    if( b_seek )
+    {
+        int64_t i_start, i_end;
+        /* Do the access seek */
+        i_start = mdate();
+        if( p_access->pf_seek( p_access, i_pos ) )
+            return VLC_EGENERIC;
+        i_end = mdate();
 
-void     stream_DemuxSend( stream_t *s, block_t *p_block )
-{
-    d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+        /* Release data */
+        block_ChainRelease( p_sys->block.p_first );
+
+        /* Reinit */
+        p_sys->block.i_start = p_sys->i_pos = i_pos;
+        p_sys->block.i_offset = 0;
+        p_sys->block.p_current = NULL;
+        p_sys->block.i_size = 0;
+        p_sys->block.p_first = NULL;
+        p_sys->block.pp_last = &p_sys->block.p_first;
 
-    if( p_block->i_buffer > 0 )
+        /* Refill a block */
+        if( AStreamRefillBlock( s ) )
+        {
+            msg_Err( s, "cannot re fill buffer" );
+            return VLC_EGENERIC;
+        }
+        /* Update stat */
+        p_sys->stat.i_seek_time += i_end - i_start;
+        p_sys->stat.i_seek_count++;
+        return VLC_SUCCESS;
+    }
+    else
     {
-        vlc_mutex_lock( &p_sys->lock );
-        /* Realloc if needed */
-        if( p_sys->i_buffer + p_block->i_buffer > p_sys->i_buffer_size )
+        /* Read enought data */
+        while( p_sys->block.i_start + p_sys->block.i_size < i_pos )
         {
-            if( p_sys->i_buffer_size > 5000000 )
+            if( AStreamRefillBlock( s ) )
+            {
+                msg_Err( s, "can't read enough data in seek" );
+                return VLC_EGENERIC;
+            }
+            while( p_sys->block.p_current &&
+                   p_sys->i_pos + p_sys->block.p_current->i_buffer < i_pos )
             {
-                vlc_mutex_unlock( &p_sys->lock );
-                msg_Err( s, "stream_DemuxSend: buffer size > 5000000" );
-                block_Release( p_block );
-                return;
+                p_sys->i_pos += p_sys->block.p_current->i_buffer;
+                p_sys->block.p_current = p_sys->block.p_current->p_next;