* all: new sout scheme. Now a chain of module are created that can
authorLaurent Aimar <fenrir@videolan.org>
Sun, 13 Apr 2003 20:00:21 +0000 (20:00 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Sun, 13 Apr 2003 20:00:21 +0000 (20:00 +0000)
modify/apply on all streams, --sout has the same behavour expect when
starting with a '#'.

 With a starting '#' you can specify a chain of modules, it's still
unstable but a lot more powerfull.
 You have access to duplicate(that duplicate all stream), transcode
(using only ffmpeg), standard/std and es (that apply muxers and access),
and display. You could chain them with ':' and specify options with
{option1=value,option2=value[,...]}.

ex: * to stream and see the stream to udp/ts:ip
 --sout '#duplicate{dst=display,dst=std{access=udp,mux=ts,url=ip}}'
    * to transcode,see and stream
 --sout '#transcode{acodec=mpga}:duplicate{dst=display,dst=std{access=udp,mux=ts,url=ip}}'

 Without a starting '#', the url is converted into '#std{acces=,mux=,url}'
Test and report bugs :)

25 files changed:
configure.ac.in
include/input_ext-intf.h
include/stream_output.h
include/vlc_common.h
modules/Makefile.am
modules/mux/avi.c
modules/mux/mpeg/ps.c
modules/mux/mpeg/ts.c
modules/mux/ogg.c
modules/packetizer/a52.c
modules/packetizer/copy.c
modules/packetizer/mpeg4audio.c
modules/packetizer/mpeg4video.c
modules/packetizer/mpegaudio.c
modules/packetizer/mpegvideo.c
modules/stream_out/Modules.am [new file with mode: 0644]
modules/stream_out/display.c [new file with mode: 0644]
modules/stream_out/dummy.c [new file with mode: 0644]
modules/stream_out/duplicate.c [new file with mode: 0644]
modules/stream_out/es.c [new file with mode: 0644]
modules/stream_out/standard.c [new file with mode: 0644]
modules/stream_out/transcode.c [new file with mode: 0644]
src/input/input_dec.c
src/input/input_programs.c
src/stream_output/stream_output.c

index 3c2944c..d8f050e 100644 (file)
@@ -334,6 +334,7 @@ AC_CHECK_LIB(m,cos,
   LDFLAGS_a52tofloat32="${LDFLAGS_a52tofloat32} -lm")
 AC_CHECK_LIB(m,pow,
   LDFLAGS_ffmpeg="${LDFLAGS_ffmpeg} -lm"
+  LDFLAGS_stream_out_transcode="${LDFLAGS_stream_out_transcode} -lm"
   LDFLAGS_imdct="${LDFLAGS_imdct} -lm"
   LDFLAGS_imdct3dn="${LDFLAGS_imdct3dn} -lm"
   LDFLAGS_imdctsse="${LDFLAGS_imdctsse} -lm"
@@ -1017,7 +1018,8 @@ then
   PLUGINS="${PLUGINS} packetizer_mpeg4video packetizer_mpeg4audio"
   PLUGINS="${PLUGINS} packetizer_copy"
 
-  PLUGINS="${PLUGINS} vout_encoder"
+  PLUGINS="${PLUGINS} stream_out_dummy stream_out_standard stream_out_es"
+  PLUGINS="${PLUGINS} stream_out_duplicate stream_out_display"
 
     dnl Ogg/ogm
     AC_CHECK_HEADERS(ogg/ogg.h, [
@@ -1510,6 +1512,10 @@ then
   then
     CPPFLAGS_ffmpeg="${CPPFLAGS_ffmpeg} -I${with_ffmpeg}/include/ffmpeg"
     LDFLAGS_ffmpeg="${LDFLAGS_ffmpeg} -L${with_ffmpeg}/lib"
+
+    CPPFLAGS_stream_out_transcode="${CPPFLAGS_stream_out_transcode} -I${with_ffmpeg}/include/ffmpeg"
+    LDFLAGS_stream_out_transcode="${LDFLAGS_stream_out_transcode} -L${with_ffmpeg}/lib"
+
   fi
 
   dnl Add postprocessing modules
@@ -1538,9 +1544,13 @@ then
     then
       dnl  Use a custom libffmpeg
       AC_MSG_RESULT(${real_ffmpeg_tree}/libavcodec/libavcodec.a)
-      BUILTINS="${BUILTINS} ffmpeg"
+      BUILTINS="${BUILTINS} ffmpeg stream_out_transcode"
       LDFLAGS_ffmpeg="${LDFLAGS_ffmpeg} -L${real_ffmpeg_tree}/libavcodec -lavcodec"
       CPPFLAGS_ffmpeg="${CPPFLAGS_ffmpeg} -I${real_ffmpeg_tree}/libavcodec"
+
+      LDFLAGS_stream_out_transcode="${LDFLAGS_stream_out_transcode} -L${real_ffmpeg_tree}/libavcodec -lavcodec"
+      CPPFLAGS_stream_out_transcode="${CPPFLAGS_stream_out_transcode} -I${real_ffmpeg_tree}/libavcodec"
+
     else
       dnl  The given libavcodec wasn't built
       AC_MSG_RESULT(no)
@@ -1550,8 +1560,9 @@ then
     CPPFLAGS="${CPPFLAGS_save} ${CPPFLAGS_ffmpeg}"
     LDFLAGS="${LDFLAGS_save} ${LDFLAGS_ffmpeg}"
     AC_CHECK_LIB(avcodec, avcodec_init, [
-      BUILTINS="${BUILTINS} ffmpeg"
-      LDFLAGS_ffmpeg="${LDFLAGS_ffmpeg} -lavcodec" ],
+      BUILTINS="${BUILTINS} ffmpeg stream_out_transcode"
+      LDFLAGS_ffmpeg="${LDFLAGS_ffmpeg} -lavcodec" 
+      LDFLAGS_stream_out_transcode="${LDFLAGS_stream_out_transcode} -lavcodec" ],
       [ AC_MSG_ERROR([Cannot find libavcodec library...]) ])
     LDFLAGS="${LDFLAGS_save}"
     CPPFLAGS="${CPPFLAGS_save}"
index fa6acdb..6b382fe 100644 (file)
@@ -4,7 +4,7 @@
  * control the pace of reading.
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
- * $Id: input_ext-intf.h,v 1.87 2003/03/24 17:15:29 gbazin Exp $
+ * $Id: input_ext-intf.h,v 1.88 2003/04/13 20:00:20 fenrir Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -71,6 +71,9 @@ struct es_descriptor_t
 
     count_t                 c_packets;                 /* total packets read */
     count_t                 c_invalid_packets;       /* invalid packets read */
+
+    /* XXX hack: to force a decoder instead of mode based on sout */
+    vlc_bool_t              b_force_decoder;
 };
 
 /* Special PID values - note that the PID is only on 13 bits, and that values
index 91427b2..56ac3f3 100644 (file)
@@ -2,7 +2,7 @@
  * stream_output.h : stream output module
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: stream_output.h,v 1.9 2003/03/11 19:02:30 fenrir Exp $
+ * $Id: stream_output.h,v 1.10 2003/04/13 20:00:20 fenrir Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *          Laurent Aimar <fenrir@via.ecp.fr>
@@ -57,12 +57,24 @@ struct sout_buffer_t
     struct sout_buffer_t    *p_next;
 };
 
-struct sout_packet_format_t
+struct sout_format_t
 {
-    int             i_cat;      // AUDIO_ES, VIDEO_ES, SPU_ES
+    int             i_cat;
     vlc_fourcc_t    i_fourcc;
 
-    void            *p_format;  // WAVEFORMATEX or BITMAPINFOHEADER
+    /* audio */
+    int             i_sample_rate;
+    int             i_channels;
+    int             i_block_align;
+
+    /* video */
+    int             i_width;
+    int             i_height;
+
+    int             i_bitrate;
+    int             i_extra_data;
+    uint8_t         *p_extra_data;
+
 };
 
 struct sout_fifo_t
@@ -75,39 +87,36 @@ struct sout_fifo_t
     sout_buffer_t       **pp_last;
 };
 
+typedef struct sout_stream_id_t  sout_stream_id_t;
+
 /* for mux */
 struct sout_input_t
 {
-//    vlc_mutex_t             lock;
-
-    sout_instance_t         *p_sout;
+    sout_instance_t *p_sout;
 
-    sout_packet_format_t    input_format;
-    sout_fifo_t             *p_fifo;
+    sout_format_t   *p_fmt;
+    sout_fifo_t     *p_fifo;
 
-    void                    *p_sys;
+    void            *p_sys;
 };
 
-/* for packetizr */
+/* for packetizer */
 struct sout_packetizer_input_t
 {
 
-    sout_instance_t         *p_sout;
-    sout_packet_format_t    input_format;
-
-//    vlc_mutex_t             lock;
-    int                     i_nb_inputs;
-    sout_input_t            **pp_inputs;
+    sout_instance_t     *p_sout;
 
-    int                     i_nb_mux;   // not really used, just usefull with TAB_*
-    sout_mux_t              **pp_mux;
+    sout_format_t       *p_fmt;
 
+    sout_stream_id_t    *id;
 };
 
+
 #define SOUT_METHOD_NONE        0x00
 #define SOUT_METHOD_FILE        0x10
 #define SOUT_METHOD_NETWORK     0x20
 
+typedef struct sout_access_out_sys_t   sout_access_out_sys_t;
 struct sout_access_out_t
 {
     VLC_COMMON_MEMBERS
@@ -180,36 +189,129 @@ struct  sout_mux_t
     mtime_t     i_add_stream_start;
 };
 
+
+
+struct sout_cfg_t
+{
+    sout_cfg_t  *p_next;
+
+    char        *psz_name;
+    char        *psz_value;
+};
+
+typedef struct sout_stream_sys_t sout_stream_sys_t;
+struct sout_stream_t
+{
+    VLC_COMMON_MEMBERS
+
+    module_t                *p_module;
+    sout_instance_t         *p_sout;
+
+    char                    *psz_name;
+    sout_cfg_t              *p_cfg;
+    char                    *psz_next;
+
+    /* add, remove a stream */
+    sout_stream_id_t *      (*pf_add) ( sout_stream_t *, sout_format_t * );
+    int                     (*pf_del) ( sout_stream_t *, sout_stream_id_t * );
+
+    /* manage a packet */
+    int                     (*pf_send)( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* );
+
+    /* private */
+    sout_stream_sys_t       *p_sys;
+};
+
 typedef struct sout_instance_sys_t sout_instance_sys_t;
 struct sout_instance_t
 {
     VLC_COMMON_MEMBERS
 
-    /* complete sout string like udp/ts:239.255.12.42#file/ps://essai.ps */
     char * psz_sout;
-
-    /* here are stored the parsed psz_sout */
-    int                     i_nb_dest;
-    char                    **ppsz_dest;
+    char * psz_chain;
 
     /* muxer data */
     int                     i_preheader;    /* max over all muxer */
 
-    int                     i_nb_mux;
-    sout_mux_t              **pp_mux;
-
-    /* here are all packetizer inputs accepted by at least one muxer */
     vlc_mutex_t             lock;
-    int                     i_nb_inputs;
-    sout_packetizer_input_t **pp_inputs;
+    sout_stream_t           *p_stream;
 
     /* sout private */
     sout_instance_sys_t     *p_sys;
 };
 
+/* some macro */
+#define TAB_APPEND( count, tab, p )             \
+    if( (count) > 0 )                           \
+    {                                           \
+        (tab) = realloc( (tab), sizeof( void ** ) * ( (count) + 1 ) ); \
+    }                                           \
+    else                                        \
+    {                                           \
+        (tab) = malloc( sizeof( void ** ) );    \
+    }                                           \
+    (void**)(tab)[(count)] = (void*)(p);        \
+    (count)++
+
+#define TAB_FIND( count, tab, p, index )        \
+    {                                           \
+        int _i_;                                \
+        (index) = -1;                           \
+        for( _i_ = 0; _i_ < (count); _i_++ )    \
+        {                                       \
+            if((void**)(tab)[_i_]==(void*)(p))  \
+            {                                   \
+                (index) = _i_;                  \
+                break;                          \
+            }                                   \
+        }                                       \
+    }
+
+#define TAB_REMOVE( count, tab, p )             \
+    {                                           \
+        int i_index;                            \
+        TAB_FIND( count, tab, p, i_index );     \
+        if( i_index >= 0 )                      \
+        {                                       \
+            if( count > 1 )                     \
+            {                                   \
+                memmove( ((void**)tab + i_index),    \
+                         ((void**)tab + i_index+1),  \
+                         ( (count) - i_index - 1 ) * sizeof( void* ) );\
+            }                                   \
+            else                                \
+            {                                   \
+                free( tab );                    \
+                (tab) = NULL;                   \
+            }                                   \
+            (count)--;                          \
+        }                                       \
+    }
+
+static inline sout_cfg_t *sout_cfg_find( sout_cfg_t *p_cfg, char *psz_name )
+{
+    while( p_cfg && strcmp( p_cfg->psz_name, psz_name ) )
+    {
+        p_cfg = p_cfg->p_next;
+    }
 
+    return p_cfg;
+}
 
-
+static inline char *sout_cfg_find_value( sout_cfg_t *p_cfg, char *psz_name )
+{
+    while( p_cfg && strcmp( p_cfg->psz_name, psz_name ) )
+    {
+        p_cfg = p_cfg->p_next;
+    }
+
+    if( p_cfg && p_cfg->psz_value )
+    {
+        return( p_cfg->psz_value );
+    }
+
+    return NULL;
+}
 /*****************************************************************************
  * Prototypes
  *****************************************************************************/
@@ -227,7 +329,7 @@ VLC_EXPORT( sout_buffer_t *, sout_FifoShow,       ( sout_fifo_t * ) );
 
 
 #define sout_InputNew( a, b ) __sout_InputNew( VLC_OBJECT(a), b )
-VLC_EXPORT( sout_packetizer_input_t *, __sout_InputNew,       ( vlc_object_t *, sout_packet_format_t * ) );
+VLC_EXPORT( sout_packetizer_input_t *, __sout_InputNew,       ( vlc_object_t *, sout_format_t * ) );
 VLC_EXPORT( int,            sout_InputDelete,      ( sout_packetizer_input_t * ) );
 VLC_EXPORT( int,            sout_InputSendBuffer,  ( sout_packetizer_input_t *, sout_buffer_t* ) );
 
@@ -243,3 +345,13 @@ VLC_EXPORT( void,                sout_AccessOutDelete, ( sout_access_out_t * ) )
 VLC_EXPORT( int,                 sout_AccessOutSeek,   ( sout_access_out_t *, off_t ) );
 VLC_EXPORT( int,                 sout_AccessOutWrite,  ( sout_access_out_t *, sout_buffer_t * ) );
 
+VLC_EXPORT( sout_mux_t *,       sout_MuxNew,          ( sout_instance_t*, char *, sout_access_out_t * ) );
+VLC_EXPORT( sout_input_t *,     sout_MuxAddStream,    ( sout_mux_t *, sout_format_t * ) );
+VLC_EXPORT( void,               sout_MuxDeleteStream, ( sout_mux_t *, sout_input_t * ) );
+VLC_EXPORT( void,               sout_MuxDelete,       ( sout_mux_t * ) );
+VLC_EXPORT( void,               sout_MuxSendBuffer, ( sout_mux_t *, sout_input_t  *, sout_buffer_t * ) );
+
+VLC_EXPORT( char *,             sout_cfg_parser, ( char **, sout_cfg_t **, char * ) );
+VLC_EXPORT( sout_stream_t *,    sout_stream_new, ( sout_instance_t *, char *psz_chain ) );
+VLC_EXPORT( void,               sout_stream_delete, ( sout_stream_t *p_stream ) );
+
index 457b7ff..7ae22b1 100644 (file)
@@ -3,7 +3,7 @@
  * Collection of useful common types and macros definitions
  *****************************************************************************
  * Copyright (C) 1998, 1999, 2000 VideoLAN
- * $Id: vlc_common.h,v 1.59 2003/03/17 18:02:11 sam Exp $
+ * $Id: vlc_common.h,v 1.60 2003/04/13 20:00:20 fenrir Exp $
  *
  * Authors: Samuel Hocevar <sam@via.ecp.fr>
  *          Vincent Seguin <seguin@via.ecp.fr>
@@ -249,11 +249,11 @@ typedef struct sout_fifo_t sout_fifo_t;
 typedef struct sout_input_t sout_input_t;
 typedef struct sout_packetizer_input_t sout_packetizer_input_t;
 typedef struct sout_buffer_t sout_buffer_t;
-typedef struct sout_packet_format_t sout_packet_format_t;
 typedef struct sout_access_out_t sout_access_out_t;
 typedef struct sout_mux_t sout_mux_t;
-typedef struct sout_access_out_sys_t sout_access_out_sys_t;
-
+typedef struct sout_stream_t    sout_stream_t;
+typedef struct sout_cfg_t       sout_cfg_t;
+typedef struct sout_format_t    sout_format_t;
 /* Decoders */
 typedef struct decoder_fifo_t decoder_fifo_t;
 
index 0f70f23..03c2ca1 100644 (file)
@@ -62,6 +62,7 @@ EXTRA_DIST = \
        mux/Modules.am \
        mux/mpeg/Modules.am \
        packetizer/Modules.am \
+       stream_out/Modules.am \
        video_chroma/Modules.am \
        video_filter/Modules.am \
        video_filter/deinterlace/Modules.am \
index 03f1b58..5593e79 100644 (file)
@@ -2,7 +2,7 @@
  * avi.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: avi.c,v 1.11 2003/03/31 03:46:11 fenrir Exp $
+ * $Id: avi.c,v 1.12 2003/04/13 20:00:21 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
@@ -231,12 +231,12 @@ static void Close( vlc_object_t * p_this )
                     (uint64_t)p_stream->i_totalsize /
                     (uint64_t)p_stream->i_duration;
         }
-        msg_Err( p_mux, "stream[%d] duration:%lld totalsize:%lld frames:%d fps:%f kb/s:%d",
-                 i_stream,
-                 (int64_t)p_stream->i_duration / (int64_t)1000000,
-                 p_stream->i_totalsize,
-                 p_stream->i_frames,
-                 p_stream->f_fps, p_stream->i_bitrate/1024 );
+        msg_Info( p_mux, "stream[%d] duration:%lld totalsize:%lld frames:%d fps:%f kb/s:%d",
+                  i_stream,
+                  (int64_t)p_stream->i_duration / (int64_t)1000000,
+                  p_stream->i_totalsize,
+                  p_stream->i_frames,
+                  p_stream->f_fps, p_stream->i_bitrate/1024 );
     }
 
     p_hdr = avi_HeaderCreateRIFF( p_mux );
@@ -266,11 +266,6 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
         msg_Err( p_mux, "too many streams" );
         return( -1 );
     }
-    if( p_input->input_format.p_format == NULL )
-    {
-        msg_Err( p_mux, "stream descriptor missing" );
-        return( -1 );
-    }
 
     msg_Dbg( p_mux, "adding input" );
     p_input->p_sys = malloc( sizeof( int ) );
@@ -278,49 +273,96 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
     *((int*)p_input->p_sys) = p_sys->i_streams;
     p_stream = &p_sys->stream[p_sys->i_streams];
 
-    switch( p_input->input_format.i_cat )
+    switch( p_input->p_fmt->i_cat )
     {
         case AUDIO_ES:
+            p_stream->i_cat = AUDIO_ES;
+            p_stream->fcc[0] = '0' + p_sys->i_streams / 10;
+            p_stream->fcc[1] = '0' + p_sys->i_streams % 10;
+            p_stream->fcc[2] = 'w';
+            p_stream->fcc[3] = 'b';
+
+            p_stream->p_bih = NULL;
+
+            p_stream->p_wf  = malloc( sizeof( WAVEFORMATEX ) + p_input->p_fmt->i_extra_data );
+#define p_wf p_stream->p_wf
+            p_wf->cbSize = p_input->p_fmt->i_extra_data;
+            if( p_wf->cbSize > 0 )
+            {
+                memcpy( &p_wf[1],
+                        p_input->p_fmt->p_extra_data,
+                        p_input->p_fmt->i_extra_data );
+            }
+            p_wf->nChannels      = p_input->p_fmt->i_channels;
+            p_wf->nSamplesPerSec = p_input->p_fmt->i_sample_rate;
+            p_wf->nBlockAlign    = p_input->p_fmt->i_block_align;
+            p_wf->nAvgBytesPerSec= p_input->p_fmt->i_bitrate / 8;
+            p_wf->wBitsPerSample = 0;
+
+            switch( p_input->p_fmt->i_fourcc )
             {
-                WAVEFORMATEX *p_wf =
-                    (WAVEFORMATEX*)p_input->input_format.p_format;
-
-                p_stream->i_cat = AUDIO_ES;
-                p_stream->fcc[0] = '0' + p_sys->i_streams / 10;
-                p_stream->fcc[1] = '0' + p_sys->i_streams % 10;
-                p_stream->fcc[2] = 'w';
-                p_stream->fcc[3] = 'b';
-
-                p_stream->p_bih = NULL;
-                p_stream->p_wf  = malloc( sizeof( WAVEFORMATEX ) + p_wf->cbSize );
-                memcpy( p_stream->p_wf,
-                        p_wf,
-                        sizeof( WAVEFORMATEX ) + p_wf->cbSize);
+                case VLC_FOURCC( 'a', '5', '2', ' ' ):
+                    p_wf->wFormatTag = WAVE_FORMAT_A52;
+                    break;
+                case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
+                    p_wf->wFormatTag = WAVE_FORMAT_MPEGLAYER3;
+                    break;
+                case VLC_FOURCC( 'w', 'm', 'a', '1' ):
+                    p_wf->wFormatTag = WAVE_FORMAT_WMA1;
+                    break;
+                case VLC_FOURCC( 'w', 'm', 'a', '2' ):
+                    p_wf->wFormatTag = WAVE_FORMAT_WMA2;
+                    break;
+                case VLC_FOURCC( 'w', 'm', 'a', '3' ):
+                    p_wf->wFormatTag = WAVE_FORMAT_WMA3;
+                    break;
+                default:
+                    return VLC_EGENERIC;
             }
+#undef p_wf
             break;
         case VIDEO_ES:
+            p_stream->i_cat = VIDEO_ES;
+            p_stream->fcc[0] = '0' + p_sys->i_streams / 10;
+            p_stream->fcc[1] = '0' + p_sys->i_streams % 10;
+            p_stream->fcc[2] = 'd';
+            p_stream->fcc[3] = 'c';
+            if( p_sys->i_stream_video < 0 )
             {
-                BITMAPINFOHEADER *p_bih =
-                    (BITMAPINFOHEADER*)p_input->input_format.p_format;;
-
-                p_stream->i_cat = VIDEO_ES;
-                p_stream->fcc[0] = '0' + p_sys->i_streams / 10;
-                p_stream->fcc[1] = '0' + p_sys->i_streams % 10;
-                p_stream->fcc[2] = 'd';
-                p_stream->fcc[3] = 'c';
-                if( p_sys->i_stream_video < 0 )
-                {
-                    p_sys->i_stream_video = p_sys->i_streams;
-                }
-                p_stream->p_wf  = NULL;
-                p_stream->p_bih = malloc( p_bih->biSize );
-                memcpy( p_stream->p_bih,
-                        p_bih,
-                        p_bih->biSize );
+                p_sys->i_stream_video = p_sys->i_streams;
             }
+            p_stream->p_wf  = NULL;
+            p_stream->p_bih = malloc( sizeof( BITMAPINFOHEADER ) + p_input->p_fmt->i_extra_data );
+#define p_bih p_stream->p_bih
+            p_bih->biSize  = sizeof( BITMAPINFOHEADER ) + p_input->p_fmt->i_extra_data;
+            if( p_input->p_fmt->i_extra_data > 0 )
+            {
+                memcpy( &p_bih[1],
+                        p_input->p_fmt->p_extra_data,
+                        p_input->p_fmt->i_extra_data );
+            }
+            p_bih->biWidth = p_input->p_fmt->i_width;
+            p_bih->biHeight= p_input->p_fmt->i_height;
+            p_bih->biPlanes= 1;
+            p_bih->biBitCount       = 24;
+            p_bih->biSizeImage      = 0;
+            p_bih->biXPelsPerMeter  = 0;
+            p_bih->biYPelsPerMeter  = 0;
+            p_bih->biClrUsed        = 0;
+            p_bih->biClrImportant   = 0;
+            switch( p_input->p_fmt->i_fourcc )
+            {
+                case VLC_FOURCC( 'm', 'p', '4', 'v' ):
+                    p_bih->biCompression = VLC_FOURCC( 'X', 'V', 'I', 'D' );
+                    break;
+                default:
+                    p_bih->biCompression = p_input->p_fmt->i_fourcc;
+                    break;
+            }
+#undef p_bih
             break;
         default:
-            return( -1 );
+            return( VLC_EGENERIC );
     }
     p_stream->i_totalsize = 0;
     p_stream->i_frames    = 0;
@@ -333,7 +375,7 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
 
 
     p_sys->i_streams++;
-    return( 0 );
+    return( VLC_SUCCESS );
 }
 
 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
@@ -431,8 +473,8 @@ static int Mux      ( sout_mux_t *p_mux )
                 p_data->i_size += 1;
             }
 
-            sout_AccessOutWrite( p_mux->p_access, p_data );
             p_sys->i_movi_size += p_data->i_size;
+            sout_AccessOutWrite( p_mux->p_access, p_data );
 
             i_count--;
         }
@@ -649,7 +691,7 @@ static int avi_HeaderAdd_strh( sout_mux_t   *p_mux,
                 if( i_samplesize > 1 )
                 {
                     i_scale = i_samplesize;
-                    i_rate = i_scale * p_stream->i_bitrate / 8;
+                    i_rate = /*i_scale **/ p_stream->i_bitrate / 8;
                 }
                 else
                 {
index f3f6ebf..72474f1 100644 (file)
@@ -2,7 +2,7 @@
  * ps.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: ps.c,v 1.11 2003/03/11 19:02:30 fenrir Exp $
+ * $Id: ps.c,v 1.12 2003/04/13 20:00:21 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Eric Petit <titer@videolan.org>
@@ -174,11 +174,11 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
     msg_Dbg( p_mux, "adding input" );
     p_input->p_sys = (void*)p_stream = malloc( sizeof( ps_stream_t ) );
     p_stream->i_ok = 0;
-    switch( p_input->input_format.i_cat )
+    switch( p_input->p_fmt->i_cat )
     {
         case VIDEO_ES:
 
-            switch( p_input->input_format.i_fourcc )
+            switch( p_input->p_fmt->i_fourcc )
             {
                 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
                     p_stream->i_stream_id = p_sys->i_stream_id_mpgv;
@@ -190,7 +190,7 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
             }
             break;
         case AUDIO_ES:
-            switch( p_input->input_format.i_fourcc )
+            switch( p_input->p_fmt->i_fourcc )
             {
                 case VLC_FOURCC( 'a', '5', '2', ' ' ):
                 case VLC_FOURCC( 'a', '5', '2', 'b' ):
index 9e3811a..ca347da 100644 (file)
@@ -2,7 +2,7 @@
  * ts.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: ts.c,v 1.15 2003/03/11 19:02:30 fenrir Exp $
+ * $Id: ts.c,v 1.16 2003/04/13 20:00:21 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Eric Petit <titer@videolan.org>
@@ -223,8 +223,6 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
 {
     sout_mux_sys_t      *p_sys = p_mux->p_sys;
     ts_stream_t         *p_stream;
-    BITMAPINFOHEADER    *p_bih;
-    WAVEFORMATEX        *p_wf;
 
     msg_Dbg( p_mux, "adding input" );
     p_input->p_sys = (void*)p_stream = malloc( sizeof( ts_stream_t ) );
@@ -236,10 +234,10 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
     }
     p_stream->i_continuity_counter = 0;
 
-    switch( p_input->input_format.i_cat )
+    switch( p_input->p_fmt->i_cat )
     {
         case VIDEO_ES:
-            switch( p_input->input_format.i_fourcc )
+            switch( p_input->p_fmt->i_fourcc )
             {
                 case VLC_FOURCC( 'm', 'p','g', 'v' ):
                     p_stream->i_stream_type = 0x02;
@@ -269,38 +267,28 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
                     return( -1 );
             }
             p_sys->i_video_bound++;
-            p_bih = (BITMAPINFOHEADER*)p_input->input_format.p_format;
-            if( p_bih )
-            {
-                p_stream->i_bih_codec = p_input->input_format.i_fourcc;
-                p_stream->i_bih_width = p_bih->biWidth;
-                p_stream->i_bih_height = p_bih->biHeight;
-            }
-            else
-            {
-                p_stream->i_bih_codec = 0x0;
-                p_stream->i_bih_width = 0;
-                p_stream->i_bih_height = 0;
-            }
 
-            if( p_bih && p_bih->biSize > sizeof( BITMAPINFOHEADER ) )
+            p_stream->i_bih_codec  = p_input->p_fmt->i_fourcc;
+            p_stream->i_bih_width  = p_input->p_fmt->i_width;
+            p_stream->i_bih_height = p_input->p_fmt->i_height;
+
+            p_stream->i_decoder_specific_info_len = p_input->p_fmt->i_extra_data;
+            if( p_stream->i_decoder_specific_info_len > 0 )
             {
-                p_stream->i_decoder_specific_info_len =
-                    p_bih->biSize - sizeof( BITMAPINFOHEADER );
                 p_stream->p_decoder_specific_info =
                     malloc( p_stream->i_decoder_specific_info_len );
                 memcpy( p_stream->p_decoder_specific_info,
-                        &p_bih[1],
-                        p_stream->i_decoder_specific_info_len );
+                        p_input->p_fmt->p_extra_data,
+                        p_input->p_fmt->i_extra_data );
             }
             else
             {
                 p_stream->p_decoder_specific_info = NULL;
-                p_stream->i_decoder_specific_info_len = 0;
             }
             break;
+
         case AUDIO_ES:
-            switch( p_input->input_format.i_fourcc )
+            switch( p_input->p_fmt->i_fourcc )
             {
                 case VLC_FOURCC( 'a', '5','2', ' ' ):
                 case VLC_FOURCC( 'a', '5','2', 'b' ):
@@ -324,20 +312,19 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
                     return( -1 );
             }
             p_sys->i_audio_bound++;
-            p_wf = (WAVEFORMATEX*)p_input->input_format.p_format;
-            if( p_wf && p_wf->cbSize > 0 )
+
+            p_stream->i_decoder_specific_info_len = p_input->p_fmt->i_extra_data;
+            if( p_stream->i_decoder_specific_info_len > 0 )
             {
-                p_stream->i_decoder_specific_info_len = p_wf->cbSize;
                 p_stream->p_decoder_specific_info =
                     malloc( p_stream->i_decoder_specific_info_len );
                 memcpy( p_stream->p_decoder_specific_info,
-                        &p_wf[1],
-                        p_stream->i_decoder_specific_info_len );
+                        p_input->p_fmt->p_extra_data,
+                        p_input->p_fmt->i_extra_data );
             }
             else
             {
                 p_stream->p_decoder_specific_info = NULL;
-                p_stream->i_decoder_specific_info_len = 0;
             }
             break;
         default:
index 08607be..ca48bbd 100644 (file)
@@ -2,7 +2,7 @@
  * ogg.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: ogg.c,v 1.4 2003/03/31 03:46:11 fenrir Exp $
+ * $Id: ogg.c,v 1.5 2003/04/13 20:00:21 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
@@ -209,33 +209,29 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
     sout_mux_sys_t  *p_sys = p_mux->p_sys;
     ogg_stream_t        *p_stream;
 
-    BITMAPINFOHEADER    *p_bih;
-    WAVEFORMATEX        *p_wf;
-
     msg_Dbg( p_mux, "adding input" );
     p_input->p_sys = (void*)p_stream = malloc( sizeof( ogg_stream_t ) );
 
-    p_stream->i_cat       = p_input->input_format.i_cat;
-    p_stream->i_fourcc    = p_input->input_format.i_fourcc;
+    p_stream->i_cat       = p_input->p_fmt->i_cat;
+    p_stream->i_fourcc    = p_input->p_fmt->i_fourcc;
     p_stream->i_packet_no = 0;
 
     p_stream->header.i_packet_type = PACKET_TYPE_HEADER;
-    switch( p_input->input_format.i_cat )
+    switch( p_input->p_fmt->i_cat )
     {
         case VIDEO_ES:
-            p_bih = (BITMAPINFOHEADER*)p_input->input_format.p_format;
-            switch( p_input->input_format.i_fourcc )
+            switch( p_input->p_fmt->i_fourcc )
             {
                 case VLC_FOURCC( 'm', 'p','4', 'v' ):
                 case VLC_FOURCC( 'D', 'I','V', '3' ):
                     memcpy( p_stream->header.stream_type,
                             "video    ",
                             8 );
-                    if( p_input->input_format.i_fourcc == VLC_FOURCC( 'm', 'p','4', 'v' ) )
+                    if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'm', 'p','4', 'v' ) )
                     {
                         memcpy( p_stream->header.sub_type, "XVID", 4 );
                     }
-                    else if( p_input->input_format.i_fourcc == VLC_FOURCC( 'D', 'I','V', '3' ) )
+                    else if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'D', 'I','V', '3' ) )
                     {
                         memcpy( p_stream->header.sub_type, "DIV3", 4 );
                     }
@@ -246,16 +242,8 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
                     SetDWLE( &p_stream->header.i_default_len, 0 );      /* ??? */
                     SetDWLE( &p_stream->header.i_buffer_size, 1024*1024 );
                     SetWLE( &p_stream->header.i_bits_per_sample, 0 );
-                    if( p_bih )
-                    {
-                        SetDWLE( &p_stream->header.header.video.i_width, p_bih->biWidth );
-                        SetDWLE( &p_stream->header.header.video.i_height, p_bih->biHeight );
-                    }
-                    else
-                    {
-                        SetDWLE( &p_stream->header.header.video.i_width,  0 );
-                        SetDWLE( &p_stream->header.header.video.i_height, 0 );
-                    }
+                    SetDWLE( &p_stream->header.header.video.i_width,  p_input->p_fmt->i_width );
+                    SetDWLE( &p_stream->header.header.video.i_height, p_input->p_fmt->i_height );
                     break;
                 default:
                     FREE( p_input->p_sys );
@@ -263,19 +251,18 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
             }
             break;
         case AUDIO_ES:
-            p_wf = (WAVEFORMATEX*)p_input->input_format.p_format;
-            switch( p_input->input_format.i_fourcc )
+            switch( p_input->p_fmt->i_fourcc )
             {
                 case VLC_FOURCC( 'm', 'p','g', 'a' ):
                 case VLC_FOURCC( 'a', '5','2', ' ' ):
                     memcpy( p_stream->header.stream_type,
                             "audio    ",
                             8 );
-                    if( p_input->input_format.i_fourcc == VLC_FOURCC( 'm', 'p','g', 'a' ) )
+                    if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'm', 'p','g', 'a' ) )
                     {
                         memcpy( p_stream->header.sub_type, "55  ", 4 );
                     }
-                    else if( p_input->input_format.i_fourcc == VLC_FOURCC( 'a', '5','2', ' ' ) )
+                    else if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'a', '5','2', ' ' ) )
                     {
                         memcpy( p_stream->header.sub_type, "2000", 4 );
                     }
@@ -283,23 +270,11 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
                     SetQWLE( &p_stream->header.i_time_unit, 1000000 );  /* is it used ? */
                     SetDWLE( &p_stream->header.i_default_len, 0 );      /* ??? */
                     SetDWLE( &p_stream->header.i_buffer_size, 30*1024 );
-                    if( p_wf )
-                    {
-                        SetQWLE( &p_stream->header.i_samples_per_unit, p_wf->nSamplesPerSec );
-                        SetWLE( &p_stream->header.i_bits_per_sample, p_wf->wBitsPerSample );
-                        SetDWLE( &p_stream->header.header.audio.i_channels, p_wf->nChannels );
-                        SetDWLE( &p_stream->header.header.audio.i_block_align, p_wf->nBlockAlign );
-                        SetDWLE( &p_stream->header.header.audio.i_avgbytespersec, p_wf->nAvgBytesPerSec );
-                    }
-                    else
-                    {
-                        /* perhaps it's better to fail */
-                        SetQWLE( &p_stream->header.i_samples_per_unit, 44100 );
-                        SetWLE( &p_stream->header.i_bits_per_sample, 0 );
-                        SetDWLE( &p_stream->header.header.audio.i_channels, 2 );
-                        SetDWLE( &p_stream->header.header.audio.i_block_align, 0 );
-                        SetDWLE( &p_stream->header.header.audio.i_avgbytespersec, 0 );
-                    }
+                    SetQWLE( &p_stream->header.i_samples_per_unit, p_input->p_fmt->i_sample_rate );
+                    SetWLE( &p_stream->header.i_bits_per_sample, 0 );
+                    SetDWLE( &p_stream->header.header.audio.i_channels, p_input->p_fmt->i_channels );
+                    SetDWLE( &p_stream->header.header.audio.i_block_align, p_input->p_fmt->i_block_align );
+                    SetDWLE( &p_stream->header.header.audio.i_avgbytespersec, 0 );
                     break;
                 case VLC_FOURCC( 'v', 'o', 'r', 'b' ):
                 default:
index 11cbded..5e82503 100644 (file)
@@ -2,7 +2,7 @@
  * a52.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: a52.c,v 1.3 2003/03/31 03:46:11 fenrir Exp $
+ * $Id: a52.c,v 1.4 2003/04/13 20:00:21 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Eric Petit <titer@videolan.org>
@@ -45,7 +45,7 @@ typedef struct packetizer_s
 
     /* Output properties */
     sout_packetizer_input_t *p_sout_input;
-    sout_packet_format_t    output_format;
+    sout_format_t           output_format;
 
     uint64_t                i_samplescount;
 
@@ -155,8 +155,6 @@ static int InitThread( packetizer_t *p_pack )
     p_pack->output_format.i_cat = AUDIO_ES;
     p_pack->output_format.i_fourcc = VLC_FOURCC( 'a', '5', '2', ' ' );
 
-    p_pack->output_format.p_format = NULL;
-
     p_pack->p_sout_input   = NULL;
 
     p_pack->i_samplescount = 0;
@@ -230,19 +228,12 @@ static void PacketizeThread( packetizer_t *p_pack )
 
     if( !p_pack->p_sout_input )
     {
-        /* add a input for the stream ouput */
-        WAVEFORMATEX    *p_wf;
-
-        p_wf = malloc( sizeof( WAVEFORMATEX ) );
-        p_pack->output_format.p_format = (void*)p_wf;
-
-        p_wf->wFormatTag        = WAVE_FORMAT_A52;
-        p_wf->nChannels         = i_channels;
-        p_wf->nSamplesPerSec    = i_samplerate;
-        p_wf->nAvgBytesPerSec   = 0;
-        p_wf->nBlockAlign       = 1;
-        p_wf->wBitsPerSample    = 0;
-        p_wf->cbSize            = 0;
+        p_pack->output_format.i_sample_rate = i_samplerate;
+        p_pack->output_format.i_channels    = i_channels;
+        p_pack->output_format.i_block_align = 0;
+        p_pack->output_format.i_bitrate     = 0;
+        p_pack->output_format.i_extra_data  = 0;
+        p_pack->output_format.p_extra_data  = NULL;
 
         p_pack->p_sout_input =
             sout_InputNew( p_pack->p_fifo,
index e302640..197d34a 100644 (file)
@@ -2,7 +2,7 @@
  * copy.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: copy.c,v 1.6 2003/03/31 03:46:11 fenrir Exp $
+ * $Id: copy.c,v 1.7 2003/04/13 20:00:21 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Eric Petit <titer@videolan.org>
@@ -45,7 +45,7 @@ typedef struct packetizer_thread_s
 
     /* Output properties */
     sout_packetizer_input_t *p_sout_input;
-    sout_packet_format_t    output_format;
+    sout_format_t           output_format;
 
 //    mtime_t i_last_pts;
 
@@ -243,11 +243,26 @@ static int InitThread( packetizer_thread_t *p_pack )
             p_pack->output_format.i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'l' );
             p_pack->output_format.i_cat = VIDEO_ES;
             break;
+        case VLC_FOURCC( 'S', 'V', 'Q', '1' ):
+            p_pack->output_format.i_fourcc = VLC_FOURCC( 'S', 'V', 'Q', '1' );
+            p_pack->output_format.i_cat = VIDEO_ES;
+            break;
 
-        default:
-            p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc;
-            p_pack->output_format.i_cat = UNKNOWN_ES;
+        case VLC_FOURCC( 'w', 'm', 'a', '1' ):
+            p_pack->output_format.i_fourcc = VLC_FOURCC( 'w', 'm', 'a', '1' );
+            p_pack->output_format.i_cat = AUDIO_ES;
+            break;
+        case VLC_FOURCC( 'w', 'm', 'a', '2' ):
+            p_pack->output_format.i_fourcc = VLC_FOURCC( 'w', 'm', 'a', '2' );
+            p_pack->output_format.i_cat = AUDIO_ES;
             break;
+
+        default:
+            msg_Err( p_pack->p_fifo, "unknown es type !!" );
+            return VLC_EGENERIC;
+            //p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc;
+            //p_pack->output_format.i_cat = UNKNOWN_ES;
+            //break;
     }
 
     switch( p_pack->output_format.i_cat )
@@ -257,12 +272,32 @@ static int InitThread( packetizer_thread_t *p_pack )
                 WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_pack->p_fifo->p_waveformatex;
                 if( p_wf )
                 {
-                    p_pack->output_format.p_format = malloc( sizeof( WAVEFORMATEX ) + p_wf->cbSize );
-                    memcpy( p_pack->output_format.p_format, p_wf, sizeof( WAVEFORMATEX ) + p_wf->cbSize );
+                    p_pack->output_format.i_sample_rate = p_wf->nSamplesPerSec;
+                    p_pack->output_format.i_channels    = p_wf->nChannels;
+                    p_pack->output_format.i_block_align = p_wf->nBlockAlign;
+                    p_pack->output_format.i_bitrate     = p_wf->nAvgBytesPerSec * 8;
+                    p_pack->output_format.i_extra_data  = p_wf->cbSize;
+                    if( p_wf->cbSize  > 0 )
+                    {
+                        p_pack->output_format.p_extra_data =
+                            malloc( p_pack->output_format.i_extra_data );
+                        memcpy( p_pack->output_format.p_extra_data,
+                                &p_wf[1],
+                                p_pack->output_format.i_extra_data );
+                    }
+                    else
+                    {
+                        p_pack->output_format.p_extra_data = NULL;
+                    }
                 }
                 else
                 {
-                    p_pack->output_format.p_format = NULL;
+                    p_pack->output_format.i_sample_rate = 0;
+                    p_pack->output_format.i_channels    = 0;
+                    p_pack->output_format.i_block_align = 0;
+                    p_pack->output_format.i_bitrate     = 0;
+                    p_pack->output_format.i_extra_data  = 0;
+                    p_pack->output_format.p_extra_data  = NULL;
                 }
             }
             break;
@@ -270,29 +305,34 @@ static int InitThread( packetizer_thread_t *p_pack )
         case VIDEO_ES:
             {
                 BITMAPINFOHEADER *p_bih = (BITMAPINFOHEADER*)p_pack->p_fifo->p_bitmapinfoheader;
+
+                p_pack->output_format.i_bitrate = 0;
                 if( p_bih )
                 {
-                    p_pack->output_format.p_format = malloc( p_bih->biSize );
-                    memcpy( p_pack->output_format.p_format, p_bih, p_bih->biSize );
-                    if( p_pack->output_format.i_fourcc == VLC_FOURCC( 'm', 'p', '4', 'v' ) )
-                    {
-                        p_bih->biCompression = VLC_FOURCC( 'd', 'i', 'v', 'x' );
-                    }
-                    else
+                    p_pack->output_format.i_width  = p_bih->biWidth;
+                    p_pack->output_format.i_height = p_bih->biHeight;
+                    p_pack->output_format.i_extra_data  = p_bih->biSize - sizeof( BITMAPINFOHEADER );
+                    if( p_pack->output_format.i_extra_data > 0 )
                     {
-                        p_bih->biCompression = p_pack->output_format.i_fourcc;
+                        p_pack->output_format.p_extra_data =
+                            malloc( p_pack->output_format.i_extra_data );
+                        memcpy( p_pack->output_format.p_extra_data,
+                                &p_bih[1],
+                                p_pack->output_format.i_extra_data );
                     }
-
                 }
                 else
                 {
-                    p_pack->output_format.p_format = NULL;
+                    p_pack->output_format.i_width  = 0;
+                    p_pack->output_format.i_height = 0;
+                    p_pack->output_format.i_extra_data  = 0;
+                    p_pack->output_format.p_extra_data  = NULL;
                 }
             }
             break;
+
         default:
-            p_pack->output_format.p_format = NULL;
-            break;
+            return VLC_EGENERIC;
     }
 
     p_pack->p_sout_input =
@@ -302,10 +342,10 @@ static int InitThread( packetizer_thread_t *p_pack )
     if( !p_pack->p_sout_input )
     {
         msg_Err( p_pack->p_fifo, "cannot add a new stream" );
-        return( -1 );
+        return VLC_EGENERIC;
     }
 //    p_pack->i_last_pts = 0;
-    return( 0 );
+    return( VLC_SUCCESS );
 }
 
 /*****************************************************************************
@@ -329,7 +369,7 @@ static void PacketizeThread( packetizer_thread_t *p_pack )
 
     if( i_pts <= 0 ) //&& p_pack->i_last_pts <= 0 )
     {
-        msg_Err( p_pack->p_fifo, "need pts != 0" );
+        msg_Dbg( p_pack->p_fifo, "need pts != 0" );
         input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
         return;
     }
index 3177d38..981e1b1 100644 (file)
@@ -2,7 +2,7 @@
  * mpeg4audio.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: mpeg4audio.c,v 1.4 2003/03/31 03:46:11 fenrir Exp $
+ * $Id: mpeg4audio.c,v 1.5 2003/04/13 20:00:21 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
@@ -60,7 +60,7 @@ typedef struct packetizer_thread_s
 
     /* Output properties */
     sout_packetizer_input_t *p_sout_input;
-    sout_packet_format_t    output_format;
+    sout_format_t           output_format;
 
 //    mtime_t                 i_pts_start;
     mtime_t                 i_last_pts;
@@ -187,17 +187,8 @@ static int InitThread( packetizer_thread_t *p_pack )
     if( p_wf && p_wf->cbSize > 0)
     {
         uint8_t *p_config = (uint8_t*)&p_wf[1];
-        int i_wf = sizeof( WAVEFORMATEX ) + p_wf->cbSize;
-        int i_index;
+        int     i_index;
 
-
-        p_pack->p_wf = malloc( i_wf );
-        memcpy( p_pack->p_wf,
-                p_wf,
-                i_wf );
-        p_pack->output_format.i_cat = AUDIO_ES;
-        p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'a' );
-        p_pack->output_format.p_format = p_pack->p_wf;
         p_pack->b_adts = 0;
 
         i_index = ( ( p_config[0] << 1 ) | ( p_config[1] >> 7 ) )&0x0f;
@@ -216,6 +207,19 @@ static int InitThread( packetizer_thread_t *p_pack )
                  "aac %dHz %d samples/frame",
                  p_pack->i_sample_rate,
                  p_pack->i_frame_size );
+
+        p_pack->output_format.i_cat = AUDIO_ES;
+        p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'a' );
+        p_pack->output_format.i_sample_rate = p_pack->i_sample_rate;
+        p_pack->output_format.i_channels    = p_wf->nChannels;
+        p_pack->output_format.i_block_align = 0;
+        p_pack->output_format.i_bitrate     = 0;
+
+        p_pack->output_format.i_extra_data = p_wf->cbSize;
+        p_pack->output_format.p_extra_data = malloc( p_wf->cbSize );
+        memcpy( p_pack->output_format.p_extra_data,
+                &p_wf[1],
+                p_wf->cbSize );
     }
     else
     {
index 008d07b..58bc86f 100644 (file)
@@ -2,7 +2,7 @@
  * mpeg4video.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: mpeg4video.c,v 1.9 2003/03/31 03:46:11 fenrir Exp $
+ * $Id: mpeg4video.c,v 1.10 2003/04/13 20:00:21 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Eric Petit <titer@videolan.org>
@@ -46,7 +46,7 @@ typedef struct packetizer_thread_s
 
     /* Output properties */
     sout_packetizer_input_t *p_sout_input;
-    sout_packet_format_t    output_format;
+    sout_format_t           output_format;
 
     mtime_t                 i_last_pts;
 
@@ -198,8 +198,15 @@ static int InitThread( packetizer_thread_t *p_pack )
         /* create stream input output */
         p_pack->output_format.i_cat = VIDEO_ES;
         p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v' );
-        p_pack->output_format.p_format = malloc( p_bih->biSize );
-        memcpy( p_pack->output_format.p_format, p_bih, p_bih->biSize );
+        p_pack->output_format.i_width  = p_bih->biWidth;
+        p_pack->output_format.i_height = p_bih->biHeight;
+        p_pack->output_format.i_bitrate= 0;
+
+        p_pack->output_format.i_extra_data = p_pack->i_vol;
+        p_pack->output_format.p_extra_data = malloc( p_pack->i_vol );
+        memcpy( p_pack->output_format.p_extra_data,
+                p_pack->p_vol,
+                p_pack->i_vol );
 
         msg_Warn( p_pack->p_fifo, "opening with vol size:%d", p_pack->i_vol );
         p_pack->p_sout_input =
@@ -212,7 +219,11 @@ static int InitThread( packetizer_thread_t *p_pack )
         p_pack->p_vol = 0;
         p_pack->output_format.i_cat = UNKNOWN_ES;
         p_pack->output_format.i_fourcc = VLC_FOURCC( 'n', 'u', 'l', 'l' );
-        p_pack->output_format.p_format = NULL;
+        p_pack->output_format.i_width  = 0;
+        p_pack->output_format.i_height = 0;
+        p_pack->output_format.i_bitrate= 0;
+        p_pack->output_format.i_extra_data = 0;
+        p_pack->output_format.p_extra_data = NULL;
 
         p_pack->p_sout_input =
             sout_InputNew( p_pack->p_fifo,
@@ -260,12 +271,14 @@ static void PacketizeThread( packetizer_thread_t *p_pack )
     }
 
     i_pts = p_pes->i_pts;
+#if 0
     if( i_pts <= 0 && p_pack->i_last_pts <= 0 )
     {
-        msg_Err( p_pack->p_fifo, "need a starting pts" );
+        msg_Dbg( p_pack->p_fifo, "need a starting pts" );
         input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
         return;
     }
+#endif
 
     i_size = p_pes->i_pes_size;
     if( i_size > 0 )
@@ -364,8 +377,6 @@ static void PacketizeThread( packetizer_thread_t *p_pack )
 
                 if( p_vol_end != NULL && p_vol_begin < p_vol_end )
                 {
-                    BITMAPINFOHEADER *p_bih;
-
                     p_pack->i_vol = p_vol_end - p_vol_begin;
                     msg_Dbg( p_pack->p_fifo, "Reopening output" );
 
@@ -376,21 +387,16 @@ static void PacketizeThread( packetizer_thread_t *p_pack )
 
                     p_pack->output_format.i_cat = VIDEO_ES;
                     p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v' );
-                    p_pack->output_format.p_format =
-                        (void*)p_bih = malloc( sizeof( BITMAPINFOHEADER ) + p_pack->i_vol);
-
-                    p_bih->biSize = sizeof( BITMAPINFOHEADER ) + p_pack->i_vol;
-                    p_bih->biWidth  = 0;
-                    p_bih->biHeight = 0;
-                    p_bih->biPlanes = 1;
-                    p_bih->biBitCount = 24;
-                    p_bih->biCompression = VLC_FOURCC( 'd', 'i', 'v', 'x' );
-                    p_bih->biSizeImage = 0;
-                    p_bih->biXPelsPerMeter = 0;
-                    p_bih->biYPelsPerMeter = 0;
-                    p_bih->biClrUsed = 0;
-                    p_bih->biClrImportant = 0;
-                    memcpy( &p_bih[1], p_pack->p_vol, p_pack->i_vol );
+
+                    p_pack->output_format.i_width  = 0;
+                    p_pack->output_format.i_height = 0;
+                    p_pack->output_format.i_bitrate= 0;
+
+                    p_pack->output_format.i_extra_data = p_pack->i_vol;
+                    p_pack->output_format.p_extra_data = malloc( p_pack->i_vol );
+                    memcpy( p_pack->output_format.p_extra_data,
+                            p_pack->p_vol,
+                            p_pack->i_vol );
 
                     p_pack->p_sout_input =
                         sout_InputNew( p_pack->p_fifo,
@@ -410,8 +416,16 @@ static void PacketizeThread( packetizer_thread_t *p_pack )
             }
         }
 
-        sout_InputSendBuffer( p_pack->p_sout_input,
+        if( i_pts > 0 )
+        {
+            sout_InputSendBuffer( p_pack->p_sout_input,
+                                  p_sout_buffer );
+        }
+        else
+        {
+            sout_BufferDelete( p_pack->p_sout_input->p_sout,
                                p_sout_buffer );
+        }
     }
 
     input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
index faaa191..ee95286 100644 (file)
@@ -2,7 +2,7 @@
  * mpegaudio.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: mpegaudio.c,v 1.5 2003/03/31 03:46:11 fenrir Exp $
+ * $Id: mpegaudio.c,v 1.6 2003/04/13 20:00:21 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Eric Petit <titer@videolan.org>
@@ -45,7 +45,7 @@ typedef struct packetizer_s
 
     /* Output properties */
     sout_packetizer_input_t *p_sout_input;
-    sout_packet_format_t    output_format;
+    sout_format_t           output_format;
 
     uint64_t                i_samplescount;
     uint32_t                i_samplespersecond;
@@ -180,8 +180,13 @@ static int InitThread( packetizer_t *p_pack )
 
     p_pack->output_format.i_cat = AUDIO_ES;
     p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc;
+    p_pack->output_format.i_sample_rate = 0;
+    p_pack->output_format.i_channels    = 0;
+    p_pack->output_format.i_block_align = 0;
+    p_pack->output_format.i_bitrate     = 0;
+    p_pack->output_format.i_extra_data  = 0;
+    p_pack->output_format.p_extra_data  = NULL;
 
-    p_pack->output_format.p_format = NULL;
 
     p_pack->p_sout_input = NULL;
 
@@ -301,18 +306,10 @@ static void PacketizeThread( packetizer_t *p_pack )
     if( !p_pack->p_sout_input )
     {
         /* add a input for the stream ouput */
-        WAVEFORMATEX    *p_wf;
-
-        p_wf = malloc( sizeof( WAVEFORMATEX ) );
-        p_pack->output_format.p_format = (void*)p_wf;
-
-        p_wf->wFormatTag        = WAVE_FORMAT_MPEG;
-        p_wf->nChannels         = i_channels;
-        p_wf->nSamplesPerSec    = i_samplerate;
-        p_wf->nAvgBytesPerSec   = 0;
-        p_wf->nBlockAlign       = 1;
-        p_wf->wBitsPerSample    = 0;
-        p_wf->cbSize            = 0; // FIXME there are more field for mpegaudio
+        p_pack->output_format.i_sample_rate = i_samplerate;
+        p_pack->output_format.i_channels    = i_channels;
+        p_pack->output_format.i_block_align = 1;
+        p_pack->output_format.i_bitrate     = 0;
 
         p_pack->p_sout_input =
             sout_InputNew( p_pack->p_fifo,
index 8e3a6ec..dac33d8 100644 (file)
@@ -2,7 +2,7 @@
  * mpegvideo.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: mpegvideo.c,v 1.11 2003/03/31 03:46:11 fenrir Exp $
+ * $Id: mpegvideo.c,v 1.12 2003/04/13 20:00:21 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Eric Petit <titer@videolan.org>
@@ -45,7 +45,7 @@ typedef struct packetizer_s
 
     /* Output properties */
     sout_packetizer_input_t *p_sout_input;
-    sout_packet_format_t    output_format;
+    sout_format_t           output_format;
 
     mtime_t                 i_last_dts;
     mtime_t                 i_last_ref_pts;
@@ -157,6 +157,11 @@ static int InitThread( packetizer_t *p_pack )
 
     p_pack->output_format.i_cat = VIDEO_ES;
     p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'v');
+    p_pack->output_format.i_width  = 0;
+    p_pack->output_format.i_height = 0;
+    p_pack->output_format.i_bitrate= 0;
+    p_pack->output_format.i_extra_data = 0;
+    p_pack->output_format.p_extra_data = NULL;
 
     p_pack->p_sout_input = NULL;
 
@@ -228,10 +233,7 @@ static void PacketizeThread( packetizer_t *p_pack )
         byte_t p_temp[512];/* 150 bytes is the maximal size
                                of a sequence_header + sequence_extension */
         int i_frame_rate_code;
-        BITMAPINFOHEADER *p_bih;
 
-        p_bih = malloc( sizeof( BITMAPINFOHEADER ) );
-        p_pack->output_format.p_format = (void*)p_bih;
 
         /* skip data until we find a sequence_header_code */
         /* TODO: store skipped somewhere so can send it to the mux
@@ -250,21 +252,12 @@ static void PacketizeThread( packetizer_t *p_pack )
         i_pos = 0;
         GetChunk( &p_pack->bit_stream, p_temp, 4 ); i_pos += 4;
 
-        p_bih->biSize = sizeof( BITMAPINFOHEADER );
         /* horizontal_size_value */
-        p_bih->biWidth = ShowBits( &p_pack->bit_stream, 12 );
+        p_pack->output_format.i_width = ShowBits( &p_pack->bit_stream, 12 );
         /* vertical_size_value */
-        p_bih->biHeight = ShowBits( &p_pack->bit_stream, 24 ) & 0xFFF;
+        p_pack->output_format.i_height= ShowBits( &p_pack->bit_stream, 24 ) & 0xFFF;
         /* frame_rate_code */
         i_frame_rate_code = ShowBits( &p_pack->bit_stream, 32 ) & 0xF;
-        p_bih->biPlanes = 1;
-        p_bih->biBitCount = 0;
-        p_bih->biCompression = VLC_FOURCC( 'm', 'p', 'g', '2' );
-        p_bih->biSizeImage = 0;
-        p_bih->biXPelsPerMeter = 0;
-        p_bih->biYPelsPerMeter = 0;
-        p_bih->biClrUsed = 0;
-        p_bih->biClrImportant = 0;
 
         /* copy headers */
         GetChunk( &p_pack->bit_stream, p_temp + i_pos, 7 ); i_pos += 7;
@@ -313,7 +306,9 @@ static void PacketizeThread( packetizer_t *p_pack )
 
         msg_Warn( p_pack->p_fifo,
                   "creating input (image size %dx%d, frame rate %.2f)",
-                  p_bih->biWidth, p_bih->biHeight, p_pack->d_frame_rate );
+                  p_pack->output_format.i_width,
+                  p_pack->output_format.i_height,
+                  p_pack->d_frame_rate );
 
         /* now we have informations to create the input */
         p_pack->p_sout_input = sout_InputNew( p_pack->p_fifo,
@@ -365,7 +360,8 @@ static void PacketizeThread( packetizer_t *p_pack )
             }
 
             p_pack->i_last_ref_pts =
-                   p_pack->i_last_dts + 40000; /* FIXME */
+                   p_pack->i_last_dts +
+                        (mtime_t)( 1000000 / p_pack->d_frame_rate); /* FIXME */
             CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos );
         }
         else if( i_code == 0x100 ) /* Picture */
@@ -437,16 +433,21 @@ static void PacketizeThread( packetizer_t *p_pack )
         return;
     }
 
+#if 1
     if( i_dts > 0 )
     {
-        p_pack->i_last_dts = i_dts;
-    }
-    if( i_pts > 0 )
-    {
-        p_pack->i_last_ref_pts =
-            i_pts - i_temporal_ref *
-                    (mtime_t)( 1000000 / p_pack->d_frame_rate );
+        //if( i_dts - p_pack->i_last_dts > 200000 ||
+        //    i_dts - p_pack->i_last_dts < 200000 )
+        {
+            p_pack->i_last_dts = i_dts;
+            if( i_pts > 0 )
+            {
+                p_pack->i_last_ref_pts = i_pts -
+                    i_temporal_ref * (mtime_t)( 1000000 / p_pack->d_frame_rate );
+            }
+        }
     }
+#endif
 
     p_sout_buffer->i_dts = p_pack->i_last_dts;
     p_sout_buffer->i_pts = p_pack->i_last_ref_pts + 
diff --git a/modules/stream_out/Modules.am b/modules/stream_out/Modules.am
new file mode 100644 (file)
index 0000000..8c0464f
--- /dev/null
@@ -0,0 +1,6 @@
+SOURCES_stream_out_dummy = modules/stream_out/dummy.c
+SOURCES_stream_out_standard = modules/stream_out/standard.c
+SOURCES_stream_out_transcode = modules/stream_out/transcode.c
+SOURCES_stream_out_duplicate = modules/stream_out/duplicate.c
+SOURCES_stream_out_es = modules/stream_out/es.c
+SOURCES_stream_out_display = modules/stream_out/display.c
diff --git a/modules/stream_out/display.c b/modules/stream_out/display.c
new file mode 100644 (file)
index 0000000..edd9948
--- /dev/null
@@ -0,0 +1,285 @@
+/*****************************************************************************
+ * display.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: display.c,v 1.1 2003/04/13 20:00:21 fenrir Exp $
+ *
+ * Authors: 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 <string.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#include "codecs.h"
+
+/*****************************************************************************
+ * Exported prototypes
+ *****************************************************************************/
+static int      Open    ( vlc_object_t * );
+static void     Close   ( vlc_object_t * );
+
+static sout_stream_id_t *Add ( sout_stream_t *, sout_format_t * );
+static int               Del ( sout_stream_t *, sout_stream_id_t * );
+static int               Send( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("Display stream") );
+    set_capability( "sout stream", 50 );
+    add_shortcut( "display" );
+    set_callbacks( Open, Close );
+vlc_module_end();
+
+struct sout_stream_sys_t
+{
+    input_thread_t *p_input;
+
+    vlc_bool_t     b_audio;
+    vlc_bool_t     b_video;
+
+    mtime_t        i_delay;
+};
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    sout_stream_t     *p_stream = (sout_stream_t*)p_this;
+    sout_stream_sys_t *p_sys;
+    char              *val;
+    p_sys           = malloc( sizeof( sout_stream_sys_t ) );
+    p_sys->p_input  = vlc_object_find( p_stream, VLC_OBJECT_INPUT, FIND_ANYWHERE );
+    if( !p_sys->p_input )
+    {
+        msg_Err( p_stream, "cannot find p_input" );
+        free( p_sys );
+        return VLC_EGENERIC;
+    }
+
+    p_sys->b_audio = VLC_TRUE;
+    p_sys->b_video = VLC_TRUE;
+    p_sys->i_delay = 100*1000;
+    if( sout_cfg_find( p_stream->p_cfg, "noaudio" ) )
+    {
+        p_sys->b_audio = VLC_FALSE;
+    }
+    if( sout_cfg_find( p_stream->p_cfg, "novideo" ) )
+    {
+        p_sys->b_video = VLC_FALSE;
+    }
+    if( ( val = sout_cfg_find_value( p_stream->p_cfg, "delay" ) ) )
+    {
+        p_sys->i_delay = (mtime_t)atoi( val ) * (mtime_t)1000;
+    }
+
+    p_stream->pf_add    = Add;
+    p_stream->pf_del    = Del;
+    p_stream->pf_send   = Send;
+
+    p_stream->p_sys     = p_sys;
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close:
+ *****************************************************************************/
+
+static void Close( vlc_object_t * p_this )
+{
+    sout_stream_t     *p_stream = (sout_stream_t*)p_this;
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+
+    vlc_object_release( p_sys->p_input );
+
+    free( p_sys );
+}
+
+struct sout_stream_id_t
+{
+    es_descriptor_t *p_es;
+};
+
+
+static sout_stream_id_t * Add      ( sout_stream_t *p_stream, sout_format_t *p_fmt )
+{
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+    sout_stream_id_t *id;
+
+    if( ( p_fmt->i_cat == AUDIO_ES && !p_sys->b_audio )||
+        ( p_fmt->i_cat == VIDEO_ES && !p_sys->b_video ) )
+    {
+        return NULL;
+    }
+
+    id = malloc( sizeof( sout_stream_id_t ) );
+
+    vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
+    id->p_es = input_AddES( p_sys->p_input,
+                            NULL,           /* no program */
+                            12,             /* es_id */
+                            0 );            /* no extra data */
+
+    if( !id->p_es )
+    {
+        vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
+
+        msg_Err( p_stream, "cannot create es" );
+        free( id );
+        return NULL;
+    }
+    id->p_es->i_stream_id   = 1;
+    id->p_es->i_cat         = UNKNOWN_ES; //p_fmt->i_cat;
+    id->p_es->i_fourcc      = p_fmt->i_fourcc;
+    id->p_es->b_force_decoder = VLC_TRUE;
+    switch( p_fmt->i_cat )
+    {
+        case AUDIO_ES:
+            id->p_es->p_bitmapinfoheader = NULL;
+            id->p_es->p_waveformatex =
+                malloc( sizeof( WAVEFORMATEX ) + p_fmt->i_extra_data );
+#define p_wf    ((WAVEFORMATEX*)id->p_es->p_waveformatex)
+            p_wf->wFormatTag     = WAVE_FORMAT_UNKNOWN;
+            p_wf->nChannels      = p_fmt->i_channels;
+            p_wf->nSamplesPerSec = p_fmt->i_sample_rate;
+            p_wf->nAvgBytesPerSec= p_fmt->i_bitrate / 8;
+            p_wf->nBlockAlign    = p_fmt->i_block_align;
+            p_wf->wBitsPerSample = 0;
+            p_wf->cbSize         = p_fmt->i_extra_data;
+            if( p_fmt->i_extra_data > 0 )
+            {
+                memcpy( &p_wf[1],
+                        p_fmt->p_extra_data,
+                        p_fmt->i_extra_data );
+            }
+#undef p_wf
+            break;
+        case VIDEO_ES:
+            id->p_es->p_waveformatex = NULL;
+            id->p_es->p_bitmapinfoheader = malloc( sizeof( BITMAPINFOHEADER ) + p_fmt->i_extra_data );
+#define p_bih ((BITMAPINFOHEADER*)id->p_es->p_bitmapinfoheader)
+            p_bih->biSize   = sizeof( BITMAPINFOHEADER ) + p_fmt->i_extra_data;
+            p_bih->biWidth  = p_fmt->i_width;
+            p_bih->biHeight = p_fmt->i_height;
+            p_bih->biPlanes   = 0;
+            p_bih->biBitCount = 0;
+            p_bih->biCompression = 0;
+            p_bih->biSizeImage   = 0;
+            p_bih->biXPelsPerMeter = 0;
+            p_bih->biYPelsPerMeter = 0;
+            p_bih->biClrUsed       = 0;
+            p_bih->biClrImportant  = 0;
+            if( p_fmt->i_extra_data > 0 )
+            {
+                memcpy( &p_bih[1],
+                        p_fmt->p_extra_data,
+                        p_fmt->i_extra_data );
+            }
+#undef p_bih
+            break;
+        default:
+            msg_Err( p_stream, "unknown es type" );
+            free( id );
+            return NULL;
+    }
+
+    if( input_SelectES( p_sys->p_input, id->p_es ) )
+    {
+        input_DelES( p_sys->p_input, id->p_es );
+        vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
+
+        msg_Err( p_stream, "cannot select es" );
+        free( id );
+        return NULL;
+    }
+    vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
+
+    return id;
+}
+
+static int     Del      ( sout_stream_t *p_stream, sout_stream_id_t *id )
+{
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+
+    input_DelES( p_sys->p_input, id->p_es );
+
+    free( id );
+
+    return VLC_SUCCESS;
+}
+
+static int     Send     ( sout_stream_t *p_stream, sout_stream_id_t *id, sout_buffer_t *p_buffer )
+{
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+
+    while( p_buffer )
+    {
+        sout_buffer_t *p_next;
+        pes_packet_t *p_pes;
+        data_packet_t   *p_data;
+
+        if( p_buffer->i_size > 0 )
+        {
+            if( !( p_pes = input_NewPES( p_sys->p_input->p_method_data ) ) )
+            {
+                msg_Err( p_stream, "cannot allocate new PES" );
+                return VLC_EGENERIC;
+            }
+            if( !( p_data = input_NewPacket( p_sys->p_input->p_method_data, p_buffer->i_size ) ) )
+            {
+                msg_Err( p_stream, "cannot allocate new data_packet" );
+                return VLC_EGENERIC;
+            }
+            p_pes->i_dts = p_buffer->i_dts + p_sys->i_delay;
+            p_pes->i_pts = p_buffer->i_pts + p_sys->i_delay;
+            p_pes->p_first = p_pes->p_last = p_data;
+            p_pes->i_nb_data = 1;
+            p_pes->i_pes_size = p_buffer->i_size;
+
+            p_stream->p_vlc->pf_memcpy( p_data->p_payload_start,
+                                        p_buffer->p_buffer,
+                                        p_buffer->i_size );
+
+            if( id->p_es->p_decoder_fifo )
+            {
+                input_DecodePES( id->p_es->p_decoder_fifo, p_pes );
+            }
+            else
+            {
+                input_DeletePES( p_sys->p_input->p_method_data, p_pes );
+            }
+        }
+
+        /* *** go to next buffer *** */
+        p_next = p_buffer->p_next;
+        sout_BufferDelete( p_stream->p_sout, p_buffer );
+        p_buffer = p_next;
+    }
+
+    return VLC_SUCCESS;
+}
+
diff --git a/modules/stream_out/dummy.c b/modules/stream_out/dummy.c
new file mode 100644 (file)
index 0000000..8b27502
--- /dev/null
@@ -0,0 +1,116 @@
+/*****************************************************************************
+ * dummy.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: dummy.c,v 1.1 2003/04/13 20:00:21 fenrir Exp $
+ *
+ * Authors: 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 <string.h>
+
+#include <vlc/vlc.h>
+#include <vlc/sout.h>
+
+/*****************************************************************************
+ * Exported prototypes
+ *****************************************************************************/
+static int      Open    ( vlc_object_t * );
+static void     Close   ( vlc_object_t * );
+
+static sout_stream_id_t *Add ( sout_stream_t *, sout_format_t * );
+static int               Del ( sout_stream_t *, sout_stream_id_t * );
+static int               Send( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("Dummy stream") );
+    set_capability( "sout stream", 50 );
+    add_shortcut( "dummy" );
+    set_callbacks( Open, Close );
+vlc_module_end();
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    sout_stream_t   *p_stream = (sout_stream_t*)p_this;
+
+    p_stream->pf_add    = Add;
+    p_stream->pf_del    = Del;
+    p_stream->pf_send   = Send;
+
+    p_stream->p_sys     = NULL;
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close:
+ *****************************************************************************/
+
+static void Close( vlc_object_t * p_this )
+{
+    sout_stream_t   *p_stream = (sout_stream_t*)p_this;
+
+}
+
+struct sout_stream_id_t
+{
+    int i_d_u_m_m_y;
+};
+
+
+static sout_stream_id_t * Add      ( sout_stream_t *p_stream, sout_format_t *p_fmt )
+{
+    sout_stream_id_t *id;
+
+    id = malloc( sizeof( sout_stream_id_t ) );
+    id->i_d_u_m_m_y = 0;
+
+    return id;
+}
+
+static int     Del      ( sout_stream_t *p_stream, sout_stream_id_t *id )
+{
+    free( id );
+
+    return VLC_SUCCESS;
+}
+
+static int     Send     ( sout_stream_t *p_stream, sout_stream_id_t *id, sout_buffer_t *p_buffer )
+{
+    sout_buffer_t *p_next;
+
+    while( p_buffer )
+    {
+        p_next = p_buffer->p_next;
+
+        sout_BufferDelete( p_stream->p_sout, p_buffer );
+        p_buffer = p_next;
+    }
+
+    return VLC_SUCCESS;
+}
+
diff --git a/modules/stream_out/duplicate.c b/modules/stream_out/duplicate.c
new file mode 100644 (file)
index 0000000..f74a355
--- /dev/null
@@ -0,0 +1,211 @@
+/*****************************************************************************
+ * duplicate.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: duplicate.c,v 1.1 2003/04/13 20:00:21 fenrir Exp $
+ *
+ * Authors: 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 <string.h>
+
+#include <vlc/vlc.h>
+#include <vlc/sout.h>
+
+/*****************************************************************************
+ * Exported prototypes
+ *****************************************************************************/
+static int      Open    ( vlc_object_t * );
+static void     Close   ( vlc_object_t * );
+
+static sout_stream_id_t *Add ( sout_stream_t *, sout_format_t * );
+static int               Del ( sout_stream_t *, sout_stream_id_t * );
+static int               Send( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("Duplicate stream") );
+    set_capability( "sout stream", 50 );
+    add_shortcut( "duplicate" );
+    add_shortcut( "dup" );
+    set_callbacks( Open, Close );
+vlc_module_end();
+
+
+struct sout_stream_sys_t
+{
+    int             i_nb_streams;
+    sout_stream_t   **pp_streams;
+};
+
+struct sout_stream_id_t
+{
+    int                 i_nb_ids;
+    void                **pp_ids;
+};
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    sout_stream_t     *p_stream = (sout_stream_t*)p_this;
+    sout_stream_sys_t *p_sys;
+    sout_cfg_t        *p_cfg;
+
+    msg_Dbg( p_stream, "creating a duplication" );
+
+    p_sys = malloc( sizeof( sout_stream_sys_t ) );
+    p_sys->i_nb_streams = 0;
+    p_sys->pp_streams   = NULL;
+
+    for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
+    {
+        if( !strncmp( p_cfg->psz_name, "dst", strlen( "dst" ) ) )
+        {
+            sout_stream_t *s;
+
+            msg_Dbg( p_stream, " * adding `%s'", p_cfg->psz_value );
+            s = sout_stream_new( p_stream->p_sout, p_cfg->psz_value );
+
+            TAB_APPEND( p_sys->i_nb_streams, p_sys->pp_streams, s );
+        }
+    }
+
+    if( p_sys->i_nb_streams == 0 )
+    {
+        msg_Err( p_stream, "no destination given" );
+        free( p_sys );
+
+        return VLC_EGENERIC;
+    }
+
+    p_stream->pf_add    = Add;
+    p_stream->pf_del    = Del;
+    p_stream->pf_send   = Send;
+
+    p_stream->p_sys     = p_sys;
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close:
+ *****************************************************************************/
+
+static void Close( vlc_object_t * p_this )
+{
+    sout_stream_t     *p_stream = (sout_stream_t*)p_this;
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+
+    int i;
+
+    msg_Dbg( p_stream, "closing a duplication" );
+    for( i = 0; i < p_sys->i_nb_streams; i++ )
+    {
+        sout_stream_delete( p_sys->pp_streams[i] );
+    }
+    free( p_sys->pp_streams );
+
+    free( p_sys );
+}
+
+
+
+static sout_stream_id_t * Add      ( sout_stream_t *p_stream, sout_format_t *p_fmt )
+{
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+    sout_stream_id_t  *id;
+    int               i_stream;
+
+    id = malloc( sizeof( sout_stream_id_t ) );
+    id->i_nb_ids = 0;
+    id->pp_ids   = NULL;
+
+    for( i_stream = 0; i_stream < p_sys->i_nb_streams; i_stream++ )
+    {
+        void *id_new;
+
+        /* XXX not the same sout_stream_id_t definition ... */
+        id_new = (void*)p_sys->pp_streams[i_stream]->pf_add( p_sys->pp_streams[i_stream], p_fmt );
+        TAB_APPEND( id->i_nb_ids, id->pp_ids, id_new );
+    }
+
+    if( id->i_nb_ids <= 0 )
+    {
+        free( id );
+        return NULL;
+    }
+
+    return id;
+}
+
+static int     Del      ( sout_stream_t *p_stream, sout_stream_id_t *id )
+{
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+    int               i_stream;
+
+    for( i_stream = 0; i_stream < p_sys->i_nb_streams; i_stream++ )
+    {
+        if( id->pp_ids[i_stream] )
+        {
+            p_sys->pp_streams[i_stream]->pf_del( p_sys->pp_streams[i_stream],
+                                                 id->pp_ids[i_stream] );
+        }
+    }
+
+    free( id->pp_ids );
+    free( id );
+    return VLC_SUCCESS;
+}
+
+static int     Send     ( sout_stream_t *p_stream, sout_stream_id_t *id, sout_buffer_t *p_buffer )
+{
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+    int               i_stream;
+
+    for( i_stream = 0; i_stream < p_sys->i_nb_streams - 1; i_stream++ )
+    {
+        sout_buffer_t *p_dup;
+
+        if( id->pp_ids[i_stream] )
+        {
+            p_dup = sout_BufferDuplicate( p_stream->p_sout, p_buffer );
+
+            p_sys->pp_streams[i_stream]->pf_send( p_sys->pp_streams[i_stream],
+                                                  id->pp_ids[i_stream],
+                                                  p_dup );
+        }
+    }
+
+    i_stream = p_sys->i_nb_streams - 1;
+    if( id->pp_ids[i_stream] )
+    {
+        p_sys->pp_streams[i_stream]->pf_send( p_sys->pp_streams[i_stream],
+                                              id->pp_ids[i_stream],
+                                              p_buffer);
+    }
+
+    return VLC_SUCCESS;
+}
+
diff --git a/modules/stream_out/es.c b/modules/stream_out/es.c
new file mode 100644 (file)
index 0000000..0ddac41
--- /dev/null
@@ -0,0 +1,326 @@
+/*****************************************************************************
+ * es.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: es.c,v 1.1 2003/04/13 20:00:21 fenrir Exp $
+ *
+ * Authors: 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 <string.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#define FREE( p ) if( p ) { free( p ); (p) = NULL; }
+/*****************************************************************************
+ * Exported prototypes
+ *****************************************************************************/
+static int      Open    ( vlc_object_t * );
+static void     Close   ( vlc_object_t * );
+
+static sout_stream_id_t *Add ( sout_stream_t *, sout_format_t * );
+static int               Del ( sout_stream_t *, sout_stream_id_t * );
+static int               Send( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("ES stream") );
+    set_capability( "sout stream", 50 );
+    add_shortcut( "es" );
+    add_shortcut( "es" );
+    set_callbacks( Open, Close );
+vlc_module_end();
+
+struct sout_stream_sys_t
+{
+    int  i_count_audio;
+    int  i_count_video;
+    int  i_count;
+
+    char *psz_mux;
+    char *psz_mux_audio;
+    char *psz_mux_video;
+
+    char *psz_access;
+    char *psz_access_audio;
+    char *psz_access_video;
+
+    char *psz_url;
+    char *psz_url_audio;
+    char *psz_url_video;
+};
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    sout_stream_t       *p_stream = (sout_stream_t*)p_this;
+    sout_stream_sys_t   *p_sys;
+
+    //p_sout->i_preheader = __MAX( p_sout->i_preheader, p_mux->i_preheader );
+
+    p_sys                   = malloc( sizeof( sout_stream_sys_t ) );
+
+    p_sys->i_count          = 0;
+    p_sys->i_count_audio    = 0;
+    p_sys->i_count_video    = 0;
+
+    p_sys->psz_access       = sout_cfg_find_value( p_stream->p_cfg, "access" );
+    p_sys->psz_access_audio = sout_cfg_find_value( p_stream->p_cfg, "acesss_audio" );
+    p_sys->psz_access_video = sout_cfg_find_value( p_stream->p_cfg, "access_video" );
+
+
+    p_sys->psz_mux          = sout_cfg_find_value( p_stream->p_cfg, "mux" );
+    p_sys->psz_mux_audio    = sout_cfg_find_value( p_stream->p_cfg, "mux_audio" );
+    p_sys->psz_mux_video    = sout_cfg_find_value( p_stream->p_cfg, "mux_video" );
+
+    p_sys->psz_url         = sout_cfg_find_value( p_stream->p_cfg, "url" );
+    p_sys->psz_url_audio   = sout_cfg_find_value( p_stream->p_cfg, "url_audio" );
+    p_sys->psz_url_video   = sout_cfg_find_value( p_stream->p_cfg, "url_video" );
+
+    p_stream->pf_add    = Add;
+    p_stream->pf_del    = Del;
+    p_stream->pf_send   = Send;
+
+    p_stream->p_sys     = p_sys;
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close:
+ *****************************************************************************/
+
+static void Close( vlc_object_t * p_this )
+{
+    sout_stream_t     *p_stream = (sout_stream_t*)p_this;
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+
+    free( p_sys );
+}
+
+struct sout_stream_id_t
+{
+    sout_input_t *p_input;
+    sout_mux_t   *p_mux;
+};
+
+static char * es_print_url( char *psz_fmt, vlc_fourcc_t i_fourcc, int i_count, char *psz_access, char *psz_mux )
+{
+    char *psz_url, *p;
+
+    if( psz_fmt == NULL || !*psz_fmt )
+    {
+        psz_fmt = "stream-%n-%c.%m";
+    }
+
+    p = psz_url = malloc( 4096 );
+    memset( p, 0, 4096 );
+    for( ;; )
+    {
+        if( *psz_fmt == '\0' )
+        {
+            *p = '\0';
+            break;
+        }
+
+        if( *psz_fmt != '%' )
+        {
+            *p++ = *psz_fmt++;
+        }
+        else
+        {
+            if( psz_fmt[1] == 'n' )
+            {
+                p += sprintf( p, "%d", i_count );
+            }
+            else if( psz_fmt[1] == 'c' )
+            {
+                p += sprintf( p, "%4.4s", (char*)&i_fourcc );
+            }
+            else if( psz_fmt[1] == 'm' )
+            {
+                p += sprintf( p, "%s", psz_mux );
+            }
+            else if( psz_fmt[1] == 'a' )
+            {
+                p += sprintf( p, "%s", psz_access );
+            }
+            else if( psz_fmt[1] != '\0' )
+            {
+                p += sprintf( p, "%c%c", psz_fmt[0], psz_fmt[1] );
+            }
+            else
+            {
+                p += sprintf( p, "%c", psz_fmt[0] );
+                *p++ = '\0';
+                break;
+            }
+            psz_fmt += 2;
+        }
+    }
+
+    return( psz_url );
+}
+
+static sout_stream_id_t * Add      ( sout_stream_t *p_stream, sout_format_t *p_fmt )
+{
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+    sout_instance_t   *p_sout = p_stream->p_sout;
+    sout_stream_id_t  *id;
+
+    char              *psz_access;
+    char              *psz_mux;
+    char              *psz_url;
+
+    sout_access_out_t *p_access;
+    sout_mux_t        *p_mux;
+
+    /* *** get access name *** */
+    if( p_fmt->i_cat == AUDIO_ES && p_sys->psz_access_audio )
+    {
+        psz_access = p_sys->psz_access_audio;
+    }
+    else if( p_fmt->i_cat == VIDEO_ES && p_sys->psz_access_video )
+    {
+        psz_access = p_sys->psz_access_video;
+    }
+    else
+    {
+        psz_access = p_sys->psz_access;
+    }
+
+    /* *** get mux name *** */
+    if( p_fmt->i_cat == AUDIO_ES && p_sys->psz_mux_audio )
+    {
+        psz_mux = p_sys->psz_mux_audio;
+    }
+    else if( p_fmt->i_cat == VIDEO_ES && p_sys->psz_mux_video )
+    {
+        psz_mux = p_sys->psz_mux_video;
+    }
+    else
+    {
+        psz_mux = p_sys->psz_mux;
+    }
+
+    /* *** get url (%d expanded as a codec count, %c expanded as codec fcc ) *** */
+    if( p_fmt->i_cat == AUDIO_ES && p_sys->psz_url_audio )
+    {
+        psz_url = es_print_url( p_sys->psz_url_audio, p_fmt->i_fourcc, p_sys->i_count_audio, psz_access, psz_mux );
+    }
+    else if( p_fmt->i_cat == VIDEO_ES && p_sys->psz_url_video )
+    {
+        psz_url = es_print_url( p_sys->psz_url_video, p_fmt->i_fourcc, p_sys->i_count_video, psz_access, psz_mux );
+    }
+    else
+    {
+        int i_count;
+        if( p_fmt->i_cat == VIDEO_ES )
+        {
+            i_count = p_sys->i_count_video;
+        }
+        else if( p_fmt->i_cat == AUDIO_ES )
+        {
+            i_count = p_sys->i_count_audio;
+        }
+        else
+        {
+            i_count = p_sys->i_count;
+        }
+
+        psz_url = es_print_url( p_sys->psz_url, p_fmt->i_fourcc, i_count, psz_access, psz_mux );
+    }
+
+    p_sys->i_count++;
+    if( p_fmt->i_cat == VIDEO_ES )
+    {
+        p_sys->i_count_video++;
+    }
+    else if( p_fmt->i_cat == AUDIO_ES )
+    {
+        p_sys->i_count_audio++;
+    }
+    msg_Dbg( p_stream, "creating `%s/%s://%s'",
+             psz_access, psz_mux, psz_url );
+
+    /* *** find and open appropriate access module *** */
+    p_access = sout_AccessOutNew( p_sout, psz_access, psz_url );
+    if( p_access == NULL )
+    {
+        msg_Err( p_stream, "no suitable sout access module for `%s/%s://%s'",
+                 psz_access, psz_mux, psz_url );
+        return( NULL );
+    }
+
+    /* *** find and open appropriate mux module *** */
+    p_mux = sout_MuxNew( p_sout, psz_mux, p_access );
+    if( p_mux == NULL )
+    {
+        msg_Err( p_stream, "no suitable sout mux module for `%s/%s://%s'",
+                 psz_access, psz_mux, psz_url );
+        sout_AccessOutDelete( p_access );
+        return( NULL );
+    }
+
+    /* XXX beurk */
+    p_sout->i_preheader = __MAX( p_sout->i_preheader, p_mux->i_preheader );
+
+    id = malloc( sizeof( sout_stream_id_t ) );
+    id->p_mux = p_mux;
+    id->p_input = sout_MuxAddStream( p_mux, p_fmt );
+
+    if( id->p_input == NULL )
+    {
+        free( id );
+
+        sout_MuxDelete( p_mux );
+        sout_AccessOutDelete( p_access );
+        free( id );
+        return NULL;
+    }
+
+    return id;
+}
+
+static int     Del      ( sout_stream_t *p_stream, sout_stream_id_t *id )
+{
+    sout_access_out_t *p_access = id->p_mux->p_access;
+
+    sout_MuxDeleteStream( id->p_mux, id->p_input );
+    sout_AccessOutDelete( p_access );
+
+    free( id );
+    return VLC_SUCCESS;
+}
+
+static int     Send     ( sout_stream_t *p_stream, sout_stream_id_t *id, sout_buffer_t *p_buffer )
+{
+    sout_MuxSendBuffer( id->p_mux, id->p_input, p_buffer );
+
+    return VLC_SUCCESS;
+}
+
diff --git a/modules/stream_out/standard.c b/modules/stream_out/standard.c
new file mode 100644 (file)
index 0000000..9cb5664
--- /dev/null
@@ -0,0 +1,174 @@
+/*****************************************************************************
+ * standard.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: standard.c,v 1.1 2003/04/13 20:00:21 fenrir Exp $
+ *
+ * Authors: 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 <string.h>
+
+#include <vlc/vlc.h>
+#include <vlc/sout.h>
+
+/*****************************************************************************
+ * Exported prototypes
+ *****************************************************************************/
+static int      Open    ( vlc_object_t * );
+static void     Close   ( vlc_object_t * );
+
+static sout_stream_id_t *Add ( sout_stream_t *, sout_format_t * );
+static int               Del ( sout_stream_t *, sout_stream_id_t * );
+static int               Send( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("Standard stream") );
+    set_capability( "sout stream", 50 );
+    add_shortcut( "standard" );
+    add_shortcut( "std" );
+    set_callbacks( Open, Close );
+vlc_module_end();
+
+struct sout_stream_sys_t
+{
+    sout_mux_t *p_mux;
+};
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    sout_stream_t       *p_stream = (sout_stream_t*)p_this;
+    sout_instance_t     *p_sout = p_stream->p_sout;
+    sout_stream_sys_t   *p_sys;
+
+    char                *psz_mux    = sout_cfg_find_value( p_stream->p_cfg, "mux" );
+    char                *psz_access = sout_cfg_find_value( p_stream->p_cfg, "access" );
+    char                *psz_url    = sout_cfg_find_value( p_stream->p_cfg, "url" );
+
+    sout_access_out_t *p_access;
+    sout_mux_t        *p_mux;
+
+    msg_Dbg( p_this, "creating `%s/%s://%s'",
+             psz_access, psz_mux, psz_url );
+
+    /* *** find and open appropriate access module *** */
+    p_access = sout_AccessOutNew( p_sout, psz_access, psz_url );
+    if( p_access == NULL )
+    {
+        msg_Err( p_stream, "no suitable sout access module for `%s/%s://%s'",
+                 psz_access, psz_mux, psz_url );
+        return( VLC_EGENERIC );
+    }
+    msg_Dbg( p_stream, "access opened" );
+
+    /* *** find and open appropriate mux module *** */
+    p_mux = sout_MuxNew( p_sout, psz_mux, p_access );
+    if( p_mux == NULL )
+    {
+        msg_Err( p_stream, "no suitable sout mux module for `%s/%s://%s'",
+                 psz_access, psz_mux, psz_url );
+
+        sout_AccessOutDelete( p_access );
+        return( VLC_EGENERIC );
+    }
+    msg_Dbg( p_stream, "mux opened" );
+
+    /* XXX beurk */
+    p_sout->i_preheader = __MAX( p_sout->i_preheader, p_mux->i_preheader );
+
+    p_sys        = malloc( sizeof( sout_stream_sys_t ) );
+    p_sys->p_mux = p_mux;
+
+    p_stream->pf_add    = Add;
+    p_stream->pf_del    = Del;
+    p_stream->pf_send   = Send;
+
+    p_stream->p_sys     = p_sys;
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close:
+ *****************************************************************************/
+
+static void Close( vlc_object_t * p_this )
+{
+    sout_stream_t     *p_stream = (sout_stream_t*)p_this;
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+
+    sout_access_out_t *p_access = p_sys->p_mux->p_access;
+
+
+    sout_MuxDelete( p_sys->p_mux );
+    sout_AccessOutDelete( p_access );
+
+    free( p_sys );
+}
+
+struct sout_stream_id_t
+{
+    sout_input_t *p_input;
+};
+
+
+static sout_stream_id_t * Add      ( sout_stream_t *p_stream, sout_format_t *p_fmt )
+{
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+    sout_stream_id_t  *id;
+
+    id = malloc( sizeof( sout_stream_id_t ) );
+    if( ( id->p_input = sout_MuxAddStream( p_sys->p_mux, p_fmt ) ) == NULL )
+    {
+        free( id );
+
+        return NULL;
+    }
+
+    return id;
+}
+
+static int     Del      ( sout_stream_t *p_stream, sout_stream_id_t *id )
+{
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+
+    sout_MuxDeleteStream( p_sys->p_mux, id->p_input );
+
+    free( id );
+
+    return VLC_SUCCESS;
+}
+
+static int     Send     ( sout_stream_t *p_stream, sout_stream_id_t *id, sout_buffer_t *p_buffer )
+{
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+
+    sout_MuxSendBuffer( p_sys->p_mux, id->p_input, p_buffer );
+
+    return VLC_SUCCESS;
+}
+
diff --git a/modules/stream_out/transcode.c b/modules/stream_out/transcode.c
new file mode 100644 (file)
index 0000000..ded022d
--- /dev/null
@@ -0,0 +1,940 @@
+/*****************************************************************************
+ * transcode.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: transcode.c,v 1.1 2003/04/13 20:00:21 fenrir Exp $
+ *
+ * Authors: 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 <string.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#include "/home/fenrir/videolan/ffmpeg/libavcodec/avcodec.h"
+
+/*****************************************************************************
+ * Exported prototypes
+ *****************************************************************************/
+static int      Open    ( vlc_object_t * );
+static void     Close   ( vlc_object_t * );
+
+static sout_stream_id_t *Add ( sout_stream_t *, sout_format_t * );
+static int               Del ( sout_stream_t *, sout_stream_id_t * );
+static int               Send( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* );
+
+static int  transcode_audio_ffmpeg_new    ( sout_stream_t *, sout_stream_id_t * );
+static void transcode_audio_ffmpeg_close  ( sout_stream_t *, sout_stream_id_t * );
+static int  transcode_audio_ffmpeg_process( sout_stream_t *, sout_stream_id_t *, sout_buffer_t *, sout_buffer_t ** );
+
+static int  transcode_video_ffmpeg_new    ( sout_stream_t *, sout_stream_id_t * );
+static void transcode_video_ffmpeg_close  ( sout_stream_t *, sout_stream_id_t * );
+static int  transcode_video_ffmpeg_process( sout_stream_t *, sout_stream_id_t *, sout_buffer_t *, sout_buffer_t ** );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("Transcode stream") );
+    set_capability( "sout stream", 50 );
+    add_shortcut( "transcode" );
+    set_callbacks( Open, Close );
+vlc_module_end();
+
+struct sout_stream_sys_t
+{
+    sout_stream_t   *p_out;
+
+    vlc_fourcc_t    i_acodec;   // codec audio (0 if not transcode)
+    int             i_sample_rate;
+    int             i_channels;
+    int             i_abitrate;
+
+    vlc_fourcc_t    i_vcodec;   //   "   video  " "   "      "
+    int             i_vbitrate;
+    int             i_width;
+    int             i_height;
+    vlc_bool_t      b_deinterlace;
+
+    int             i_crop_top;
+    int             i_crop_bottom;
+    int             i_crop_right;
+    int             i_crop_left;
+};
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    sout_stream_t     *p_stream = (sout_stream_t*)p_this;
+    sout_stream_sys_t *p_sys;
+    char *codec;
+
+    p_sys = malloc( sizeof( sout_stream_sys_t ) );
+    p_sys->p_out = sout_stream_new( p_stream->p_sout, p_stream->psz_next );
+
+    p_sys->i_acodec      = 0;
+    p_sys->i_sample_rate = 0;
+    p_sys->i_channels    = 0;
+    p_sys->i_abitrate    = 0;
+
+    p_sys->i_vcodec     = 0;
+    p_sys->i_vbitrate   = 0;
+    p_sys->i_width      = 0;
+    p_sys->i_height     = 0;
+    p_sys->b_deinterlace= VLC_FALSE;
+
+    p_sys->i_crop_top   = 0;
+    p_sys->i_crop_bottom= 0;
+    p_sys->i_crop_right = 0;
+    p_sys->i_crop_left  = 0;
+
+    if( ( codec = sout_cfg_find_value( p_stream->p_cfg, "acodec" ) ) )
+    {
+        char fcc[4] = "    ";
+        char *val;
+
+        memcpy( fcc, codec, strlen( codec ) );
+
+        p_sys->i_acodec = VLC_FOURCC( fcc[0], fcc[1], fcc[2], fcc[3] );
+
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "samplerate" ) ) )
+        {
+            p_sys->i_sample_rate = atoi( val );
+        }
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "channels" ) ) )
+        {
+            p_sys->i_channels = atoi( val );
+        }
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "ab" ) ) )
+        {
+            p_sys->i_abitrate = atoi( val );
+        }
+
+        msg_Dbg( p_stream, "codec audio=%4.4s %dHz %d channels %dKb/s",
+                 fcc,
+                 p_sys->i_sample_rate, p_sys->i_channels,
+                 p_sys->i_abitrate / 1024 );
+    }
+
+    if( ( codec = sout_cfg_find_value( p_stream->p_cfg, "vcodec" ) ) )
+    {
+        char fcc[4] = "    ";
+        char *val;
+
+        memcpy( fcc, codec, strlen( codec ) );
+
+        p_sys->i_vcodec = VLC_FOURCC( fcc[0], fcc[1], fcc[2], fcc[3] );
+
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "width" ) ) )
+        {
+            p_sys->i_width = atoi( val );
+        }
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "height" ) ) )
+        {
+            p_sys->i_height = atoi( val );
+        }
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "vb" ) ) )
+        {
+            p_sys->i_vbitrate = atoi( val );
+        }
+        if( sout_cfg_find( p_stream->p_cfg, "deinterlace" ) )
+        {
+            p_sys->b_deinterlace = VLC_TRUE;
+        }
+        /* crop */
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "croptop" ) ) )
+        {
+            p_sys->i_crop_top = atoi( val );
+        }
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "cropbottom" ) ) )
+        {
+            p_sys->i_crop_bottom = atoi( val );
+        }
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "cropleft" ) ) )
+        {
+            p_sys->i_crop_left = atoi( val );
+        }
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "cropright" ) ) )
+        {
+            p_sys->i_crop_right = atoi( val );
+        }
+
+        msg_Dbg( p_stream, "codec video=%4.4s %dx%d %dkb/s",
+                 fcc,
+                 p_sys->i_width, p_sys->i_height,
+                 p_sys->i_vbitrate / 1024 );
+    }
+
+    if( !p_sys->p_out )
+    {
+        msg_Err( p_stream, "cannot create chain" );
+        free( p_sys );
+        return VLC_EGENERIC;
+    }
+    p_stream->pf_add    = Add;
+    p_stream->pf_del    = Del;
+    p_stream->pf_send   = Send;
+
+    p_stream->p_sys     = p_sys;
+
+    avcodec_init();
+    avcodec_register_all();
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close:
+ *****************************************************************************/
+
+static void Close( vlc_object_t * p_this )
+{
+    sout_stream_t       *p_stream = (sout_stream_t*)p_this;
+    sout_stream_sys_t   *p_sys = p_stream->p_sys;
+
+    sout_stream_delete( p_sys->p_out );
+    free( p_sys );
+}
+
+struct sout_stream_id_t
+{
+    vlc_fourcc_t  b_transcode;
+    sout_format_t f_src;        // only if transcoding
+    sout_format_t f_dst;        //  "   "      "
+
+    /* id of the out stream */
+    void *id;
+
+    /* ffmpeg part */
+    AVCodec         *ff_dec;
+    AVCodecContext  *ff_dec_c;
+
+
+    vlc_fourcc_t    b_enc_inited;
+    AVCodec         *ff_enc;
+    AVCodecContext  *ff_enc_c;
+
+    mtime_t         i_dts;
+    mtime_t         i_length;
+
+    int             i_buffer_in;
+    int             i_buffer_in_pos;
+    uint8_t         *p_buffer_in;
+
+    int             i_buffer;
+    int             i_buffer_pos;
+    uint8_t         *p_buffer;
+
+    int             i_buffer_out;
+    int             i_buffer_out_pos;
+    uint8_t         *p_buffer_out;
+
+    AVFrame         *p_ff_pic;
+    AVFrame         *p_ff_pic_tmp0; // to do deinterlace
+    AVFrame         *p_ff_pic_tmp1; // to do pix conversion
+    AVFrame         *p_ff_pic_tmp2; // to do resample
+
+    ImgReSampleContext *p_vresample;
+};
+
+
+static sout_stream_id_t * Add      ( sout_stream_t *p_stream, sout_format_t *p_fmt )
+{
+    sout_stream_sys_t   *p_sys = p_stream->p_sys;
+    sout_stream_id_t    *id;
+
+    id = malloc( sizeof( sout_stream_id_t ) );
+    id->i_dts = 0;
+    if( p_fmt->i_cat == AUDIO_ES && p_sys->i_acodec != 0 )
+    {
+        msg_Dbg( p_stream,
+                 "creating audio transcoding from fcc=`%4.4s' to fcc=`%4.4s'",
+                 (char*)&p_fmt->i_fourcc,
+                 (char*)&p_sys->i_acodec );
+
+        /* src format */
+        memcpy( &id->f_src, p_fmt, sizeof( sout_format_t ) );
+
+        /* create dst format */
+        id->f_dst.i_cat    = AUDIO_ES;
+        id->f_dst.i_fourcc = p_sys->i_acodec;
+        id->f_dst.i_sample_rate = p_sys->i_sample_rate  > 0 ? p_sys->i_sample_rate : id->f_src.i_sample_rate;
+        id->f_dst.i_channels    = p_sys->i_channels > 0 ? p_sys->i_channels : id->f_src.i_channels;
+        id->f_dst.i_bitrate     = p_sys->i_abitrate > 0 ? p_sys->i_abitrate : 64000;
+        id->f_dst.i_block_align = 0;
+        id->f_dst.i_extra_data  = 0;
+        id->f_dst.p_extra_data  = NULL;
+
+        /* build decoder -> filter -> encoder */
+        if( transcode_audio_ffmpeg_new( p_stream, id ) )
+        {
+            msg_Err( p_stream, "cannot create audio chain" );
+            free( id );
+            return NULL;
+        }
+
+        /* open output stream */
+        id->id = p_sys->p_out->pf_add( p_sys->p_out, &id->f_dst );
+        id->b_transcode = VLC_TRUE;
+    }
+    else if( p_fmt->i_cat == VIDEO_ES && p_sys->i_vcodec != 0 )
+    {
+        msg_Dbg( p_stream,
+                 "creating video transcoding from fcc=`%4.4s' to fcc=`%4.4s'",
+                 (char*)&p_fmt->i_fourcc,
+                 (char*)&p_sys->i_vcodec );
+
+        memcpy( &id->f_src, p_fmt, sizeof( sout_format_t ) );
+
+        /* create dst format */
+        id->f_dst.i_cat         = VIDEO_ES;
+        id->f_dst.i_fourcc      = p_sys->i_vcodec;
+        id->f_dst.i_width       = p_sys->i_width ; //> 0 ? p_sys->i_width : id->f_src.i_width;
+        id->f_dst.i_height      = p_sys->i_height; // > 0 ? p_sys->i_height: id->f_src.i_height;
+        id->f_dst.i_bitrate     = p_sys->i_vbitrate > 0 ? p_sys->i_vbitrate : 800*1000;
+        id->f_dst.i_extra_data  = 0;
+        id->f_dst.p_extra_data  = NULL;
+
+        /* build decoder -> filter -> encoder */
+        if( transcode_video_ffmpeg_new( p_stream, id ) )
+        {
+            msg_Err( p_stream, "cannot create video chain" );
+            free( id );
+            return NULL;
+        }
+
+        /* open output stream */
+        id->id = p_sys->p_out->pf_add( p_sys->p_out, &id->f_dst );
+        id->b_transcode = VLC_TRUE;
+    }
+    else
+    {
+        msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')", (char*)&p_fmt->i_fourcc );
+        id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
+        id->b_transcode = VLC_FALSE;
+
+        if( id->id == NULL )
+        {
+            free( id );
+            return NULL;
+        }
+    }
+
+    return id;
+}
+
+static int     Del      ( sout_stream_t *p_stream, sout_stream_id_t *id )
+{
+    sout_stream_sys_t   *p_sys = p_stream->p_sys;
+
+    if( id->b_transcode )
+    {
+        if( id->f_src.i_cat == AUDIO_ES )
+        {
+            transcode_audio_ffmpeg_close( p_stream, id );
+        }
+        else if( id->f_src.i_cat == VIDEO_ES )
+        {
+            transcode_video_ffmpeg_close( p_stream, id );
+        }
+    }
+
+    p_sys->p_out->pf_del( p_sys->p_out, id->id );
+    free( id );
+
+    return VLC_SUCCESS;
+}
+
+static int     Send     ( sout_stream_t *p_stream, sout_stream_id_t *id, sout_buffer_t *p_buffer )
+{
+    sout_stream_sys_t   *p_sys = p_stream->p_sys;
+
+    if( id->b_transcode )
+    {
+        sout_buffer_t *p_buffer_out;
+        if( id->f_src.i_cat == AUDIO_ES )
+        {
+            transcode_audio_ffmpeg_process( p_stream, id, p_buffer, &p_buffer_out );
+        }
+        else if( id->f_src.i_cat == VIDEO_ES )
+        {
+            transcode_video_ffmpeg_process( p_stream, id, p_buffer, &p_buffer_out );
+        }
+        sout_BufferDelete( p_stream->p_sout, p_buffer );
+
+        if( p_buffer_out )
+        {
+            return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer_out );
+        }
+        return VLC_SUCCESS;
+    }
+    else
+    {
+        return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
+    }
+}
+
+/****************************************************************************
+ * ffmpeg decoder reencocdr part
+ ****************************************************************************/
+
+static struct
+{
+    vlc_fourcc_t i_fcc;
+    int          i_ff_codec;
+} fourcc_to_ff_code[] =
+{
+    /* audio */
+    { VLC_FOURCC( 'm', 'p', 'g', 'a' ), CODEC_ID_MP2 },
+    { VLC_FOURCC( 'a', '5', '2', ' ' ), CODEC_ID_AC3 },
+    { VLC_FOURCC( 'a', 'c', '3', ' ' ), CODEC_ID_AC3 },
+    { VLC_FOURCC( 'w', 'm', 'a', '1' ), CODEC_ID_WMAV1 },
+    { VLC_FOURCC( 'w', 'm', 'a', '2' ), CODEC_ID_WMAV2 },
+
+    /* video */
+    { VLC_FOURCC( 'm', 'p', '4', 'v'),  CODEC_ID_MPEG4 },
+    { VLC_FOURCC( 'm', 'p', 'g', 'v' ), CODEC_ID_MPEG1VIDEO },
+    { VLC_FOURCC( 'D', 'I', 'V', '1' ), CODEC_ID_MSMPEG4V1 },
+    { VLC_FOURCC( 'D', 'I', 'V', '2' ), CODEC_ID_MSMPEG4V2 },
+    { VLC_FOURCC( 'D', 'I', 'V', '3' ), CODEC_ID_MSMPEG4V3 },
+    { VLC_FOURCC( 'H', '2', '6', '3' ), CODEC_ID_H263 },
+    { VLC_FOURCC( 'I', '2', '6', '3' ), CODEC_ID_H263I },
+    { VLC_FOURCC( 'W', 'M', 'V', '1' ), CODEC_ID_WMV1 },
+    { VLC_FOURCC( 'W', 'M', 'V', '2' ), CODEC_ID_WMV2 },
+    { VLC_FOURCC( 'M', 'J', 'P', 'G' ), CODEC_ID_MJPEG },
+    { VLC_FOURCC( 'm', 'j', 'p', 'b' ), CODEC_ID_MJPEGB },
+    { VLC_FOURCC( 'd', 'v', 's', 'l' ), CODEC_ID_DVVIDEO },
+    { VLC_FOURCC( 'S', 'V', 'Q', '1' ), CODEC_ID_SVQ1 },
+
+    { VLC_FOURCC(   0,   0,   0,   0 ), 0 }
+};
+
+static inline int get_ff_codec( vlc_fourcc_t i_fcc )
+{
+    int i;
+
+    for( i = 0; fourcc_to_ff_code[i].i_fcc != 0; i++ )
+    {
+        if( fourcc_to_ff_code[i].i_fcc == i_fcc )
+        {
+            return fourcc_to_ff_code[i].i_ff_codec;
+        }
+    }
+
+    return 0;
+}
+
+static int transcode_audio_ffmpeg_new   ( sout_stream_t *p_stream, sout_stream_id_t *id )
+{
+    int i_ff_codec;
+
+    /* find decoder */
+
+    i_ff_codec = get_ff_codec( id->f_src.i_fourcc );
+    if( i_ff_codec == 0 )
+    {
+        msg_Err( p_stream, "cannot find decoder" );
+        return VLC_EGENERIC;
+    }
+
+    id->ff_dec = avcodec_find_decoder( i_ff_codec );
+    if( !id->ff_dec )
+    {
+        msg_Err( p_stream, "cannot find decoder" );
+        return VLC_EGENERIC;
+    }
+
+    id->ff_dec_c = avcodec_alloc_context();
+    id->ff_dec_c->sample_rate = id->f_src.i_sample_rate;
+    id->ff_dec_c->channels    = id->f_src.i_channels;
+    id->ff_dec_c->block_align = id->f_src.i_block_align;
+    id->ff_dec_c->bit_rate    = id->f_src.i_bitrate;
+
+    id->ff_dec_c->extradata_size = id->f_src.i_extra_data;
+    id->ff_dec_c->extradata      = id->f_src.p_extra_data;
+    if( avcodec_open( id->ff_dec_c, id->ff_dec ) )
+    {
+        msg_Err( p_stream, "cannot open decoder" );
+        return VLC_EGENERIC;
+    }
+
+    /* find encoder */
+    i_ff_codec = get_ff_codec( id->f_dst.i_fourcc );
+    if( i_ff_codec == 0 )
+    {
+        msg_Err( p_stream, "cannot find encoder" );
+        return VLC_EGENERIC;
+    }
+
+    id->ff_enc = avcodec_find_encoder( i_ff_codec );
+    if( !id->ff_enc )
+    {
+        msg_Err( p_stream, "cannot find encoder" );
+        return VLC_EGENERIC;
+    }
+
+    id->ff_enc_c = avcodec_alloc_context();
+    id->ff_enc_c->bit_rate    = id->f_dst.i_bitrate;
+    id->ff_enc_c->sample_rate = id->f_dst.i_sample_rate;
+    id->ff_enc_c->channels    = id->f_dst.i_channels;
+
+    if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
+    {
+        msg_Err( p_stream, "cannot open encoder" );
+        return VLC_EGENERIC;
+    }
+
+
+    id->i_buffer_in      = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+    id->i_buffer_in_pos = 0;
+    id->p_buffer_in      = malloc( id->i_buffer_in );
+
+    id->i_buffer     = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+    id->i_buffer_pos = 0;
+    id->p_buffer     = malloc( id->i_buffer );
+
+    id->i_buffer_out     = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+    id->i_buffer_out_pos = 0;
+    id->p_buffer_out     = malloc( id->i_buffer_out );
+
+    return VLC_SUCCESS;
+}
+
+static void transcode_audio_ffmpeg_close ( sout_stream_t *p_stream, sout_stream_id_t *id )
+{
+    avcodec_close( id->ff_dec_c );
+    avcodec_close( id->ff_enc_c );
+
+    free( id->ff_dec_c );
+    free( id->ff_enc_c );
+
+    free( id->p_buffer );
+}
+
+static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream, sout_stream_id_t *id,
+                                           sout_buffer_t *in, sout_buffer_t **out )
+{
+    *out = NULL;
+
+    /* gather data into p_buffer_in */
+    id->i_dts = in->i_dts -
+                (mtime_t)1000000 *
+                (mtime_t)(id->i_buffer_pos / 2 / id->ff_enc_c->channels )/
+                (mtime_t)id->ff_enc_c->sample_rate;
+
+    memcpy( &id->p_buffer_in[id->i_buffer_in_pos],
+            in->p_buffer,
+            in->i_size );
+    id->i_buffer_in_pos += in->i_size;
+
+    /* decode as many data as possible */
+    for( ;; )
+    {
+        int i_buffer_size;
+        int i_used;
+
+        i_buffer_size = id->i_buffer - id->i_buffer_pos;
+
+        i_used = avcodec_decode_audio( id->ff_dec_c,
+                                       (int16_t*)&id->p_buffer[id->i_buffer_pos], &i_buffer_size,
+                                       id->p_buffer_in, id->i_buffer_in_pos );
+
+        //msg_Warn( p_stream, "avcodec_decode_audio: %d used", i_used );
+        id->i_buffer_pos += i_buffer_size;
+
+        if( i_used < 0 )
+        {
+            msg_Warn( p_stream, "error");
+            id->i_buffer_in_pos = 0;
+            break;
+        }
+        else if( i_used < id->i_buffer_in_pos )
+        {
+            memmove( id->p_buffer_in,
+                     &id->p_buffer_in[i_used],
+                     id->i_buffer_in - i_used );
+            id->i_buffer_in_pos -= i_used;
+        }
+        else
+        {
+            id->i_buffer_in_pos = 0;
+            break;
+        }
+    }
+
+    /* encode as many data as possible */
+    for( ;; )
+    {
+        int i_frame_size = id->ff_enc_c->frame_size * 2 * id->ff_enc_c->channels;
+        int i_out_size;
+        sout_buffer_t *p_out;
+
+        if( id->i_buffer_pos < i_frame_size )
+        {
+            break;
+        }
+
+        //msg_Warn( p_stream, "avcodec_encode_audio: frame size%d", i_frame_size);
+        i_out_size = avcodec_encode_audio( id->ff_enc_c,
+                                           id->p_buffer_out, id->i_buffer_out,
+                                           (int16_t*)id->p_buffer );
+
+        if( i_out_size <= 0 )
+        {
+            break;
+        }
+        memmove( id->p_buffer,
+                 &id->p_buffer[i_frame_size],
+                 id->i_buffer - i_frame_size );
+        id->i_buffer_pos -= i_frame_size;
+
+        p_out = sout_BufferNew( p_stream->p_sout, i_out_size );
+        memcpy( p_out->p_buffer, id->p_buffer_out, i_out_size );
+        p_out->i_size = i_out_size;
+        p_out->i_length = (mtime_t)1000000 * (mtime_t)id->ff_enc_c->frame_size / (mtime_t)id->ff_enc_c->sample_rate;
+        /* FIXME */
+        p_out->i_dts = id->i_dts;
+        p_out->i_pts = id->i_dts;
+
+        /* update dts */
+        id->i_dts += p_out->i_length;
+
+       //msg_Warn( p_stream, "frame dts=%lld len %lld out=%d", p_out->i_dts, p_out->i_length, i_out_size );
+        sout_BufferChain( out, p_out );
+    }
+
+    return VLC_SUCCESS;
+}
+
+
+/*
+ * video
+ */
+static int transcode_video_ffmpeg_new   ( sout_stream_t *p_stream, sout_stream_id_t *id )
+{
+    int i_ff_codec;
+
+    /* find decoder */
+    i_ff_codec = get_ff_codec( id->f_src.i_fourcc );
+    if( i_ff_codec == 0 )
+    {
+        msg_Err( p_stream, "cannot find decoder" );
+        return VLC_EGENERIC;
+    }
+
+    id->ff_dec = avcodec_find_decoder( i_ff_codec );
+    if( !id->ff_dec )
+    {
+        msg_Err( p_stream, "cannot find decoder" );
+        return VLC_EGENERIC;
+    }
+
+    id->ff_dec_c = avcodec_alloc_context();
+    id->ff_dec_c->width         = id->f_src.i_width;
+    id->ff_dec_c->height        = id->f_src.i_height;
+    //id->ff_dec_c->bit_rate      = id->f_src.i_bitrate;
+    id->ff_dec_c->extradata_size= id->f_src.i_extra_data;
+    id->ff_dec_c->extradata     = id->f_src.p_extra_data;
+    id->ff_dec_c->workaround_bugs = FF_BUG_AUTODETECT;
+    id->ff_dec_c->error_resilience= -1;
+    if( id->ff_dec->capabilities & CODEC_CAP_TRUNCATED )
+    {
+        id->ff_dec_c->flags |= CODEC_FLAG_TRUNCATED;
+    }
+
+    if( avcodec_open( id->ff_dec_c, id->ff_dec ) < 0 )
+    {
+        msg_Err( p_stream, "cannot open decoder" );
+        return VLC_EGENERIC;
+    }
+#if 1
+    if( i_ff_codec == CODEC_ID_MPEG4 && id->ff_dec_c->extradata_size > 0 )
+    {
+        int b_gotpicture;
+        AVFrame frame;
+
+        avcodec_decode_video( id->ff_dec_c, &frame,
+                              &b_gotpicture,
+                              id->ff_dec_c->extradata, id->ff_dec_c->extradata_size );
+    }
+#endif
+
+    /* find encoder */
+    i_ff_codec = get_ff_codec( id->f_dst.i_fourcc );
+    if( i_ff_codec == 0 )
+    {
+        msg_Err( p_stream, "cannot find encoder" );
+        return VLC_EGENERIC;
+    }
+
+    id->ff_enc = avcodec_find_encoder( i_ff_codec );
+    if( !id->ff_enc )
+    {
+        msg_Err( p_stream, "cannot find encoder" );
+        return VLC_EGENERIC;
+    }
+
+    id->ff_enc_c = avcodec_alloc_context();
+    id->ff_enc_c->width          = id->f_dst.i_width;
+    id->ff_enc_c->height         = id->f_dst.i_height;
+    id->ff_enc_c->bit_rate       = id->f_dst.i_bitrate;
+    id->ff_enc_c->frame_rate     = 25 ; // FIXME as it break mpeg
+    id->ff_enc_c->frame_rate_base= 1;
+    id->ff_enc_c->gop_size       = 25;
+    id->ff_enc_c->qmin           = 2;
+    id->ff_enc_c->qmax           = 31;
+#if 0
+    /* XXX open it when we have the first frame */
+    if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
+    {
+        msg_Err( p_stream, "cannot open encoder" );
+        return VLC_EGENERIC;
+    }
+#endif
+    id->b_enc_inited     = VLC_FALSE;
+    id->i_buffer_in      = 0;
+    id->i_buffer_in_pos  = 0;
+    id->p_buffer_in      = NULL;
+
+    id->i_buffer     = 3*1024*1024;
+    id->i_buffer_pos = 0;
+    id->p_buffer     = malloc( id->i_buffer );
+
+    id->i_buffer_out     = 0;
+    id->i_buffer_out_pos = 0;
+    id->p_buffer_out     = NULL;
+
+    id->p_ff_pic         = avcodec_alloc_frame();
+    id->p_ff_pic_tmp0    = NULL;
+    id->p_ff_pic_tmp1    = NULL;
+    id->p_ff_pic_tmp2    = NULL;
+    id->p_vresample      = NULL;
+    return VLC_SUCCESS;
+}
+
+static void transcode_video_ffmpeg_close ( sout_stream_t *p_stream, sout_stream_id_t *id )
+{
+    avcodec_close( id->ff_dec_c );
+    if( id->b_enc_inited )
+    {
+        avcodec_close( id->ff_enc_c );
+    }
+
+    if( id->p_ff_pic)
+    {
+        free( id->p_ff_pic );
+    }
+
+    if( id->p_ff_pic_tmp0 )
+    {
+        free( id->p_ff_pic_tmp0->data[0] );
+        free( id->p_ff_pic_tmp0 );
+    }
+    if( id->p_ff_pic_tmp1)
+    {
+        free( id->p_ff_pic_tmp1->data[0] );
+        free( id->p_ff_pic_tmp1 );
+    }
+    if( id->p_ff_pic_tmp2)
+    {
+        free( id->p_ff_pic_tmp2->data[0] );
+        free( id->p_ff_pic_tmp2 );
+    }
+    if( id->p_vresample )
+    {
+        free( id->p_vresample );
+    }
+
+    free( id->ff_dec_c );
+    free( id->ff_enc_c );
+
+    free( id->p_buffer );
+}
+
+static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_id_t *id,
+                                           sout_buffer_t *in, sout_buffer_t **out )
+{
+    int     i_used;
+    int     i_out;
+    int     b_gotpicture;
+    AVFrame *frame;
+
+    int     i_data;
+    uint8_t *p_data;
+
+    *out = NULL;
+
+    i_data = in->i_size;
+    p_data = in->p_buffer;
+
+    for( ;; )
+    {
+        /* decode frame */
+        frame = id->p_ff_pic;
+        i_used = avcodec_decode_video( id->ff_dec_c, frame,
+                                       &b_gotpicture,
+                                       p_data, i_data );
+
+        if( i_used < 0 )
+        {
+            msg_Warn( p_stream, "error");
+            return VLC_EGENERIC;
+        }
+        i_data -= i_used;
+        p_data += i_used;
+
+        if( !b_gotpicture )
+        {
+            return VLC_SUCCESS;
+        }
+
+        if( !id->b_enc_inited )
+        {
+            /* XXX hack because of copy packetizer and mpeg4video that can failed
+               detecting size */
+            if( id->ff_enc_c->width == 0 || id->ff_enc_c->height == 0 )
+            {
+                id->ff_enc_c->width          = id->ff_dec_c->width;
+                id->ff_enc_c->height         = id->ff_dec_c->height;
+            }
+
+            if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
+            {
+                msg_Err( p_stream, "cannot open encoder" );
+                return VLC_EGENERIC;
+            }
+            id->b_enc_inited = VLC_TRUE;
+        }
+
+
+        /* deinterlace */
+        if( p_stream->p_sys->b_deinterlace )
+        {
+            if( id->p_ff_pic_tmp0 == NULL )
+            {
+                int     i_size;
+                uint8_t *buf;
+                id->p_ff_pic_tmp0 = avcodec_alloc_frame();
+                i_size = avpicture_get_size( id->ff_dec_c->pix_fmt,
+                                             id->ff_dec_c->width, id->ff_dec_c->height );
+
+                buf = malloc( i_size );
+
+                avpicture_fill( (AVPicture*)id->p_ff_pic_tmp0, buf,
+                                id->ff_enc_c->pix_fmt,
+                                id->ff_dec_c->width, id->ff_dec_c->height );
+            }
+
+            avpicture_deinterlace( (AVPicture*)id->p_ff_pic_tmp0, (AVPicture*)frame,
+                                   id->ff_dec_c->pix_fmt,
+                                   id->ff_dec_c->width, id->ff_dec_c->height );
+
+            frame = id->p_ff_pic_tmp0;
+        }
+
+        /* convert pix format */
+        if( id->ff_dec_c->pix_fmt != id->ff_enc_c->pix_fmt )
+        {
+            if( id->p_ff_pic_tmp1 == NULL )
+            {
+                int     i_size;
+                uint8_t *buf;
+                id->p_ff_pic_tmp1 = avcodec_alloc_frame();
+                i_size = avpicture_get_size( id->ff_enc_c->pix_fmt,
+                                             id->ff_dec_c->width, id->ff_dec_c->height );
+
+                buf = malloc( i_size );
+
+                avpicture_fill( (AVPicture*)id->p_ff_pic_tmp1, buf,
+                                id->ff_enc_c->pix_fmt,
+                                id->ff_dec_c->width, id->ff_dec_c->height );
+            }
+
+            img_convert( (AVPicture*)id->p_ff_pic_tmp1, id->ff_enc_c->pix_fmt,
+                         (AVPicture*)frame,             id->ff_dec_c->pix_fmt,
+                         id->ff_dec_c->width, id->ff_dec_c->height );
+
+            frame = id->p_ff_pic_tmp1;
+        }
+
+        /* convert size and crop */
+        if( ( id->ff_dec_c->width  != id->ff_enc_c->width ) ||
+            ( id->ff_dec_c->height != id->ff_enc_c->height ) )
+        {
+            if( id->p_ff_pic_tmp2 == NULL )
+            {
+                int     i_size;
+                uint8_t *buf;
+                id->p_ff_pic_tmp2 = avcodec_alloc_frame();
+                i_size = avpicture_get_size( id->ff_enc_c->pix_fmt,
+                                             id->ff_enc_c->width, id->ff_enc_c->height );
+
+                buf = malloc( i_size );
+
+                avpicture_fill( (AVPicture*)id->p_ff_pic_tmp2, buf,
+                                id->ff_enc_c->pix_fmt,
+                                id->ff_enc_c->width, id->ff_enc_c->height );
+
+                id->p_vresample =
+                    img_resample_full_init( id->ff_enc_c->width, id->ff_enc_c->height,
+                                            id->ff_dec_c->width, id->ff_dec_c->height,
+                                            p_stream->p_sys->i_crop_top,
+                                            p_stream->p_sys->i_crop_bottom,
+                                            p_stream->p_sys->i_crop_left,
+                                            p_stream->p_sys->i_crop_right );
+            }
+
+            img_resample( id->p_vresample, (AVPicture*)id->p_ff_pic_tmp2, (AVPicture*)frame );
+
+            frame = id->p_ff_pic_tmp2;
+        }
+
+        /* encode frame */
+        i_out = avcodec_encode_video( id->ff_enc_c, id->p_buffer, id->i_buffer, frame );
+
+        if( i_out > 0 )
+        {
+            sout_buffer_t *p_out;
+            p_out = sout_BufferNew( p_stream->p_sout, i_out );
+
+            memcpy( p_out->p_buffer, id->p_buffer, i_out );
+
+            p_out->i_size   = i_out;
+            p_out->i_length = in->i_length;
+            p_out->i_dts    = in->i_dts;
+            p_out->i_pts    = in->i_dts; /* FIXME */
+
+            sout_BufferChain( out, p_out );
+        }
+
+        if( i_data <= 0 )
+        {
+            return VLC_SUCCESS;
+        }
+    }
+
+    return VLC_SUCCESS;
+}
+
index 7489d7a..0ee1d03 100644 (file)
@@ -2,7 +2,7 @@
  * input_dec.c: Functions for the management of decoders
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: input_dec.c,v 1.59 2003/03/04 13:21:19 massiot Exp $
+ * $Id: input_dec.c,v 1.60 2003/04/13 20:00:21 fenrir Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -58,10 +58,9 @@ decoder_fifo_t * input_RunDecoder( input_thread_t * p_input,
     }
 
     p_fifo->p_module = NULL;
-    /* If we are in sout mode, search first for packetizer module then
-     * codec to do transcoding */
+    /* If we are in sout mode, search for packetizer module */
     psz_sout = config_GetPsz( p_input, "sout" );
-    if( psz_sout != NULL && *psz_sout != 0 )
+    if( !p_es->b_force_decoder && psz_sout != NULL && *psz_sout != 0 )
     {
         vlc_bool_t b_sout = VLC_TRUE;
 
@@ -76,40 +75,8 @@ decoder_fifo_t * input_RunDecoder( input_thread_t * p_input,
 
         if( b_sout )
         {
-            vlc_bool_t b_reencode = VLC_FALSE;
-
-            if( p_es->i_cat == AUDIO_ES )
-            {
-                char *psz_sout_acodec = config_GetPsz( p_input, "sout-acodec" );
-                if( psz_sout_acodec != NULL && *psz_sout_acodec != '\0' )
-                {
-                    msg_Dbg( p_input, "audio reencoding requested -> unsupported" );
-                    b_reencode = VLC_TRUE;
-                }
-            }
-            else if( p_es->i_cat == VIDEO_ES )
-            {
-                char *psz_sout_vcodec = config_GetPsz( p_input, "sout-vcodec" );
-                if( psz_sout_vcodec != NULL && *psz_sout_vcodec != '\0' )
-                {
-                    msg_Dbg( p_input, "video reencoding requested" );
-                    /* force encoder video output */
-                    config_PutPsz( p_input, "vout", "encoder" );
-                    b_reencode = VLC_TRUE;
-                }
-            }
-
-            if( !b_reencode )
-            {
-                /* we don't want to reencode so search for a packetizer */
-                p_fifo->p_module =
-                    module_Need( p_fifo, "packetizer", "$packetizer" );
-            }
-            else
-            {
-                /* get a suitable decoder module to do reencoding*/
-                p_fifo->p_module = module_Need( p_fifo, "decoder", "$codec" );
-            }
+            p_fifo->p_module =
+                module_Need( p_fifo, "packetizer", "$packetizer" );
         }
     }
     else
@@ -118,6 +85,11 @@ decoder_fifo_t * input_RunDecoder( input_thread_t * p_input,
         p_fifo->p_module = module_Need( p_fifo, "decoder", "$codec" );
     }
 
+    if( psz_sout )
+    {
+        free( psz_sout );
+    }
+
     if( p_fifo->p_module == NULL )
     {
         msg_Err( p_fifo, "no suitable decoder module for fourcc `%4.4s'.\nVLC probably does not support this sound or video format.",
index 838e236..cc66a62 100644 (file)
@@ -2,7 +2,7 @@
  * input_programs.c: es_descriptor_t, pgrm_descriptor_t management
  *****************************************************************************
  * Copyright (C) 1999-2002 VideoLAN
- * $Id: input_programs.c,v 1.103 2003/03/12 05:26:46 sam Exp $
+ * $Id: input_programs.c,v 1.104 2003/04/13 20:00:21 fenrir Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -524,6 +524,7 @@ es_descriptor_t * input_AddES( input_thread_t * p_input,
     p_es->i_demux_fd = 0;
     p_es->c_packets = 0;
     p_es->c_invalid_packets = 0;
+    p_es->b_force_decoder = VLC_FALSE;
 
     if( i_data_len )
     {
index e578f69..92cb1ac 100644 (file)
@@ -2,7 +2,7 @@
  * stream_output.c : stream output module
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: stream_output.c,v 1.23 2003/03/31 03:46:11 fenrir Exp $
+ * $Id: stream_output.c,v 1.24 2003/04/13 20:00:21 fenrir Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *          Laurent Aimar <fenrir@via.ecp.fr>
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static int          InstanceNewOutput   ( sout_instance_t *, char * );
-static int          InstanceMuxNew      ( sout_instance_t *,
-                                          char *, char *, char * );
-
-static sout_mux_t * MuxNew              ( sout_instance_t*,
-                                          char *, sout_access_out_t * );
-static sout_input_t *MuxAddStream       ( sout_mux_t *, sout_packet_format_t * );
-static void         MuxDeleteStream     ( sout_mux_t *, sout_input_t * );
-static void         MuxDelete           ( sout_mux_t * );
-
-#if 0
-typedef struct
-{
-    /* if muxer doesn't support adding stream at any time then we first wait
-     *  for stream then we refuse all stream and start muxing */
-    vlc_bool_t  b_add_stream_any_time;
-    vlc_bool_t  b_waiting_stream;
-
-    /* we wait one second after first stream added */
-    mtime_t     i_add_stream_start;
-
-} sout_instance_sys_mux_t;
-#endif
-
-struct sout_instance_sys_t
-{
-    int i_d_u_m_m_y;
-};
-
+static char *sout_stream_chain_to_str( char * );
 /*
  * Generic MRL parser
  *
  */
-/* <access>{options}/<way>{options}://<name> */
-typedef struct mrl_option_s
-{
-    struct mrl_option_s *p_next;
-
-    char *psz_name;
-    char *psz_value;
-} mrl_option_t;
 
 typedef struct
 {
     char            *psz_access;
-    mrl_option_t    *p_access_options;
 
     char            *psz_way;
-    mrl_option_t    *p_way_options;
 
     char *psz_name;
 } mrl_t;
@@ -95,54 +57,6 @@ static int  mrl_Parse( mrl_t *p_mrl, char *psz_mrl );
 /* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
 static void mrl_Clean( mrl_t *p_mrl );
 
-/* some macro */
-#define TAB_APPEND( count, tab, p )             \
-    if( (count) > 0 )                           \
-    {                                           \
-        (tab) = realloc( (tab), sizeof( void ** ) * ( (count) + 1 ) ); \
-    }                                           \
-    else                                        \
-    {                                           \
-        (tab) = malloc( sizeof( void ** ) );    \
-    }                                           \
-    (void**)(tab)[(count)] = (void*)(p);        \
-    (count)++
-
-#define TAB_FIND( count, tab, p, index )        \
-    {                                           \
-        int _i_;                                \
-        (index) = -1;                           \
-        for( _i_ = 0; _i_ < (count); _i_++ )    \
-        {                                       \
-            if((void**)(tab)[_i_]==(void*)(p))  \
-            {                                   \
-                (index) = _i_;                  \
-                break;                          \
-            }                                   \
-        }                                       \
-    }
-
-#define TAB_REMOVE( count, tab, p )             \
-    {                                           \
-        int i_index;                            \
-        TAB_FIND( count, tab, p, i_index );     \
-        if( i_index >= 0 )                      \
-        {                                       \
-            if( count > 1 )                     \
-            {                                   \
-                memmove( ((void**)tab + i_index),    \
-                         ((void**)tab + i_index+1),  \
-                         ( (count) - i_index - 1 ) * sizeof( void* ) );\
-            }                                   \
-            else                                \
-            {                                   \
-                free( tab );                    \
-                (tab) = NULL;                   \
-            }                                   \
-            (count)--;                          \
-        }                                       \
-    }
-
 #define FREE( p ) if( p ) { free( p ); (p) = NULL; }
 
 /*****************************************************************************
@@ -152,9 +66,8 @@ sout_instance_t * __sout_NewInstance ( vlc_object_t *p_parent,
                                        char * psz_dest )
 {
     sout_instance_t *p_sout;
-    char            *psz_dup, *psz_parser, *psz_pos;
 
-    /* Allocate descriptor */
+    /* *** Allocate descriptor *** */
     p_sout = vlc_object_create( p_parent, VLC_OBJECT_SOUT );
     if( p_sout == NULL )
     {
@@ -162,50 +75,30 @@ sout_instance_t * __sout_NewInstance ( vlc_object_t *p_parent,
         return NULL;
     }
 
-    p_sout->psz_sout    = NULL;
-
-    p_sout->i_nb_dest   = 0;
-    p_sout->ppsz_dest   = NULL;
-
+    /* *** init descriptor *** */
+    p_sout->psz_sout    = strdup( psz_dest );
     p_sout->i_preheader = 0;
-    p_sout->i_nb_mux    = 0;
-    p_sout->pp_mux      = 0;
+    p_sout->p_sys       = NULL;
 
     vlc_mutex_init( p_sout, &p_sout->lock );
-    p_sout->i_nb_inputs = 0;
-    p_sout->pp_inputs   = NULL;
-
-    p_sout->p_sys           = malloc( sizeof( sout_instance_sys_t ) );
-
-    /* now parse psz_sout */
-    psz_dup = strdup( psz_dest );
-    psz_parser = psz_dup;
-
-    while( ( psz_pos = strchr( psz_parser, '#' ) ) != NULL )
+    if( psz_dest && psz_dest[0] == '#' )
     {
-        *psz_pos++ = '\0';
-
-        if( InstanceNewOutput( p_sout, psz_parser ) )
-        {
-            msg_Err( p_sout, "adding `%s' failed", psz_parser );
-        }
-
-        psz_parser = psz_pos;
+        p_sout->psz_chain = strdup( &psz_dest[1] );
     }
-
-    if( *psz_parser )
+    else
     {
-        if( InstanceNewOutput( p_sout, psz_parser ) )
-        {
-            msg_Err( p_sout, "adding `%s' failed", psz_parser );
-        }
+        p_sout->psz_chain = sout_stream_chain_to_str( psz_dest );
     }
 
-    free( psz_dup );
+    p_sout->p_stream = sout_stream_new( p_sout, p_sout->psz_chain );
 
-    if( p_sout->i_nb_dest <= 0 )
+    if( p_sout->p_stream == NULL )
     {
-        msg_Err( p_sout, "all sout failed" );
+        msg_Err( p_sout, "stream chained failed for `%s'", p_sout->psz_chain );
+
+        FREE( p_sout->psz_sout );
+        FREE( p_sout->psz_chain );
+
         vlc_object_destroy( p_sout );
         return( NULL );
     }
@@ -219,221 +112,114 @@ sout_instance_t * __sout_NewInstance ( vlc_object_t *p_parent,
  *****************************************************************************/
 void sout_DeleteInstance( sout_instance_t * p_sout )
 {
-    int i;
     /* Unlink object */
     vlc_object_detach( p_sout );
 
     /* *** free all string *** */
     FREE( p_sout->psz_sout );
+    FREE( p_sout->psz_chain );
 
-    for( i = 0; i < p_sout->i_nb_dest; i++ )
-    {
-        FREE( p_sout->ppsz_dest[i] );
-    }
-    FREE( p_sout->ppsz_dest );
-
-    /* *** there shouldn't be any input ** */
-    if( p_sout->i_nb_inputs > 0 )
-    {
-        msg_Err( p_sout, "i_nb_inputs=%d > 0 !!!!!!", p_sout->i_nb_inputs );
-        msg_Err( p_sout, "mmmh I have a bad feeling..." );
-    }
+    sout_stream_delete( p_sout->p_stream );
     vlc_mutex_destroy( &p_sout->lock );
 
-    /* *** remove all muxer *** */
-    for( i = 0; i < p_sout->i_nb_mux; i++ )
-    {
-        sout_access_out_t *p_access;
-#define p_mux p_sout->pp_mux[i]
-
-        p_access = p_mux->p_access;
-
-        MuxDelete( p_mux );
-        sout_AccessOutDelete( p_access );
-#undef  p_mux
-    }
-    FREE( p_sout->pp_mux );
-
-#if 0
-    for( i = 0; i < p_sout->p_sys->i_nb_mux; i++ )
-    {
-        FREE( p_sout->p_sys->pp_mux[i] );
-    }
-    FREE( p_sout->p_sys->pp_mux );
-#endif
-
-    /* Free structure */
+    /* *** free structure *** */
     vlc_object_destroy( p_sout );
 }
 
-
-
 /*****************************************************************************
- * InitInstance: opens appropriate modules
+ * Packetizer/Input
  *****************************************************************************/
-static int      InstanceNewOutput   (sout_instance_t *p_sout, char *psz_dest )
+sout_packetizer_input_t *__sout_InputNew( vlc_object_t  *p_this,
+                                          sout_format_t *p_fmt )
 {
-    mrl_t   mrl;
-    char * psz_dup;
-#if 0
-    /* Parse dest string. Syntax : [[<access>][/<mux>]:][<dest>] */
-    /* This code is identical to input.c:InitThread. FIXME : factorize it ? */
+    sout_instance_t         *p_sout = NULL;
+    sout_packetizer_input_t *p_input;
 
-    char * psz_dup = strdup( psz_dest );
-    char * psz_parser = psz_dup;
-    char * psz_access = "";
-    char * psz_mux = "";
-    char * psz_name = "";
-    /* *** first parse psz_dest */
-    while( *psz_parser && *psz_parser != ':' )
-    {
-        psz_parser++;
-    }
-#if defined( WIN32 ) || defined( UNDER_CE )
-    if( psz_parser - psz_dup == 1 )
-    {
-        msg_Warn( p_sout, "drive letter %c: found in source string",
-                          *psz_dup ) ;
-        psz_parser = "";
-    }
-#endif
+    int             i_try;
 
-    if( !*psz_parser )
-    {
-        psz_access = psz_mux = "";
-        psz_name = psz_dup;
-    }
-    else
+    /* search an stream output */
+    for( i_try = 0; i_try < 12; i_try++ )
     {
-        *psz_parser++ = '\0';
-
-        /* let's skip '//' */
-        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
+        p_sout = vlc_object_find( p_this, VLC_OBJECT_SOUT, FIND_ANYWHERE );
+        if( p_sout )
         {
-            psz_parser += 2 ;
+            break;
         }
 
-        psz_name = psz_parser ;
-
-        /* Come back to parse the access and mux plug-ins */
-        psz_parser = psz_dup;
+        msleep( 100*1000 );
+        msg_Dbg( p_this, "waiting for sout" );
+    }
 
-        if( !*psz_parser )
-        {
-            /* No access */
-            psz_access = "";
-        }
-        else if( *psz_parser == '/' )
-        {
-            /* No access */
-            psz_access = "";
-            psz_parser++;
-        }
-        else
-        {
-            psz_access = psz_parser;
+    if( !p_sout )
+    {
+        msg_Err( p_this, "cannot find any stream ouput" );
+        return( NULL );
+    }
 
-            while( *psz_parser && *psz_parser != '/' )
-            {
-                psz_parser++;
-            }
+    msg_Dbg( p_sout, "adding a new input" );
 
-            if( *psz_parser == '/' )
-            {
-                *psz_parser++ = '\0';
-            }
-        }
+    /* *** create a packetizer input *** */
+    p_input         = malloc( sizeof( sout_packetizer_input_t ) );
+    p_input->p_sout = p_sout;
+    p_input->p_fmt  = p_fmt;
 
-        if( !*psz_parser )
-        {
-            /* No mux */
-            psz_mux = "";
-        }
-        else
-        {
-            psz_mux = psz_parser;
-        }
+    if( p_fmt->i_fourcc == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
+    {
+        vlc_object_release( p_sout );
+        return p_input;
     }
 
-    msg_Dbg( p_sout, "access `%s', mux `%s', name `%s'",
-             psz_access, psz_mux, psz_name );
-#endif
-
-    mrl_Parse( &mrl, psz_dest );
-    msg_Dbg( p_sout, "access `%s', mux `%s', name `%s'",
-             mrl.psz_access, mrl.psz_way, mrl.psz_name );
-
+    /* *** add it to the stream chain */
     vlc_mutex_lock( &p_sout->lock );
-    /* *** create mux *** */
-
-    if( InstanceMuxNew( p_sout, mrl.psz_way, mrl.psz_access, mrl.psz_name ) )
-    {
-        msg_Err( p_sout, "cannot create sout chain for %s/%s://%s",
-                 mrl.psz_access, mrl.psz_way, mrl.psz_name );
+    p_input->id = p_sout->p_stream->pf_add( p_sout->p_stream,
+                                            p_fmt );
+    vlc_mutex_unlock( &p_sout->lock );
 
-        mrl_Clean( &mrl );
-        vlc_mutex_unlock( &p_sout->lock );
-        return( VLC_EGENERIC );
-    }
-    mrl_Clean( &mrl );
+    vlc_object_release( p_sout );
 
-    /* *** finish all setup *** */
-    if( p_sout->psz_sout )
-    {
-        p_sout->psz_sout =
-            realloc( p_sout->psz_sout,
-                     strlen( p_sout->psz_sout ) +2+1+ strlen( psz_dest ) );
-        strcat( p_sout->psz_sout, "#" );
-        strcat( p_sout->psz_sout, psz_dest );
-    }
-    else
+    if( p_input->id == NULL )
     {
-        p_sout->psz_sout = strdup( psz_dest );
+        free( p_input );
+        return( NULL );
     }
-    psz_dup = strdup( psz_dest );
-    TAB_APPEND( p_sout->i_nb_dest, p_sout->ppsz_dest, psz_dup );
-    vlc_mutex_unlock( &p_sout->lock );
-
-    msg_Dbg( p_sout, "complete sout `%s'", p_sout->psz_sout );
 
-    return VLC_SUCCESS;
+    return( p_input );
 }
 
-static int      InstanceMuxNew      ( sout_instance_t *p_sout,
-                                      char *psz_mux, char *psz_access, char *psz_name )
+
+int sout_InputDelete( sout_packetizer_input_t *p_input )
 {
-    sout_access_out_t *p_access;
-    sout_mux_t        *p_mux;
+    sout_instance_t     *p_sout = p_input->p_sout;
+
+    msg_Dbg( p_sout, "removing an input" );
 
-    /* *** find and open appropriate access module *** */
-    p_access =
-        sout_AccessOutNew( p_sout, psz_access, psz_name );
-    if( p_access == NULL )
+    if( p_input->p_fmt->i_fourcc != VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
     {
-        msg_Err( p_sout, "no suitable sout access module for `%s/%s://%s'",
-                 psz_access, psz_mux, psz_name );
-        return( VLC_EGENERIC );
+        vlc_mutex_lock( &p_sout->lock );
+        p_sout->p_stream->pf_del( p_sout->p_stream, p_input->id );
+        vlc_mutex_unlock( &p_sout->lock );
     }
 
-    /* *** find and open appropriate mux module *** */
-    p_mux = MuxNew( p_sout, psz_mux, p_access );
-    if( p_mux == NULL )
-    {
-        msg_Err( p_sout, "no suitable sout mux module for `%s/%s://%s'",
-                 psz_access, psz_mux, psz_name );
+    free( p_input );
 
-        sout_AccessOutDelete( p_access );
-        return( VLC_EGENERIC );
-    }
+    return( VLC_SUCCESS);
+}
 
-    p_sout->i_preheader = __MAX( p_sout->i_preheader,
-                                 p_mux->i_preheader );
 
-    TAB_APPEND( p_sout->i_nb_mux, p_sout->pp_mux, p_mux );
+int sout_InputSendBuffer( sout_packetizer_input_t *p_input, sout_buffer_t *p_buffer )
+{
+    sout_instance_t     *p_sout = p_input->p_sout;
+
+    if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
+    {
+        sout_BufferDelete( p_input->p_sout, p_buffer );
+        return VLC_SUCCESS;
+    }
 
 
-    return VLC_SUCCESS;
+    return( p_sout->p_stream->pf_send( p_sout->p_stream, p_input->id, p_buffer ) );
 }
+
 /*****************************************************************************
  * sout_AccessOutNew: allocate a new access out
  *****************************************************************************/
@@ -501,43 +287,12 @@ int  sout_AccessOutWrite( sout_access_out_t *p_access, sout_buffer_t *p_buffer )
 }
 
 
-
-static sout_input_t *SoutInputCreate( sout_instance_t *p_sout,
-                                      sout_packet_format_t *p_format )
-{
-    sout_input_t *p_input;
-
-    p_input = malloc( sizeof( sout_input_t ) );
-
-    p_input->p_sout = p_sout;
-    memcpy( &p_input->input_format,
-            p_format,
-            sizeof( sout_packet_format_t ) );
-    p_input->p_fifo = sout_FifoCreate( p_sout );
-    p_input->p_sys = NULL;
-
-    return p_input;
-}
-
-static void SoutInputDestroy( sout_instance_t *p_sout,
-                              sout_input_t *p_input )
-{
-    sout_FifoDestroy( p_sout, p_input->p_fifo );
-    free( p_input );
-}
-
-/*****************************************************************************
- * Mux*: create/destroy/manipulate muxer.
- *  XXX: for now they are private, but I will near export them
- *       to allow muxer creating private muxer (ogg in avi, flexmux in ts/ps)
- *****************************************************************************/
-
 /*****************************************************************************
  * MuxNew: allocate a new mux
  *****************************************************************************/
-static sout_mux_t * MuxNew              ( sout_instance_t *p_sout,
-                                          char *psz_mux,
-                                          sout_access_out_t *p_access )
+sout_mux_t * sout_MuxNew         ( sout_instance_t *p_sout,
+                                   char *psz_mux,
+                                   sout_access_out_t *p_access )
 {
     sout_mux_t *p_mux;
 
@@ -605,7 +360,7 @@ static sout_mux_t * MuxNew              ( sout_instance_t *p_sout,
     return p_mux;
 }
 
-static void MuxDelete               ( sout_mux_t *p_mux )
+void sout_MuxDelete              ( sout_mux_t *p_mux )
 {
     if( p_mux->p_module )
     {
@@ -616,8 +371,8 @@ static void MuxDelete               ( sout_mux_t *p_mux )
     vlc_object_destroy( p_mux );
 }
 
-static sout_input_t *MuxAddStream   ( sout_mux_t *p_mux,
-                                      sout_packet_format_t *p_format )
+sout_input_t *sout_MuxAddStream( sout_mux_t *p_mux,
+                                 sout_format_t *p_fmt )
 {
     sout_input_t *p_input;
 
@@ -633,22 +388,27 @@ static sout_input_t *MuxAddStream   ( sout_mux_t *p_mux,
     }
 
     msg_Dbg( p_mux, "adding a new input" );
+
     /* create a new sout input */
-    p_input = SoutInputCreate( p_mux->p_sout, p_format );
+    p_input = malloc( sizeof( sout_input_t ) );
+    p_input->p_sout = p_mux->p_sout;
+    p_input->p_fmt  = p_fmt;
+    p_input->p_fifo = sout_FifoCreate( p_mux->p_sout );
+    p_input->p_sys  = NULL;
 
     TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
     if( p_mux->pf_addstream( p_mux, p_input ) < 0 )
     {
             msg_Err( p_mux, "cannot add this stream" );
-            MuxDeleteStream( p_mux, p_input );
+            sout_MuxDeleteStream( p_mux, p_input );
             return( NULL );
     }
 
     return( p_input );
 }
 
-static void MuxDeleteStream     ( sout_mux_t *p_mux,
-                                  sout_input_t *p_input )
+void sout_MuxDeleteStream     ( sout_mux_t *p_mux,
+                                sout_input_t *p_input )
 {
     int i_index;
 
@@ -668,13 +428,14 @@ static void MuxDeleteStream     ( sout_mux_t *p_mux,
             msg_Warn( p_mux, "no more input stream for this mux" );
         }
 
-        SoutInputDestroy( p_mux->p_sout, p_input );
+        sout_FifoDestroy( p_mux->p_sout, p_input->p_fifo );
+        free( p_input );
     }
 }
 
-static void MuxSendBuffer       ( sout_mux_t    *p_mux,
-                                  sout_input_t  *p_input,
-                                  sout_buffer_t *p_buffer )
+void sout_MuxSendBuffer       ( sout_mux_t    *p_mux,
+                                sout_input_t  *p_input,
+                                sout_buffer_t *p_buffer )
 {
     sout_FifoPut( p_input->p_fifo, p_buffer );
 
@@ -694,155 +455,7 @@ static void MuxSendBuffer       ( sout_mux_t    *p_mux,
     p_mux->pf_mux( p_mux );
 }
 
-/*****************************************************************************
- *
- *****************************************************************************/
-sout_packetizer_input_t *__sout_InputNew( vlc_object_t *p_this,
-                                          sout_packet_format_t *p_format )
-{
-    sout_instance_t         *p_sout = NULL;
-    sout_packetizer_input_t *p_input;
-    int             i_try;
-    int             i_mux;
-    vlc_bool_t      b_accepted = VLC_FALSE;
-
-    /* search an stream output */
-    for( i_try = 0; i_try < 12; i_try++ )
-    {
-        p_sout = vlc_object_find( p_this, VLC_OBJECT_SOUT, FIND_ANYWHERE );
-        if( !p_sout )
-        {
-            msleep( 100*1000 );
-            msg_Dbg( p_this, "waiting for sout" );
-        }
-        else
-        {
-            break;
-        }
-    }
-
-    if( !p_sout )
-    {
-        msg_Err( p_this, "cannot find any stream ouput" );
-        return( NULL );
-    }
-    msg_Dbg( p_sout, "adding a new input" );
-
-    /* *** create a packetizer input *** */
-    p_input = malloc( sizeof( sout_packetizer_input_t ) );
-    p_input->p_sout         = p_sout;
-    p_input->i_nb_inputs    = 0;
-    p_input->pp_inputs      = NULL;
-    p_input->i_nb_mux       = 0;
-    p_input->pp_mux         = NULL;
-    memcpy( &p_input->input_format,
-            p_format,
-            sizeof( sout_packet_format_t ) );
-
-    if( p_format->i_fourcc == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
-    {
-        vlc_object_release( p_sout );
-        return p_input;
-    }
-
-    vlc_mutex_lock( &p_sout->lock );
-    /* *** add this input to all muxers *** */
-    for( i_mux = 0; i_mux < p_sout->i_nb_mux; i_mux++ )
-    {
-        sout_input_t *p_mux_input;
-#define p_mux p_sout->pp_mux[i_mux]
-
-        p_mux_input = MuxAddStream( p_mux, p_format );
-        if( p_mux_input )
-        {
-            TAB_APPEND( p_input->i_nb_inputs, p_input->pp_inputs, p_mux_input );
-            TAB_APPEND( p_input->i_nb_mux,    p_input->pp_mux,    p_mux );
-
-            b_accepted = VLC_TRUE;
-        }
-#undef  p_mux
-    }
-
-    if( !b_accepted )
-    {
-        /* all muxer refuse this stream, so delete it */
-        free( p_input );
-
-        vlc_mutex_unlock( &p_sout->lock );
-        vlc_object_release( p_sout );
-        return( NULL );
-    }
-
-    TAB_APPEND( p_sout->i_nb_inputs, p_sout->pp_inputs, p_input );
-    vlc_mutex_unlock( &p_sout->lock );
-
-    vlc_object_release( p_sout );
-
-    return( p_input );
-}
-
-
-int sout_InputDelete( sout_packetizer_input_t *p_input )
-{
-    sout_instance_t     *p_sout = p_input->p_sout;
-    int                 i_input;
-
-    msg_Dbg( p_sout, "removing an input" );
-
-    vlc_mutex_lock( &p_sout->lock );
-
-    /* *** remove this input to all muxers *** */
-    for( i_input = 0; i_input < p_input->i_nb_inputs; i_input++ )
-    {
-        MuxDeleteStream( p_input->pp_mux[i_input], p_input->pp_inputs[i_input] );
-    }
-
-    TAB_REMOVE( p_sout->i_nb_inputs, p_sout->pp_inputs, p_input );
-
-    free( p_input->pp_inputs );
-    free( p_input->pp_mux );
-
-    free( p_input );
-
-    vlc_mutex_unlock( &p_sout->lock );
-    return( 0 );
-}
-
 
-int sout_InputSendBuffer( sout_packetizer_input_t *p_input, sout_buffer_t *p_buffer )
-{
-//    sout_instance_sys_t *p_sys = p_input->p_sout->p_sys;
-/*    msg_Dbg( p_input->p_sout,
-             "send buffer, size:%d", p_buffer->i_size ); */
-
-    if( p_input->input_format.i_fourcc != VLC_FOURCC( 'n', 'u', 'l', 'l' ) &&
-        p_input->i_nb_inputs > 0 )
-    {
-        int i;
-
-        vlc_mutex_lock( &p_input->p_sout->lock );
-        for( i = 0; i < p_input->i_nb_inputs - 1; i++ )
-        {
-            sout_buffer_t *p_dup;
-
-            p_dup = sout_BufferDuplicate( p_input->p_sout, p_buffer );
-
-            MuxSendBuffer( p_input->pp_mux[i],
-                           p_input->pp_inputs[i],
-                           p_dup );
-        }
-        MuxSendBuffer( p_input->pp_mux[p_input->i_nb_inputs-1],
-                       p_input->pp_inputs[p_input->i_nb_inputs-1],
-                       p_buffer );
-
-        vlc_mutex_unlock( &p_input->p_sout->lock );
-    }
-    else
-    {
-        sout_BufferDelete( p_input->p_sout, p_buffer );
-    }
-    return( 0 );
-}
 
 sout_fifo_t *sout_FifoCreate( sout_instance_t *p_sout )
 {
@@ -1085,78 +698,6 @@ void sout_BufferChain( sout_buffer_t **pp_chain,
     }
 }
 
-#if 0
-static int mrl_ParseOptions( mrl_option_t **pp_opt, char *psz_options )
-{
-    mrl_option_t **pp_last = pp_opt;
-
-    char *psz_parser = strdup( psz_options );
-
-    *pp_last = NULL;
-
-    if( *psz_parser == '=' )
-    {
-        free( psz_parser );
-        return( VLC_EGENERIC );
-    }
-    if( *psz_parser == '{' )
-    {
-        free( psz_parser );
-    }
-
-    for( ;; )
-    {
-        char *psz_end;
-        mrl_option_t opt;
-
-        /* skip space */
-        while( *psz_parser && ( *psz_parser == ' ' || *psz_parser == '\t' || *psz_parser == ';' ) )
-        {
-            psz_parser++;
-        }
-
-        if( ( psz_end = strchr( psz_parser, '=' ) ) != NULL )
-        {
-            opt.p_next = NULL;
-
-            while( psz_end > psz_parser && ( *psz_end == ' ' ||  *psz_end == '\t' ) )
-            {
-                psz_end--;
-            }
-
-            if( psz_end - psz_parser <= 0 )
-            {
-                return( VLC_EGENERIC );
-            }
-
-            *psz_end = '\0';
-            opt.psz_name = strdup( psz_parser );
-
-            psz_parser = psz_end + 1;
-            if( ( psz_end = strchr( psz_parser, ';' ) ) == NULL &&
-                ( psz_end = strchr( psz_parser, '}' ) ) == NULL )
-            {
-                psz_end = psz_parser + strlen( psz_parser ) + 1;
-            }
-
-            opt.psz_value = strdup( psz_parser );
-
-            fprintf( stderr, "option: name=`%s' value=`%s'\n",
-                     opt.psz_name,
-                     opt.psz_value );
-            psz_parser = psz_end + 1;
-
-            *pp_last = malloc( sizeof( mrl_option_t ) );
-            **pp_last = opt;
-        }
-        else
-        {
-            break;
-        }
-    }
-}
-#endif
-
 static int  mrl_Parse( mrl_t *p_mrl, char *psz_mrl )
 {
     char * psz_dup = strdup( psz_mrl );
@@ -1264,23 +805,6 @@ static int  mrl_Parse( mrl_t *p_mrl, char *psz_mrl )
         }
     }
 
-#if 0
-    if( ( psz_parser = strchr( psz_access, '{' ) ) != NULL )
-    {
-        mrl_ParseOptions( &p_mrl->p_access_options, psz_parser );
-        *psz_parser = '\0';
-    }
-
-    if( ( psz_parser = strchr( psz_way, '{' ) ) != NULL )
-    {
-        mrl_ParseOptions( &p_mrl->p_way_options, psz_parser );
-        *psz_parser = '\0';
-    }
-#endif
-
-    p_mrl->p_access_options = NULL;
-    p_mrl->p_way_options    = NULL;
-
     p_mrl->psz_access = strdup( psz_access );
     p_mrl->psz_way    = strdup( psz_way );
     p_mrl->psz_name   = strdup( psz_name );
@@ -1299,4 +823,332 @@ static void mrl_Clean( mrl_t *p_mrl )
 }
 
 
+/****************************************************************************
+ ****************************************************************************
+ **
+ **
+ **
+ ****************************************************************************
+ ****************************************************************************/
+
+/* create a complete chain */
+/* chain format:
+    module{option=*:option=*}[:module{option=*:...}]
+ */
+
+static char *_strndup( char *str, int i_len )
+{
+    char *p;
+
+    p = malloc( i_len + 1 );
+    strncpy( p, str, i_len );
+    p[i_len] = '\0';
+
+    return( p );
+}
+
+/*
+ * parse module{options=str, option="str "}:
+ *  return a pointer on the rest
+ *  XXX: psz_chain is modified
+ */
+#define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
+/* go accross " " and { } */
+static char *_get_chain_end( char *str )
+{
+    char *p = str;
+
+    SKIPSPACE( p );
+
+    for( ;; )
+    {
+        if( *p == '{' || *p == '"' || *p == '\'')
+        {
+            char c;
+
+            if( *p == '{' )
+            {
+                c = '}';
+            }
+            else
+            {
+                c = *p;
+            }
+            p++;
+
+            for( ;; )
+            {
+                if( *p == '\0' )
+                {
+                    return p;
+                }
+
+                if( *p == c )
+                {
+                    p++;
+                    return p;
+                }
+                else if( *p == '{' && c == '}' )
+                {
+                    p = _get_chain_end( p );
+                }
+                else
+                {
+                    p++;
+                }
+            }
+        }
+        else if( *p == '\0' || *p == ',' || *p == '}' || *p == ' ' || *p == '\t' )
+        {
+            return p;
+        }
+        else
+        {
+            p++;
+        }
+    }
+}
+
+char * sout_cfg_parser( char **ppsz_name, sout_cfg_t **pp_cfg, char *psz_chain )
+{
+    sout_cfg_t *p_cfg = NULL;
+    char       *p = psz_chain;
+
+    *ppsz_name = NULL;
+    *pp_cfg    = NULL;
+
+    SKIPSPACE( p );
+
+    while( *p && *p != '{' && *p != ':' && *p != ' ' && *p != '\t' )
+    {
+        p++;
+    }
+
+    if( p == psz_chain )
+    {
+        return NULL;
+    }
+
+    *ppsz_name = _strndup( psz_chain, p - psz_chain );
+
+    //fprintf( stderr, "name=%s - rest=%s\n", *ppsz_name, p );
+
+    SKIPSPACE( p );
+
+    if( *p == '{' )
+    {
+        char *psz_name;
+
+        p++;
+
+        for( ;; )
+        {
+            sout_cfg_t cfg;
+
+            SKIPSPACE( p );
+
+            psz_name = p;
+
+            while( *p && *p != '=' && *p != ',' && *p != '}' && *p != ' ' && *p != '\t' )
+            {
+                p++;
+            }
+
+            //fprintf( stderr, "name=%s - rest=%s\n", psz_name, p );
+            if( p == psz_name )
+            {
+                fprintf( stderr, "invalid options (empty)" );
+                break;
+            }
+
+            cfg.psz_name = _strndup( psz_name, p - psz_name );
+
+            SKIPSPACE( p );
+
+            if( *p == '=' )
+            {
+                char *end;
+
+                p++;
+#if 0
+                SKIPSPACE( p );
+
+                if( *p == '"' )
+                {
+                    char *end;
+
+                    p++;
+                    end = strchr( p, '"' );
+
+                    if( end )
+                    {
+//                        fprintf( stderr, "##%s -- %s\n", p, end );
+                        cfg.psz_value = _strndup( p, end - p );
+                        p = end + 1;
+                    }
+                    else
+                    {
+                        cfg.psz_value = strdup( p );
+                        p += strlen( p );
+                    }
+
+                }
+                else
+                {
+                    psz_value = p;
+                    while( *p && *p != ',' && *p != '}' && *p != ' ' && *p != '\t' )
+                    {
+                        p++;
+                    }
+                    cfg.psz_value = _strndup( psz_value, p - psz_value );
+                }
+#endif
+                end = _get_chain_end( p );
+                if( end <= p )
+                {
+                    cfg.psz_value = NULL;
+                }
+                else
+                {
+                    if( *p == '\'' || *p =='"' || *p == '{' )
+                    {
+                        p++;
+                        end--;
+                    }
+                    if( end <= p )
+                    {
+                        cfg.psz_value = NULL;
+                    }
+                    else
+                    {
+                        cfg.psz_value = _strndup( p, end - p );
+                    }
+                }
+
+                p = end;
+                SKIPSPACE( p );
+            }
+            else
+            {
+                cfg.psz_value = NULL;
+            }
+
+            cfg.p_next = NULL;
+            if( p_cfg )
+            {
+                p_cfg->p_next = malloc( sizeof( sout_cfg_t ) );
+                memcpy( p_cfg->p_next, &cfg, sizeof( sout_cfg_t ) );
+
+                p_cfg = p_cfg->p_next;
+            }
+            else
+            {
+                p_cfg = malloc( sizeof( sout_cfg_t ) );
+                memcpy( p_cfg, &cfg, sizeof( sout_cfg_t ) );
+
+                *pp_cfg = p_cfg;
+            }
+
+            if( *p == ',' )
+            {
+                p++;
+            }
+
+            if( *p == '}' )
+            {
+                p++;
+
+                break;
+            }
+        }
+    }
+
+    if( *p == ':' )
+    {
+        return( strdup( p + 1 ) );
+    }
+
+    return( NULL );
+}
+
+
+
+
+
+/*
+ * XXX name and p_cfg are used (-> do NOT free them)
+ */
+sout_stream_t *sout_stream_new( sout_instance_t *p_sout,
+                                char *psz_chain )
+{
+    sout_stream_t *p_stream;
+
+    p_stream = vlc_object_create( p_sout, sizeof( sout_stream_t ) );
+
+    if( !p_stream )
+    {
+        msg_Err( p_sout, "out of memory" );
+        return NULL;
+    }
+
+    p_stream->p_sout   = p_sout;
+    p_stream->p_sys    = NULL;
+
+    p_stream->psz_next = sout_cfg_parser( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
+    msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
+
+    p_stream->p_module =
+        module_Need( p_stream, "sout stream", p_stream->psz_name );
+
+    if( !p_stream->p_module )
+    {
+        /* FIXME */
+        vlc_object_destroy( p_stream );
+        return NULL;
+    }
+
+    return p_stream;
+}
+
+void sout_stream_delete( sout_stream_t *p_stream )
+{
+    sout_cfg_t *p_cfg;
+
+    msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
+    module_Unneed( p_stream, p_stream->p_module );
+
+    FREE( p_stream->psz_name );
+    FREE( p_stream->psz_next );
+
+    p_cfg = p_stream->p_cfg;
+    while( p_cfg != NULL )
+    {
+        sout_cfg_t *p_next;
+
+        p_next = p_cfg->p_next;
+
+        FREE( p_cfg->psz_name );
+        FREE( p_cfg->psz_value );
+        free( p_cfg );
+
+        p_cfg = p_next;
+    }
+
+    msg_Dbg( p_stream, "destroying chain done" );
+    vlc_object_destroy( p_stream );
+}
+
+static char *sout_stream_chain_to_str( char *psz_url )
+{
+    mrl_t mrl;
+    char *psz_chain;
+
+    mrl_Parse( &mrl, psz_url );
+
+    psz_chain = malloc( 100 + strlen( mrl.psz_way ) + strlen( mrl.psz_access ) + strlen( mrl.psz_name ) );
+
+    sprintf( psz_chain, "std{mux=%s,access=%s,url=\"%s\"", mrl.psz_way, mrl.psz_access, mrl.psz_name );
+
+    return( psz_chain );
+}