]> git.sesse.net Git - vlc/commitdiff
Added stream output. (common work with titer).
authorLaurent Aimar <fenrir@videolan.org>
Sat, 14 Dec 2002 21:32:42 +0000 (21:32 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Sat, 14 Dec 2002 21:32:42 +0000 (21:32 +0000)
29 files changed:
configure.ac.in
include/stream_output.h
include/vlc_common.h
modules/Makefile.am
modules/access_output/.cvsignore [new file with mode: 0644]
modules/access_output/Modules.am [new file with mode: 0644]
modules/access_output/dummy.c [new file with mode: 0644]
modules/access_output/file.c [new file with mode: 0644]
modules/access_output/udp.c [new file with mode: 0644]
modules/mux/.cvsignore [new file with mode: 0644]
modules/mux/Modules.am [new file with mode: 0644]
modules/mux/dummy.c [new file with mode: 0644]
modules/mux/mpeg/.cvsignore [new file with mode: 0644]
modules/mux/mpeg/Modules.am [new file with mode: 0644]
modules/mux/mpeg/bits.h [new file with mode: 0644]
modules/mux/mpeg/pes.c [new file with mode: 0644]
modules/mux/mpeg/pes.h [new file with mode: 0644]
modules/mux/mpeg/ps.c [new file with mode: 0644]
modules/mux/mpeg/ts.c [new file with mode: 0644]
modules/packetizer/.cvsignore [new file with mode: 0644]
modules/packetizer/Modules.am [new file with mode: 0644]
modules/packetizer/a52.c [new file with mode: 0644]
modules/packetizer/copy.c [new file with mode: 0644]
modules/packetizer/mpeg4video.c [new file with mode: 0644]
modules/packetizer/mpegaudio.c [new file with mode: 0644]
modules/packetizer/mpegvideo.c [new file with mode: 0644]
src/input/input_dec.c
src/libvlc.h
src/stream_output/stream_output.c

index bcb502a897c80ae182d45c40fd9b9e4edba59681..4f8ba3a447ee1a50d6c6e87ae498818dcc21142c 100644 (file)
@@ -135,6 +135,7 @@ case "x${target_os}" in
         LDFLAGS_access_mms="${LDFLAGS_access_mms} -lws2_32"
         LDFLAGS_access_rtp="${LDFLAGS_access_rtp} -lws2_32"
         LDFLAGS_access_udp="${LDFLAGS_access_udp} -lws2_32"
+        LDFLAGS_access_output_udp="${LDFLAGS_access_output_udp} -lws2_32"
         LDFLAGS_rc="${LDFLAGS_rc} -lws2_32"
         LDFLAGS_sap="${LDFLAGS_sap} -lws2_32"
     fi
@@ -273,6 +274,7 @@ AC_CHECK_FUNC(send,,[
     LDFLAGS_access_rtp="${LDFLAGS_access_rtp} -lsocket"
     LDFLAGS_access_udp="${LDFLAGS_access_udp} -lsocket"
     LDFLAGS_sap="${LDFLAGS_sap} -lsocket"
+    LDFLAGS_access_output_udp="${LDFLAGS_access_output_udp} -lsocket"
 )])
 
 AC_CHECK_FUNC(gethostbyname,,[
@@ -865,6 +867,20 @@ AC_ARG_ENABLE(release,
 [  --enable-release        activate extra optimizations (default disabled)])
 AM_CONDITIONAL(RELEASE, test "x${enable_release}" = "xyes")
 
+dnl
+dnl Stream output
+dnl
+AC_ARG_ENABLE(sout,
+  [  --enable-sout           Stream output modules (default enabled)])
+if test "x${enable_sout}" != "xno"
+then
+  PLUGINS="${PLUGINS} access_output_dummy access_output_udp access_output_file"
+  PLUGINS="${PLUGINS} mux_ts mux_ps mux_dummy"
+  PLUGINS="${PLUGINS} packetizer_mpegaudio packetizer_mpegvideo packetizer_a52"
+  PLUGINS="${PLUGINS} packetizer_mpeg4video packetizer_copy"
+fi
+
+
 dnl
 dnl  Input plugins
 dnl
index 64c707671a3de7ddd9b13cfb206ec01fb8ad9178..6ace36070f794aeb5d636b85b6a669cdbdcdf305 100644 (file)
@@ -2,15 +2,17 @@
  * stream_output.h : stream output module
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: stream_output.h,v 1.1 2002/08/12 22:12:50 massiot Exp $
+ * $Id: stream_output.h,v 1.2 2002/12/14 21:32:41 fenrir Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
+ *          Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
  *
  * 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
 /*****************************************************************************
  * sout_instance_t: stream output thread descriptor
  *****************************************************************************/
+
+struct sout_buffer_t
+{
+    size_t                  i_allocated_size;
+    byte_t                  *p_buffer;
+
+    size_t                  i_size;
+//    mtime_t                 i_date;
+    mtime_t                 i_length;
+
+    mtime_t                 i_dts;
+    mtime_t                 i_pts;
+
+    int                     i_bitrate;
+
+    struct sout_buffer_t    *p_next;
+};
+
+struct sout_packet_format_t
+{
+    int             i_cat;      // AUDIO_ES, VIDEO_ES, SPU_ES
+    vlc_fourcc_t    i_fourcc;
+
+    void            *p_format;  // WAVEFORMATEX or BITMAPINFOHEADER
+
+};
+
+struct sout_fifo_t
+{
+    vlc_mutex_t         lock;                         /* fifo data lock */
+    vlc_cond_t          wait;         /* fifo data conditional variable */
+
+    int                 i_depth;
+    sout_buffer_t       *p_first;
+    sout_buffer_t       **pp_last;
+};
+
+struct sout_input_t
+{
+    vlc_mutex_t             lock;
+
+    sout_instance_t         *p_sout;
+
+    sout_packet_format_t    input_format;
+    sout_fifo_t             *p_fifo;
+
+    void                    *p_mux_data;
+};
+
+#define SOUT_METHOD_NONE        0x00
+#define SOUT_METHOD_FILE        0x10
+#define SOUT_METHOD_NETWORK     0x20
+
 struct sout_instance_t
 {
     VLC_COMMON_MEMBERS
@@ -33,10 +88,30 @@ struct sout_instance_t
     char * psz_mux;
     char * psz_name;
 
-    module_t * p_access;
-    module_t * p_mux;
+    module_t                *p_access;
+    int                     i_method;
+    void                    *p_access_data;
+    int                     (* pf_write )( sout_instance_t *, sout_buffer_t * );
+    int                     (* pf_seek  )( sout_instance_t *, off_t );
+
+    module_t                *p_mux;
+    void                    *p_mux_data;
+    int                     (* pf_mux_addstream )( sout_instance_t *,
+                                                   sout_input_t * );
+    int                     (* pf_mux_delstream )( sout_instance_t *,
+                                                   sout_input_t * );
+    int                     (* pf_mux )          ( sout_instance_t * );
+
+
+    vlc_mutex_t             lock;
+
+    int                     i_nb_inputs;
+    sout_input_t            **pp_inputs;
 };
 
+
+
+
 /*****************************************************************************
  * Prototypes
  *****************************************************************************/
@@ -44,7 +119,21 @@ struct sout_instance_t
 VLC_EXPORT( sout_instance_t *, __sout_NewInstance,  ( vlc_object_t *, char * ) );
 VLC_EXPORT( void,              sout_DeleteInstance, ( sout_instance_t * ) );
 
-sout_fifo_t *   sout_CreateFifo     ( void );
-void            sout_DestroyFifo    ( sout_fifo_t * );
-void            sout_FreeFifo       ( sout_fifo_t * );
+VLC_EXPORT( sout_fifo_t *,   sout_FifoCreate,     ( sout_instance_t * ) );
+VLC_EXPORT( void,            sout_FifoDestroy,    ( sout_instance_t *, sout_fifo_t * ) );
+VLC_EXPORT( void,            sout_FifoFree,       ( sout_instance_t *,sout_fifo_t * ) );
+
+VLC_EXPORT( void,            sout_FifoPut,        ( sout_fifo_t *, sout_buffer_t* ) );
+VLC_EXPORT( sout_buffer_t *, sout_FifoGet,        ( sout_fifo_t * ) );
+VLC_EXPORT( sout_buffer_t *, sout_FifoShow,       ( sout_fifo_t * ) );
+
+
+#define sout_InputNew( a, b ) __sout_InputNew( VLC_OBJECT(a), b )
+VLC_EXPORT( sout_input_t *, __sout_InputNew,       ( vlc_object_t *, sout_packet_format_t * ) );
+VLC_EXPORT( int,            sout_InputDelete,      ( sout_input_t * ) );
+VLC_EXPORT( int,            sout_InputSendBuffer,  ( sout_input_t *, sout_buffer_t* ) );
 
+VLC_EXPORT( sout_buffer_t*, sout_BufferNew,    ( sout_instance_t *, size_t ) );
+VLC_EXPORT( int,            sout_BufferRealloc,( sout_instance_t *, sout_buffer_t*, size_t ) );
+VLC_EXPORT( int,            sout_BufferDelete, ( sout_instance_t *, sout_buffer_t* ) );
+VLC_EXPORT( sout_buffer_t*, sout_BufferDuplicate,(sout_instance_t *, sout_buffer_t * ) );
index cb5017a1b753104897568490cdfc989a60fc9a36..2cd46cd6d3deec5b66154d9b4e62a227c819c920 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.43 2002/12/13 01:56:29 gbazin Exp $
+ * $Id: vlc_common.h,v 1.44 2002/12/14 21:32:41 fenrir Exp $
  *
  * Authors: Samuel Hocevar <sam@via.ecp.fr>
  *          Vincent Seguin <seguin@via.ecp.fr>
@@ -241,6 +241,9 @@ typedef struct subpicture_sys_t subpicture_sys_t;
 /* Stream output */
 typedef struct sout_instance_t sout_instance_t;
 typedef struct sout_fifo_t sout_fifo_t;
+typedef struct sout_input_t sout_input_t;
+typedef struct sout_buffer_t sout_buffer_t;
+typedef struct sout_packet_format_t sout_packet_format_t;
 
 /* Decoders */
 typedef struct decoder_fifo_t decoder_fifo_t;
index f55e9835f082713e924e659cf5f1cc434a9ddacf..e353ab57be440a13391ce97849d4fd77333a1c38 100644 (file)
@@ -8,6 +8,7 @@ EXTRA_DIST = \
        access/satellite/Modules.am \
        access/v4l/Modules.am \
        access/vcd/Modules.am \
+       access_output/Modules.am \
        audio_filter/channel_mixer/Modules.am \
        audio_filter/converter/Modules.am \
        audio_filter/resampler/Modules.am \
@@ -53,6 +54,9 @@ EXTRA_DIST = \
        misc/memcpy/Modules.am \
        misc/network/Modules.am \
        misc/testsuite/Modules.am \
+       mux/Modules.am \
+       mux/mpeg/Modules.am \
+       packetizer/Modules.am \
        video_chroma/Modules.am \
        video_filter/Modules.am \
        video_filter/deinterlace/Modules.am \
diff --git a/modules/access_output/.cvsignore b/modules/access_output/.cvsignore
new file mode 100644 (file)
index 0000000..ec96903
--- /dev/null
@@ -0,0 +1,2 @@
+.deps
+.dirstamp
diff --git a/modules/access_output/Modules.am b/modules/access_output/Modules.am
new file mode 100644 (file)
index 0000000..4fcabbb
--- /dev/null
@@ -0,0 +1,3 @@
+SOURCES_access_output_dummy = modules/access_output/dummy.c
+SOURCES_access_output_file = modules/access_output/file.c
+SOURCES_access_output_udp = modules/access_output/udp.c
diff --git a/modules/access_output/dummy.c b/modules/access_output/dummy.c
new file mode 100644 (file)
index 0000000..9fb3808
--- /dev/null
@@ -0,0 +1,121 @@
+/*****************************************************************************
+ * dummy.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: dummy.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#ifdef HAVE_UNISTD_H
+#   include <unistd.h>
+#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE )
+#   include <io.h>
+#endif
+
+/*****************************************************************************
+ * Exported prototypes
+ *****************************************************************************/
+static int     Open   ( vlc_object_t * );
+static void    Close  ( vlc_object_t * );
+
+static int     Write( sout_instance_t *, sout_buffer_t * );
+static int     Seek( sout_instance_t *, off_t  );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("Dummy stream ouput") );
+    set_capability( "sout access", 0 );
+    add_shortcut( "dummy" );
+    set_callbacks( Open, Close );
+vlc_module_end();
+
+
+/*****************************************************************************
+ * Open: open the file
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    sout_instance_t     *p_sout = (sout_instance_t*)p_this;
+
+    p_sout->i_method        = SOUT_METHOD_NONE;
+    p_sout->p_access_data   = NULL;
+    p_sout->pf_write        = Write;
+    p_sout->pf_seek         = Seek;
+
+    msg_Info( p_sout, "dummy stream output access launched" );
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close: close the target
+ *****************************************************************************/
+static void Close( vlc_object_t * p_this )
+{
+    sout_instance_t     *p_sout = (sout_instance_t*)p_this;
+    msg_Info( p_sout, "Close" );
+}
+
+/*****************************************************************************
+ * Read: standard read on a file descriptor.
+ *****************************************************************************/
+static int Write( sout_instance_t *p_sout, sout_buffer_t *p_buffer )
+{
+    size_t i_write = 0;
+
+    do
+    {
+        sout_buffer_t *p_next;
+        i_write += p_buffer->i_size;
+        p_next = p_buffer->p_next;
+        sout_BufferDelete( p_sout, p_buffer );
+        p_buffer = p_next;
+    } while( p_buffer );
+
+    msg_Dbg( p_sout, "Dummy Skipped: len:%d", (uint32_t)i_write );
+
+    return( i_write );
+}
+
+/*****************************************************************************
+ * Seek: seek to a specific location in a file
+ *****************************************************************************/
+static int Seek( sout_instance_t *p_sout, off_t i_pos )
+{
+    msg_Dbg( p_sout, "Seek: pos:%lld", (int64_t)i_pos );
+    return( 0 );
+}
+
+
+
diff --git a/modules/access_output/file.c b/modules/access_output/file.c
new file mode 100644 (file)
index 0000000..caf3729
--- /dev/null
@@ -0,0 +1,151 @@
+/*****************************************************************************
+ * file.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: file.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#ifdef HAVE_UNISTD_H
+#   include <unistd.h>
+#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE )
+#   include <io.h>
+#endif
+
+/*****************************************************************************
+ * Exported prototypes
+ *****************************************************************************/
+static int     Open   ( vlc_object_t * );
+static void    Close  ( vlc_object_t * );
+
+static int     Write( sout_instance_t *, sout_buffer_t * );
+static int     Seek( sout_instance_t *, off_t  );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("File stream ouput") );
+    set_capability( "sout access", 50 );
+    add_shortcut( "file" );
+    set_callbacks( Open, Close );
+vlc_module_end();
+
+typedef struct sout_access_data_s
+{
+    FILE *p_file;
+
+} sout_access_data_t;
+
+/*****************************************************************************
+ * Open: open the file
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    sout_instance_t     *p_sout = (sout_instance_t*)p_this;
+    sout_access_data_t  *p_access;
+    char *              psz_name = p_sout->psz_name;
+
+    p_access = malloc( sizeof( sout_access_data_t ) );
+
+    if( !( p_access->p_file = fopen( psz_name, "wb" ) ) )
+    {
+        msg_Err( p_sout, "cannot open `%s'", psz_name );
+        free( p_access );
+        return( -1 );
+    }
+
+    p_sout->i_method        = SOUT_METHOD_FILE;
+    p_sout->p_access_data   = p_access;
+    p_sout->pf_write        = Write;
+    p_sout->pf_seek         = Seek;
+
+    msg_Info( p_sout, "Open: name:`%s'", psz_name );
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close: close the target
+ *****************************************************************************/
+static void Close( vlc_object_t * p_this )
+{
+    sout_instance_t     *p_sout = (sout_instance_t*)p_this;
+    sout_access_data_t  *p_access = (sout_access_data_t*)p_sout->p_access_data;
+
+    if( p_access->p_file )
+    {
+        fclose( p_access->p_file );
+    }
+
+    msg_Info( p_sout, "Close" );
+}
+
+/*****************************************************************************
+ * Read: standard read on a file descriptor.
+ *****************************************************************************/
+static int Write( sout_instance_t *p_sout, sout_buffer_t *p_buffer )
+{
+    sout_access_data_t  *p_access = (sout_access_data_t*)p_sout->p_access_data;
+    size_t i_write = 0;
+
+    do
+    {
+        sout_buffer_t *p_next;
+
+        i_write += fwrite( p_buffer->p_buffer, 1, p_buffer->i_size,
+                           p_access->p_file );
+        p_next = p_buffer->p_next;
+        sout_BufferDelete( p_sout, p_buffer );
+        p_buffer = p_next;
+
+    } while( p_buffer );
+
+    msg_Dbg( p_sout, "Write: len:%d", (uint32_t)i_write );
+
+    return( i_write );
+}
+
+/*****************************************************************************
+ * Seek: seek to a specific location in a file
+ *****************************************************************************/
+static int Seek( sout_instance_t *p_sout, off_t i_pos )
+{
+
+    sout_access_data_t  *p_access = (sout_access_data_t*)p_sout->p_access_data;
+
+    msg_Dbg( p_sout, "Seek: pos:%lld", (int64_t)i_pos );
+    return( fseek( p_access->p_file, i_pos, SEEK_SET ) );
+}
+
+
+
diff --git a/modules/access_output/udp.c b/modules/access_output/udp.c
new file mode 100644 (file)
index 0000000..0be0c6f
--- /dev/null
@@ -0,0 +1,398 @@
+/*****************************************************************************
+ * udp.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: udp.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#ifdef HAVE_UNISTD_H
+#   include <unistd.h>
+#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE )
+#   include <io.h>
+#endif
+
+#ifdef WIN32
+#   include <winsock2.h>
+#   include <ws2tcpip.h>
+#   ifndef IN_MULTICAST
+#       define IN_MULTICAST(a) IN_CLASSD(a)
+#   endif
+#else
+#   include <sys/socket.h>
+#endif
+
+#include "network.h"
+
+#define DEFAULT_PORT 1234
+#define LATENCY     100000
+#define MAX_ERROR    500000
+/*****************************************************************************
+ * Exported prototypes
+ *****************************************************************************/
+static int     Open   ( vlc_object_t * );
+static void    Close  ( vlc_object_t * );
+
+static int     Write( sout_instance_t *, sout_buffer_t * );
+static int     Seek( sout_instance_t *, off_t  );
+
+static void    ThreadWrite( vlc_object_t *p_this );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("UDP stream ouput") );
+    set_capability( "sout access", 100 );
+    add_shortcut( "udp" );
+    add_shortcut( "rtp" ); // Will work only with ts muxer
+    set_callbacks( Open, Close );
+vlc_module_end();
+
+typedef struct sout_access_thread_s
+{
+    VLC_COMMON_MEMBERS
+
+    sout_instance_t *p_sout;
+
+    sout_fifo_t *p_fifo;
+
+    int         i_handle;
+
+} sout_access_thread_t;
+
+typedef struct sout_access_data_s
+{
+    int                 b_rtpts;  // 1 if add rtp/ts header
+    uint16_t            i_sequence_number;
+    uint32_t            i_ssrc;
+
+    int                 i_mtu;
+
+    sout_buffer_t       *p_buffer;
+
+    sout_access_thread_t *p_thread;
+
+} sout_access_data_t;
+
+/*****************************************************************************
+ * Open: open the file
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    sout_instance_t     *p_sout = (sout_instance_t*)p_this;
+    sout_access_data_t  *p_access;
+
+    char                *psz_parser;
+    char                *psz_dst_addr;
+    int                 i_dst_port;
+
+    module_t            *p_network;
+    network_socket_t    socket_desc;
+
+    if( !( p_access = malloc( sizeof( sout_access_data_t ) ) ) )
+    {
+        msg_Err( p_sout, "Not enough memory" );
+        return( -1 );
+    }
+
+    if( p_sout->psz_access != NULL &&
+        !strcmp( p_sout->psz_access, "rtp" ) )
+    {
+         if( p_sout->psz_mux != NULL &&
+            strcmp( p_sout->psz_mux, "ts" ) )
+        {
+            msg_Err( p_sout, "rtp ouput work only with ts payload" );
+            free( p_access );
+            return( -1 );
+        }
+        p_access->b_rtpts = 1;
+    }
+    else
+    {
+        p_access->b_rtpts = 0;
+    }
+
+    psz_parser = strdup( p_sout->psz_name );
+
+    psz_dst_addr = psz_parser;
+    i_dst_port = 0;
+
+    while( *psz_parser && *psz_parser != ':' )
+    {
+        psz_parser++;
+    }
+    if( *psz_parser == ':' )
+    {
+        *psz_parser = '\0';
+        psz_parser++;
+        i_dst_port = atoi( psz_parser );
+    }
+    if( i_dst_port <= 0 )
+    {
+        i_dst_port = DEFAULT_PORT;
+    }
+
+    p_access->p_thread = vlc_object_create( p_sout,
+                                            sizeof( sout_access_thread_t ) );
+    if( !p_access->p_thread )
+    {
+        msg_Err( p_sout, "out of memory" );
+        return( -1 );
+    }
+
+    p_access->p_thread->p_sout = p_sout;
+    p_access->p_thread->b_die  = 0;
+    p_access->p_thread->b_error= 0;
+    p_access->p_thread->p_fifo = sout_FifoCreate( p_sout );
+
+    socket_desc.i_type = NETWORK_UDP;
+    socket_desc.psz_server_addr = psz_dst_addr;
+    socket_desc.i_server_port   = i_dst_port;
+    socket_desc.psz_bind_addr   = "";
+    socket_desc.i_bind_port     = 0;
+    p_access->p_thread->p_private = (void*)&socket_desc;
+    if( !( p_network = module_Need( p_access->p_thread, 
+                                    "network", "" ) ) )
+    {
+        msg_Err( p_sout, "failed to open a connection (udp)" );
+        return( -1 );
+    }
+    module_Unneed( p_access->p_thread, p_network );
+
+    p_access->p_thread->i_handle = socket_desc.i_handle;
+    p_access->i_mtu     = socket_desc.i_mtu;
+
+    if( vlc_thread_create( p_access->p_thread, "sout write thread",
+                           ThreadWrite, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
+    {
+        msg_Err( p_sout, "cannot spawn sout access thread" );
+        vlc_object_destroy( p_access->p_thread );
+        return( -1 );
+    }
+
+    p_access->p_buffer  = NULL;
+    p_access->i_sequence_number = 12;   // FIXME should be random, used by rtp
+    p_access->i_ssrc            = 4212; // FIXME   "    "    "       "  "   "
+
+    p_sout->i_method        = SOUT_METHOD_NETWORK;
+    p_sout->p_access_data   = (void*)p_access;
+    p_sout->pf_write        = Write;
+    p_sout->pf_seek         = Seek;
+
+    msg_Info( p_sout,
+              "Open: addr:`%s' port:`%d'",
+              psz_dst_addr, i_dst_port );
+
+    free( psz_dst_addr );
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close: close the target
+ *****************************************************************************/
+static void Close( vlc_object_t * p_this )
+{
+    sout_instance_t     *p_sout = (sout_instance_t*)p_this;
+    sout_access_data_t  *p_access = (sout_access_data_t*)p_sout->p_access_data;
+    int                 i;
+
+    p_access->p_thread->b_die = 1;
+    for( i = 0; i < 10; i++ )
+    {
+        sout_buffer_t       *p_dummy;
+
+        p_dummy = sout_BufferNew( p_sout, p_access->i_mtu );
+        p_dummy->i_dts = 0;
+        p_dummy->i_pts = 0;
+        p_dummy->i_length = 0;
+        sout_FifoPut( p_access->p_thread->p_fifo, p_dummy );
+    }
+    vlc_thread_join( p_access->p_thread );
+
+    sout_FifoDestroy( p_sout, p_access->p_thread->p_fifo );
+
+    if( p_access->p_buffer )
+    {
+        sout_BufferDelete( p_sout, p_access->p_buffer );
+    }
+
+#if defined( UNDER_CE )
+    CloseHandle( (HANDLE)p_access->p_thread->i_handle );
+#elif defined( WIN32 )
+    closesocket( p_access->p_thread->i_handle );
+#else
+    close( p_access->p_thread->i_handle );
+#endif
+    msg_Info( p_sout, "Close" );
+}
+
+/*****************************************************************************
+ * Read: standard read on a file descriptor.
+ *****************************************************************************/
+static int Write( sout_instance_t *p_sout, sout_buffer_t *p_buffer )
+{
+    sout_access_data_t  *p_access = (sout_access_data_t*)p_sout->p_access_data;
+    int i_write;
+
+    while( p_buffer )
+    {
+        sout_buffer_t *p_next;
+        if( p_buffer->i_size > p_access->i_mtu )
+        {
+            msg_Warn( p_sout, "arggggggggggggg packet size > mtu" );
+            i_write = p_access->i_mtu;
+        }
+        else
+        {
+            i_write = p_buffer->i_size;
+        }
+
+        /* if we have enough data, enque the buffer */
+        if( p_access->p_buffer &&
+            p_access->p_buffer->i_size + i_write > p_access->i_mtu )
+        {
+            sout_FifoPut( p_access->p_thread->p_fifo, p_access->p_buffer );
+            p_access->p_buffer = NULL;
+        }
+
+        if( !p_access->p_buffer )
+        {
+            p_access->p_buffer = sout_BufferNew( p_sout, p_access->i_mtu );
+            p_access->p_buffer->i_dts = p_buffer->i_dts;
+            p_access->p_buffer->i_size = 0;
+            if( p_access->b_rtpts )
+            {
+                mtime_t i_timestamp = p_access->p_buffer->i_dts * 9 / 100;
+
+                /* add rtp/ts header */
+                p_access->p_buffer->p_buffer[0] = 0x80;
+                p_access->p_buffer->p_buffer[1] = 0x21; // mpeg2-ts
+                p_access->p_buffer->p_buffer[2] =
+                    ( p_access->i_sequence_number >> 8 )&0xff;
+                p_access->p_buffer->p_buffer[3] =
+                    p_access->i_sequence_number&0xff;
+
+                p_access->p_buffer->p_buffer[4] = ( i_timestamp >> 24 )&0xff;
+                p_access->p_buffer->p_buffer[5] = ( i_timestamp >> 16 )&0xff;
+                p_access->p_buffer->p_buffer[6] = ( i_timestamp >>  8 )&0xff;
+                p_access->p_buffer->p_buffer[7] = i_timestamp&0xff;
+
+                p_access->p_buffer->p_buffer[ 8] =
+                    ( p_access->i_ssrc >> 24 )&0xff;
+                p_access->p_buffer->p_buffer[ 9] =
+                    ( p_access->i_ssrc >> 16 )&0xff;
+                p_access->p_buffer->p_buffer[10] =
+                    ( p_access->i_ssrc >>  8 )&0xff;
+                p_access->p_buffer->p_buffer[11] = p_access->i_ssrc&0xff;
+
+                p_access->p_buffer->i_size = 12;
+            }
+        }
+
+
+        if( p_buffer->i_size > 0 )
+        {
+            memcpy( p_access->p_buffer->p_buffer + p_access->p_buffer->i_size,
+                    p_buffer->p_buffer,
+                    i_write );
+            p_access->p_buffer->i_size += i_write;
+        }
+        p_next = p_buffer->p_next;
+        sout_BufferDelete( p_sout, p_buffer );
+        p_buffer = p_next;
+    }
+
+    return( p_access->p_thread->b_error ? -1 : 0 );
+}
+
+/*****************************************************************************
+ * Seek: seek to a specific location in a file
+ *****************************************************************************/
+static int Seek( sout_instance_t *p_sout, off_t i_pos )
+{
+
+    msg_Err( p_sout, "udp sout access cannot seek" );
+    return( -1 );
+}
+
+/*****************************************************************************
+ * ThreadWrite: Write a packet on the network at the good time.
+ *****************************************************************************/
+static void ThreadWrite( vlc_object_t *p_this )
+{
+    sout_access_thread_t *p_thread = (sout_access_thread_t*)p_this;
+    sout_instance_t      *p_sout = p_thread->p_sout;
+    sout_buffer_t *p_buffer;
+    mtime_t       i_date;
+
+    while( !p_thread->b_die && p_thread->p_fifo->i_depth < 5 )
+    {
+        msleep( 10000 );
+    }
+    if( p_thread->b_die )
+    {
+        return;
+    }
+    p_buffer = sout_FifoShow( p_thread->p_fifo );
+    i_date = mdate() - p_buffer->i_dts;
+
+    for( ;; )
+    {
+        mtime_t i_wait;
+
+        p_buffer = sout_FifoGet( p_thread->p_fifo );
+
+        if( p_thread->b_die )
+        {
+            return;
+        }
+        i_wait = i_date + p_buffer->i_dts;
+        mwait( i_wait );
+
+        if( i_wait - mdate() > MAX_ERROR ||
+            i_wait - mdate() < -MAX_ERROR )
+        {
+            msg_Warn( p_sout, "resetting clock" );
+            i_date = mdate() - p_buffer->i_dts;
+        }
+        send( p_thread->i_handle,
+              p_buffer->p_buffer,
+              p_buffer->i_size,
+              0 );
+
+        sout_BufferDelete( p_sout, p_buffer );
+    }
+}
+
+
diff --git a/modules/mux/.cvsignore b/modules/mux/.cvsignore
new file mode 100644 (file)
index 0000000..ec96903
--- /dev/null
@@ -0,0 +1,2 @@
+.deps
+.dirstamp
diff --git a/modules/mux/Modules.am b/modules/mux/Modules.am
new file mode 100644 (file)
index 0000000..b750e61
--- /dev/null
@@ -0,0 +1 @@
+SOURCES_mux_dummy = modules/mux/dummy.c
diff --git a/modules/mux/dummy.c b/modules/mux/dummy.c
new file mode 100644 (file)
index 0000000..adbdb1b
--- /dev/null
@@ -0,0 +1,131 @@
+/*****************************************************************************
+ * dummy.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: dummy.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#ifdef HAVE_UNISTD_H
+#   include <unistd.h>
+#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE )
+#   include <io.h>
+#endif
+
+#include "codecs.h"
+
+/*****************************************************************************
+ * Exported prototypes
+ *****************************************************************************/
+static int     Open   ( vlc_object_t * );
+static void    Close  ( vlc_object_t * );
+
+static int AddStream( sout_instance_t *, sout_input_t * );
+static int DelStream( sout_instance_t *, sout_input_t * );
+static int Mux      ( sout_instance_t * );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("Dummy muxer") );
+    set_capability( "sout mux", 5 );
+    add_shortcut( "dummy" );
+    set_callbacks( Open, Close );
+vlc_module_end();
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    sout_instance_t     *p_sout = (sout_instance_t*)p_this;
+
+    msg_Info( p_sout, "Open" );
+
+    p_sout->pf_mux_addstream = AddStream;
+    p_sout->pf_mux_delstream = DelStream;
+    p_sout->pf_mux           = Mux;
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close:
+ *****************************************************************************/
+
+static void Close( vlc_object_t * p_this )
+{
+    sout_instance_t     *p_sout = (sout_instance_t*)p_this;
+    msg_Info( p_sout, "Close" );
+}
+
+
+static int AddStream( sout_instance_t *p_sout, sout_input_t *p_input )
+{
+    msg_Dbg( p_sout, "adding input" );
+    return( 0 );
+}
+
+static int DelStream( sout_instance_t *p_sout, sout_input_t *p_input )
+{
+
+    msg_Dbg( p_sout, "removing input" );
+    return( 0 );
+}
+
+static int Mux      ( sout_instance_t *p_sout )
+{
+    int i;
+    for( i = 0; i < p_sout->i_nb_inputs; i++ )
+    {
+        int i_count;
+        sout_fifo_t *p_fifo;
+
+        p_fifo = p_sout->pp_inputs[i]->p_fifo;
+        i_count = p_fifo->i_depth;
+        while( i_count > 0 )
+        {
+            sout_buffer_t *p_data;
+
+            p_data = sout_FifoGet( p_fifo );
+
+            p_sout->pf_write( p_sout, p_data );
+
+            i_count--;
+        }
+
+    }
+    return( 0 );
+}
+
diff --git a/modules/mux/mpeg/.cvsignore b/modules/mux/mpeg/.cvsignore
new file mode 100644 (file)
index 0000000..ec96903
--- /dev/null
@@ -0,0 +1,2 @@
+.deps
+.dirstamp
diff --git a/modules/mux/mpeg/Modules.am b/modules/mux/mpeg/Modules.am
new file mode 100644 (file)
index 0000000..b64b6df
--- /dev/null
@@ -0,0 +1,12 @@
+SOURCES_mux_ps = modules/mux/mpeg/ps.c \
+                 modules/mux/mpeg/pes.c \
+                 modules/mux/mpeg/pes.h \
+                 modules/mux/mpeg/bits.h \
+                 $(NULL)
+SOURCES_mux_ts = modules/mux/mpeg/ts.c \
+                 modules/mux/mpeg/pes.c \
+                 modules/mux/mpeg/pes.h \
+                 modules/mux/mpeg/bits.h \
+                 $(NULL)
+
+
diff --git a/modules/mux/mpeg/bits.h b/modules/mux/mpeg/bits.h
new file mode 100644 (file)
index 0000000..2a0c253
--- /dev/null
@@ -0,0 +1,93 @@
+/*****************************************************************************
+ * bits.h
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: bits.h,v 1.1 2002/12/14 21:32:41 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+typedef struct bits_buffer_s
+{
+    int     i_size;
+
+    int     i_data;
+    uint8_t i_mask;
+    uint8_t *p_data;
+
+} bits_buffer_t;
+static inline int bits_initwrite( bits_buffer_t *p_buffer, 
+                                  int i_size, void *p_data )
+{
+    p_buffer->i_size = i_size;
+    p_buffer->i_data = 0;
+    p_buffer->i_mask = 0x80;
+    p_buffer->p_data = p_data;
+    p_buffer->p_data[0] = 0;
+    if( !p_buffer->p_data )
+    {   
+        if( !( p_buffer->p_data = malloc( i_size ) ) )
+        {        
+            return( -1 );
+        }
+        else
+        {
+            return( 0 );
+        }
+    }
+    else
+    {
+        return( 0 );
+    }
+}
+
+static inline void bits_align( bits_buffer_t *p_buffer )
+{
+    if( p_buffer->i_mask != 0x80 && p_buffer->i_data < p_buffer->i_size )
+    {
+        p_buffer->i_mask = 0x80;
+        p_buffer->i_data++;
+        p_buffer->p_data[p_buffer->i_data] = 0x00;
+    }
+}
+
+static inline void bits_write( bits_buffer_t *p_buffer, 
+                               int i_count, uint64_t i_bits )
+{
+    while( i_count > 0 )
+    {
+        if( i_bits &  ( 1 << ( i_count - 1 ) ) )
+        {
+            p_buffer->p_data[p_buffer->i_data] |= p_buffer->i_mask;
+        }
+        p_buffer->i_mask >>= 1;
+        if( p_buffer->i_mask == 0 )
+        {
+            p_buffer->i_data++;
+            if( p_buffer->i_data < p_buffer->i_size )
+            {
+                p_buffer->p_data[p_buffer->i_data] = 0;
+                p_buffer->i_mask = 0x80;
+            }
+        }
+        i_count--;
+    }
+}
+
+
diff --git a/modules/mux/mpeg/pes.c b/modules/mux/mpeg/pes.c
new file mode 100644 (file)
index 0000000..f34f721
--- /dev/null
@@ -0,0 +1,208 @@
+/*****************************************************************************
+ * pes.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: pes.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#ifdef HAVE_UNISTD_H
+#   include <unistd.h>
+#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE )
+#   include <io.h>
+#endif
+
+#include "codecs.h"
+#include "pes.h"
+#include "bits.h"
+
+int EStoPES( sout_instance_t *p_sout,
+             sout_buffer_t **pp_pes,
+             sout_buffer_t *p_es,
+             int i_stream_id,
+             int b_mpeg2 )
+{
+    sout_buffer_t *p_pes;
+    bits_buffer_t bits;
+    mtime_t i_pts, i_dts;
+    uint8_t *p_data;
+    int     i_size;
+
+    i_pts = p_es->i_pts * 9 / 100; // 90000 units clock
+    i_dts = p_es->i_dts * 9 / 100; // 90000 units clock
+
+    i_size = p_es->i_size;
+    p_data = p_es->p_buffer;
+
+    *pp_pes = p_pes = NULL;
+
+    do
+    {
+        int     i_copy;
+
+        i_copy = __MIN( i_size, 65500 );
+
+        if( *pp_pes == NULL )
+        {
+            *pp_pes = p_pes = sout_BufferNew( p_sout, 100 + i_copy);
+            p_pes->i_dts = p_es->i_dts;
+            p_pes->i_pts = p_es->i_pts;
+            p_pes->i_length = p_es->i_length;
+        }
+        else
+        {
+            p_pes->p_next = sout_BufferNew( p_sout, 100 + i_copy );
+            p_pes = p_pes->p_next;
+
+            p_pes->i_dts    = 0;
+            p_pes->i_pts    = 0;
+            p_pes->i_length = 0;
+        }
+
+        p_pes->i_size = 0;
+
+
+        bits_initwrite( &bits, 100, p_pes->p_buffer );
+
+        /* first 4 bytes common pes header */
+            /* add start code for pes 0x000001 */
+        bits_write( &bits, 24, 0x01 );
+            /* add stream id */
+        bits_write( &bits, 8, i_stream_id );
+
+        switch( i_stream_id )
+        {
+            case PES_PROGRAM_STREAM_MAP:
+            case PES_PADDING:
+            case PES_PRIVATE_STREAM_2:
+            case PES_ECM:
+            case PES_EMM:
+            case PES_PROGRAM_STREAM_DIRECTORY:
+            case PES_DSMCC_STREAM:
+            case PES_ITU_T_H222_1_TYPE_E_STREAM:
+                /* add pes data size  */
+                bits_write( &bits, 16, i_copy );
+                bits_align( &bits );
+                break;
+
+            default:
+                /* arg, a little more difficult */
+                if( b_mpeg2 )
+                {
+                    int     i_pts_dts;
+
+                    if( i_dts > 0 )
+                    {
+                        bits_write( &bits, 16, i_copy  + 13 );
+                        i_pts_dts = 0x03;
+                    }
+                    else
+                    {
+                        bits_write( &bits, 16, i_copy  + 8 );
+                        i_pts_dts = 0x02;
+                    }
+
+                    bits_write( &bits, 2, 0x02 ); // mpeg2 id
+                    bits_write( &bits, 2, 0x00 ); // pes scrambling control
+                    bits_write( &bits, 1, 0x00 ); // pes priority
+                    bits_write( &bits, 1, 0x00 ); // data alignement indicator
+                    bits_write( &bits, 1, 0x00 ); // copyright
+                    bits_write( &bits, 1, 0x00 ); // original or copy
+
+                    bits_write( &bits, 2, i_pts_dts ); // pts_dts flags
+                    bits_write( &bits, 1, 0x00 ); // escr flags
+                    bits_write( &bits, 1, 0x00 ); // es rate flag
+                    bits_write( &bits, 1, 0x00 ); // dsm trick mode flag
+                    bits_write( &bits, 1, 0x00 ); // additional copy info flag
+                    bits_write( &bits, 1, 0x00 ); // pes crc flag
+                    bits_write( &bits, 1, 0x00 ); // pes extention flags
+                    if( i_pts_dts & 0x01 )
+                    {
+                        bits_write( &bits, 8, 0x0a ); // header size -> pts and dts
+                    }
+                    else
+                    {
+                        bits_write( &bits, 8, 0x05 ); // header size -> pts
+                    }
+
+                    /* write pts */
+                    bits_write( &bits, 4, i_pts_dts ); // '0010' or '0011'
+                    bits_write( &bits, 3, i_pts >> 30 );
+                    bits_write( &bits, 1, 0x01 ); // marker
+                    bits_write( &bits, 15, i_pts >> 15 );
+                    bits_write( &bits, 1, 0x01 ); // marker
+                    bits_write( &bits, 15, i_pts );
+                    bits_write( &bits, 1, 0x01 ); // marker
+
+                    /* write i_dts */
+                    if( i_pts_dts & 0x01 )
+                    {
+                        bits_write( &bits, 4, 0x01 ); // '0001'
+                        bits_write( &bits, 3, i_dts >> 30 );
+                        bits_write( &bits, 1, 0x01 ); // marker
+                        bits_write( &bits, 15, i_dts >> 15 );
+                        bits_write( &bits, 1, 0x01 ); // marker
+                        bits_write( &bits, 15, i_dts );
+                        bits_write( &bits, 1, 0x01 ); // marker
+
+                        i_dts = 0; // write dts only once
+                    }
+
+                }
+                else
+                {
+                    msg_Warn( p_sout, "es isn't mpeg2 -->corrupted pes" );
+                }
+                /* now should be stuffing */
+                /* and then pes data */
+
+                bits_align( &bits );
+                break;
+        }
+
+        if( i_copy > 0 )
+        {
+            memcpy( p_pes->p_buffer + bits.i_data, p_data, i_copy );
+        }
+
+        i_size -= i_copy;
+        p_data += i_copy;
+        p_pes->i_size = bits.i_data + i_copy;
+
+
+    } while( i_size > 0 );
+
+    sout_BufferDelete( p_sout, p_es );
+    return( 0 );
+}
+
diff --git a/modules/mux/mpeg/pes.h b/modules/mux/mpeg/pes.h
new file mode 100644 (file)
index 0000000..7c6e8bd
--- /dev/null
@@ -0,0 +1,38 @@
+/*****************************************************************************
+ * pes.h
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: pes.h,v 1.1 2002/12/14 21:32:41 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+
+
+#define PES_PROGRAM_STREAM_MAP          0xbc
+#define PES_PADDING                     0xbe
+#define PES_PRIVATE_STREAM_2            0xbf
+#define PES_ECM                         0xb0
+#define PES_EMM                         0xb1
+#define PES_PROGRAM_STREAM_DIRECTORY    0xff
+#define PES_DSMCC_STREAM                0xf2
+#define PES_ITU_T_H222_1_TYPE_E_STREAM  0xf8
+
+
+int EStoPES( sout_instance_t *p_sout,
+             sout_buffer_t **pp_pes, sout_buffer_t *p_es, 
+             int i_stream_id, int b_mpeg2 );
diff --git a/modules/mux/mpeg/ps.c b/modules/mux/mpeg/ps.c
new file mode 100644 (file)
index 0000000..620cf08
--- /dev/null
@@ -0,0 +1,361 @@
+/*****************************************************************************
+ * ps.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: ps.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
+ *
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#ifdef HAVE_UNISTD_H
+#   include <unistd.h>
+#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE )
+#   include <io.h>
+#endif
+
+#include "codecs.h"
+#include "bits.h"
+#include "pes.h"
+
+/*****************************************************************************
+ * Exported prototypes
+ *****************************************************************************/
+static int     Open   ( vlc_object_t * );
+static void    Close  ( vlc_object_t * );
+
+static int AddStream( sout_instance_t *, sout_input_t * );
+static int DelStream( sout_instance_t *, sout_input_t * );
+static int Mux      ( sout_instance_t * );
+
+static void SetWBE ( uint8_t *p, uint16_t v )
+{
+    p[0] = ( v >> 8 )&0xff;
+    p[1] = v&0xff;
+}
+static void SetDWBE( uint8_t *p, uint32_t v )
+{
+    SetWBE( p,    ( v >> 16 )&0xffff );
+    SetWBE( p + 2,  v & 0xffff );
+}
+#define ADD_DWBE( p_buff, v ) \
+    SetDWBE( (p_buff)->p_buffer + i_buffer, (v) ); \
+    i_buffer +=4;
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("PS muxer") );
+    set_capability( "sout mux", 50 );
+    add_shortcut( "ps" );
+    set_callbacks( Open, Close );
+vlc_module_end();
+
+typedef struct ps_stream_s
+{
+    int             i_ok;
+
+    int             i_stream_id;
+
+} ps_stream_t;
+
+typedef struct sout_mux_s
+{
+
+    int         i_stream_id_mpga;
+    int         i_stream_id_mpgv;
+    int         i_stream_id_a52;
+
+    int         i_audio_bound;
+    int         i_video_bound;
+
+    int         i_pes_count;
+
+    int         i_system_header;
+} sout_mux_t;
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    sout_instance_t     *p_sout = (sout_instance_t*)p_this;
+    sout_mux_t          *p_mux;
+
+    msg_Info( p_sout, "Open" );
+
+    p_mux = malloc( sizeof( sout_mux_t ) );
+
+    p_sout->pf_mux_addstream = AddStream;
+    p_sout->pf_mux_delstream = DelStream;
+    p_sout->pf_mux           = Mux;
+    p_sout->p_mux_data       = (void*)p_mux;
+
+    p_mux->i_stream_id_mpga = 0xc0;
+    p_mux->i_stream_id_a52  = 0x80;
+    p_mux->i_stream_id_mpgv = 0xe0;
+    p_mux->i_audio_bound = 0;
+    p_mux->i_video_bound = 0;
+    p_mux->i_system_header = 0;
+    p_mux->i_pes_count = 0;
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close:
+ *****************************************************************************/
+
+static void Close( vlc_object_t * p_this )
+{
+    sout_instance_t     *p_sout = (sout_instance_t*)p_this;
+    sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
+    sout_buffer_t       *p_end;
+
+    msg_Info( p_sout, "Close" );
+
+    p_end = sout_BufferNew( p_sout, 4 );
+    SetDWBE( p_end->p_buffer, 0x01b9 );
+
+    p_sout->pf_write( p_sout, p_end );
+
+    free( p_mux );
+
+    p_sout->p_mux_data = NULL;
+}
+
+
+static int AddStream( sout_instance_t *p_sout, sout_input_t *p_input )
+{
+    sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
+    ps_stream_t         *p_stream;
+
+    msg_Dbg( p_sout, "adding input", p_sout );
+    p_input->p_mux_data = (void*)p_stream = malloc( sizeof( ps_stream_t ) );
+    p_stream->i_ok = 0;
+    switch( p_input->input_format.i_cat )
+    {
+        case VIDEO_ES:
+            p_stream->i_stream_id = p_mux->i_stream_id_mpgv;
+            p_mux->i_stream_id_mpgv++;
+            p_mux->i_video_bound++;
+            break;
+        case AUDIO_ES:
+            if( p_input->input_format.i_fourcc == VLC_FOURCC( 'a', '5', '2', ' ' ) )
+            {
+                p_stream->i_stream_id = p_mux->i_stream_id_a52;
+                p_mux->i_stream_id_a52++;
+            }
+            else
+            {
+                p_stream->i_stream_id = p_mux->i_stream_id_mpga;
+                p_mux->i_stream_id_mpga++;
+            }
+            p_mux->i_audio_bound++;
+            break;
+        default:
+            return( -1 );
+    }
+
+    p_stream->i_ok = 1;
+    msg_Dbg( p_sout, "adding input stream_id:0x%x [OK]", p_stream->i_stream_id, p_sout );
+    return( 0 );
+}
+
+static int DelStream( sout_instance_t *p_sout, sout_input_t *p_input )
+{
+    ps_stream_t         *p_stream =(ps_stream_t*)p_input->p_mux_data;
+
+    msg_Dbg( p_sout, "removing input" );
+    if( p_stream )
+    {
+        free( p_stream );
+    }
+    return( 0 );
+}
+
+static int MuxWritePackHeader( sout_instance_t *p_sout,
+                               mtime_t         i_dts )
+{
+    sout_buffer_t   *p_hdr;
+    bits_buffer_t   bits;
+    mtime_t         i_src;
+
+    i_src = i_dts * 9 / 100;
+
+    p_hdr = sout_BufferNew( p_sout, 18 );
+    bits_initwrite( &bits, 14, p_hdr->p_buffer );
+    bits_write( &bits, 32, 0x01ba );
+    bits_write( &bits, 2, 0x01 );       // FIXME ??
+    bits_write( &bits, 3, ( i_src >> 30 )&0x07 );
+    bits_write( &bits, 1,  1 );
+    bits_write( &bits, 15, ( i_src >> 15 )&0x7fff );
+    bits_write( &bits, 1,  1 );
+    bits_write( &bits, 15, i_src&0x7fff );
+    bits_write( &bits, 1,  1 );
+
+    bits_write( &bits, 9,  0 ); // src extention
+    bits_write( &bits, 1,  1 );
+
+    bits_write( &bits, 22,  0/8/50); // FIXME
+    bits_write( &bits, 1,  1 );
+    bits_write( &bits, 1,  1 );
+    bits_write( &bits, 5,  0x1f );  // FIXME reserved
+    bits_write( &bits, 3,  0 );     // stuffing bytes
+    p_hdr->i_size = 14;
+    p_sout->pf_write( p_sout, p_hdr );
+
+    return( 0 );
+}
+
+static int MuxWriteSystemHeader( sout_instance_t *p_sout )
+{
+    sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
+    sout_buffer_t   *p_hdr;
+    bits_buffer_t   bits;
+
+    p_hdr = sout_BufferNew( p_sout, 12 );
+
+    bits_initwrite( &bits, 12, p_hdr->p_buffer );
+    bits_write( &bits, 32, 0x01bb );
+    bits_write( &bits, 16, 12 - 6);
+    bits_write( &bits, 1,  1 );
+    bits_write( &bits, 22, 0 ); // FIXME rate bound
+    bits_write( &bits, 1,  1 );
+
+    bits_write( &bits, 6,  p_mux->i_audio_bound );
+    bits_write( &bits, 1,  0 ); // fixed flag
+    bits_write( &bits, 1,  0 ); // CSPS flag
+    bits_write( &bits, 1,  0 ); // system audio lock flag
+    bits_write( &bits, 1,  0 ); // system video lock flag
+
+    bits_write( &bits, 1,  1 ); // marker bit
+
+    bits_write( &bits, 5,  p_mux->i_video_bound );
+    bits_write( &bits, 1,  0 ); // packet rate restriction flag
+    bits_write( &bits, 7,  0x7f ); // reserved bits
+
+    /* FIXME missing stream_id ... */
+
+    p_sout->pf_write( p_sout, p_hdr );
+
+    return( 0 );
+}
+
+/* return stream number to be muxed */
+static int MuxGetStream( sout_instance_t *p_sout, 
+                         int        *pi_stream, 
+                         mtime_t    *pi_dts )
+{
+    mtime_t i_dts;
+    int     i_stream;
+    int     i;
+
+    for( i = 0, i_dts = 0, i_stream = -1; i < p_sout->i_nb_inputs; i++ )
+    {
+        sout_fifo_t  *p_fifo;
+
+        p_fifo = p_sout->pp_inputs[i]->p_fifo;
+
+        if( p_fifo->i_depth > 1 )
+        {
+            sout_buffer_t *p_buf;
+
+            p_buf = sout_FifoShow( p_fifo );
+            if( i_stream < 0 || p_buf->i_dts < i_dts )
+            {
+                i_dts = p_buf->i_dts;
+                i_stream = i;
+            }
+        }
+        else
+        {
+            return( -1 ); // wait that all fifo have at least 2 packets
+        }
+    }
+
+    if( pi_stream )
+    {
+        *pi_stream = i_stream;
+    }
+    if( pi_dts )
+    {
+        *pi_dts = i_dts;
+    }
+
+    return( i_stream );
+}
+
+
+static int Mux      ( sout_instance_t *p_sout )
+{
+    sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
+    mtime_t i_dts;
+    int     i_stream;
+
+    for( ;; )
+    {
+        sout_input_t *p_input;
+        ps_stream_t *p_stream;
+        sout_fifo_t  *p_fifo;
+        sout_buffer_t *p_data;
+
+        if( MuxGetStream( p_sout, &i_stream, &i_dts ) < 0 )
+        {
+            return( 0 );
+        }
+
+        p_input = p_sout->pp_inputs[i_stream];
+        p_fifo = p_input->p_fifo;
+        p_stream = (ps_stream_t*)p_input->p_mux_data;
+
+        if( p_mux->i_pes_count % 30 == 0)
+        {
+            MuxWritePackHeader( p_sout, i_dts );
+        }
+
+        if( p_mux->i_pes_count % 300 == 0 )
+        {
+//            MuxWriteSystemHeader( p_sout );
+        }
+
+        p_data = sout_FifoGet( p_fifo );
+        EStoPES( p_sout, &p_data, p_data, p_stream->i_stream_id, 1);
+        p_sout->pf_write( p_sout, p_data );
+
+        p_mux->i_pes_count++;
+
+    }
+    return( 0 );
+}
+
diff --git a/modules/mux/mpeg/ts.c b/modules/mux/mpeg/ts.c
new file mode 100644 (file)
index 0000000..e672e9a
--- /dev/null
@@ -0,0 +1,599 @@
+/*****************************************************************************
+ * ts.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: ts.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
+ *
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#ifdef HAVE_UNISTD_H
+#   include <unistd.h>
+#elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE )
+#   include <io.h>
+#endif
+
+#include "codecs.h"
+#include "bits.h"
+#include "pes.h"
+
+typedef struct ts_stream_s
+{
+    int             i_pid;
+    int             i_stream_type;
+    int             i_stream_id;
+    int             i_continuity_counter;
+} ts_stream_t;
+
+typedef struct sout_mux_s
+{
+    int             i_pcr_pid;
+    int             i_stream_id_mpga;
+    int             i_stream_id_mpgv;
+    int             i_stream_id_a52;
+
+    int             i_audio_bound;
+    int             i_video_bound;
+
+    int             i_pid_free; // first usable pid
+
+    int             i_pat_version_number;
+    ts_stream_t     pat;
+
+    int             i_pmt_version_number;
+    ts_stream_t     pmt;        // Up to now only one program
+
+    int             i_ts_packet;// To known when to put pat/mpt
+} sout_mux_t;
+
+
+/*****************************************************************************
+ * Exported prototypes
+ *****************************************************************************/
+static int     Open   ( vlc_object_t * );
+static void    Close  ( vlc_object_t * );
+
+static int     AddStream( sout_instance_t *, sout_input_t * );
+static int     DelStream( sout_instance_t *, sout_input_t * );
+static int     Mux      ( sout_instance_t * );
+
+/* Reserve a pid and return it */
+static int     AllocatePID( sout_mux_t *p_mux )
+{
+    return( ++p_mux->i_pid_free );
+}
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("TS muxer") );
+    set_capability( "sout mux", 100 );
+    add_shortcut( "ts" );
+    set_callbacks( Open, Close );
+vlc_module_end();
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    sout_instance_t     *p_sout = (sout_instance_t*)p_this;
+    sout_mux_t          *p_mux;
+
+    msg_Info( p_sout, "Open" );
+
+    p_mux = malloc( sizeof( sout_mux_t ) );
+
+    p_sout->pf_mux_addstream = AddStream;
+    p_sout->pf_mux_delstream = DelStream;
+    p_sout->pf_mux           = Mux;
+    p_sout->p_mux_data       = (void*)p_mux;
+
+    p_mux->i_stream_id_mpga = 0xc0;
+    p_mux->i_stream_id_a52  = 0x80;
+    p_mux->i_stream_id_mpgv = 0xe0;
+
+    p_mux->i_audio_bound = 0;
+    p_mux->i_video_bound = 0;
+
+    p_mux->i_pat_version_number = 0;
+    p_mux->pat.i_pid = 0;
+    p_mux->pat.i_continuity_counter = 0;
+
+    p_mux->i_pmt_version_number = 0;
+    p_mux->pmt.i_pid = 0x10;
+    p_mux->pmt.i_continuity_counter = 0;
+
+    p_mux->i_pid_free = 0x11;
+    p_mux->i_pcr_pid = 0x1fff;
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close:
+ *****************************************************************************/
+
+static void Close( vlc_object_t * p_this )
+{
+    sout_instance_t     *p_sout = (sout_instance_t*)p_this;
+    sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
+
+    msg_Info( p_sout, "Close" );
+
+    free( p_mux );
+    p_sout->p_mux_data = NULL;
+}
+
+
+static int AddStream( sout_instance_t *p_sout, sout_input_t *p_input )
+{
+    sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
+    ts_stream_t         *p_stream;
+
+    msg_Dbg( p_sout, "adding input" );
+    p_input->p_mux_data = (void*)p_stream = malloc( sizeof( ts_stream_t ) );
+
+    p_stream->i_pid = AllocatePID( p_mux );
+    if( p_mux->i_pcr_pid == 0x1fff )
+    {
+        p_mux->i_pcr_pid = p_stream->i_pid;
+    }
+    p_stream->i_continuity_counter = 0;
+
+    switch( p_input->input_format.i_cat )
+    {
+        case VIDEO_ES:
+            switch( p_input->input_format.i_fourcc )
+            {
+                case VLC_FOURCC( 'm', 'p','g', 'v' ):
+                    p_stream->i_stream_type = 0x02;
+                    p_stream->i_stream_id = p_mux->i_stream_id_mpgv;
+                    p_mux->i_stream_id_mpgv++;
+                    break;
+                case VLC_FOURCC( 'm', 'p','4', 'v' ):
+                    p_stream->i_stream_type = 0x10;
+                    p_stream->i_stream_id = 0xfa;
+                    break;
+                default:
+                    return( -1 );
+            }
+            p_mux->i_video_bound++;
+
+            break;
+        case AUDIO_ES:
+            switch( p_input->input_format.i_fourcc )
+            {
+                case VLC_FOURCC( 'a', '5','2', ' ' ):
+                case VLC_FOURCC( 'a', '5','2', 'b' ):
+                    p_stream->i_stream_type = 0x81;
+                    p_stream->i_stream_id = p_mux->i_stream_id_a52;
+                    p_mux->i_stream_id_a52++;
+                    break;
+#if 0
+                case VLC_FOURCC( 'm', 'p','4', 'a' ):
+                    p_stream->i_stream_type = 0x11;
+                    p_stream->i_stream_id = 0xfa;
+                    p_mux->i_stream_id_mp4a++;
+                    break;
+#endif
+                case VLC_FOURCC( 'm', 'p','g', 'a' ):
+                    p_stream->i_stream_type = 0x04;
+                    p_stream->i_stream_id = p_mux->i_stream_id_mpga;
+                    p_mux->i_stream_id_mpga++;
+                    break;
+                default:
+                    return( -1 );
+            }
+            p_mux->i_audio_bound++;
+            break;
+        default:
+            return( -1 );
+    }
+
+    p_mux->i_ts_packet = 0; // force pat/pmt recreation
+    p_mux->i_pat_version_number++; p_mux->i_pat_version_number %= 32;
+    p_mux->i_pmt_version_number++; p_mux->i_pmt_version_number %= 32;
+
+    return( 0 );
+}
+
+static int DelStream( sout_instance_t *p_sout, sout_input_t *p_input )
+{
+    sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
+
+    msg_Dbg( p_sout, "removing input" );
+    p_mux->i_ts_packet = 0; // force pat/pmt recreation
+    p_mux->i_pat_version_number++; p_mux->i_pat_version_number %= 32;
+    p_mux->i_pmt_version_number++; p_mux->i_pmt_version_number %= 32;
+
+    return( 0 );
+}
+
+
+
+static int MuxGetStream( sout_instance_t *p_sout,
+                         int        *pi_stream,
+                         mtime_t    *pi_dts )
+{
+    mtime_t i_dts;
+    int     i_stream;
+    int     i;
+
+    for( i = 0, i_dts = 0, i_stream = -1; i < p_sout->i_nb_inputs; i++ )
+    {
+        sout_fifo_t  *p_fifo;
+
+        p_fifo = p_sout->pp_inputs[i]->p_fifo;
+
+        if( p_fifo->i_depth > 1 )
+        {
+            sout_buffer_t *p_buf;
+
+            p_buf = sout_FifoShow( p_fifo );
+            if( i_stream < 0 || p_buf->i_dts < i_dts )
+            {
+                i_dts = p_buf->i_dts;
+                i_stream = i;
+            }
+        }
+        else
+        {
+            return( -1 ); // wait that all fifo have at least 2 packets
+        }
+    }
+
+    if( pi_stream )
+    {
+        *pi_stream = i_stream;
+    }
+    if( pi_dts )
+    {
+        *pi_dts = i_dts;
+    }
+
+    return( i_stream );
+}
+
+static int PEStoTS( sout_instance_t *p_sout,
+                    sout_buffer_t **pp_ts, sout_buffer_t *p_pes,
+                    ts_stream_t *p_stream )
+{
+    int i_size;
+    sout_buffer_t *p_last_buffer = NULL;
+    uint8_t       *p_data;
+    int i_first;
+    mtime_t       i_dts;
+    int         b_new_pes;
+    /* get PES total size */
+    i_size = p_pes->i_size;
+    p_data = p_pes->p_buffer;
+
+    if( p_pes->i_dts == 0 && p_pes->i_length > 0 )
+    {
+        i_dts = 1; // XXX <french> kludge immonde </french>
+    }
+    else
+    {
+        i_dts = p_pes->i_dts;
+    }
+
+    for( i_first = 1, b_new_pes = 1; p_pes != NULL; )
+    {
+        int           i_adaptation_field;
+        int           i_payload;
+        int           i_copy;
+        bits_buffer_t bits;
+        sout_buffer_t *p_ts;
+
+        p_ts = sout_BufferNew( p_sout, 188 );
+
+        p_ts->i_pts = 0;
+        p_ts->i_dts = i_dts;
+
+
+        i_payload = 184 - ( i_first && i_dts > 0 ? 8 : 0 );
+        i_copy = __MIN( i_size, i_payload );
+
+        i_adaptation_field = ( ( i_first && i_dts > 0 ) || 
+                               i_size < i_payload ) ? 1 : 0;
+
+        /* write headers */
+        bits_initwrite( &bits, 188, p_ts->p_buffer );
+        bits_write( &bits, 8, 0x47 ); /* sync byte */
+        bits_write( &bits, 1, 0 ); /* transport_error_indicator */
+        bits_write( &bits, 1, b_new_pes ? 1 : 0 ); /* payload_unit_start */
+        b_new_pes = 0;
+        bits_write( &bits, 1, 0 ); /* transport_priority */
+        bits_write( &bits, 13, p_stream->i_pid );
+        bits_write( &bits, 2, 0 ); /* transport_scrambling_control */
+        bits_write( &bits, 2, ( i_adaptation_field ? 0x03 : 0x01 ) );
+
+        bits_write( &bits, 4, /* continuity_counter */
+                    p_stream->i_continuity_counter );
+        p_stream->i_continuity_counter++;
+        p_stream->i_continuity_counter %= 16;
+        if( i_adaptation_field )
+        {
+            int i;
+            int i_stuffing;
+
+            if( i_first && i_dts > 0 )
+            {
+                i_stuffing = i_payload - i_copy;
+                bits_write( &bits, 8, 7 + i_stuffing );
+                bits_write( &bits,  8, 0x10 ); /* various flags */
+                bits_write( &bits, 33, i_dts * 9 / 100);
+                bits_write( &bits,  6, 0 );
+                bits_write( &bits,  9, 0 );
+                i_dts = 0; /* XXX set dts only for first ts packet */
+            }
+            else
+            {
+                i_stuffing = i_payload - i_copy;
+                bits_write( &bits, 8, i_stuffing - 1);
+                if( i_stuffing - 1 > 0 )
+                {
+                    bits_write( &bits, 8, 0 );
+                }
+                i_stuffing -= 2;
+            }
+
+            /* put stuffing */
+            for( i = 0; i < i_stuffing; i++ )
+            {
+                bits_write( &bits, 8, 0xff );
+            }
+        }
+        /* copy payload */
+        memcpy( p_ts->p_buffer + bits.i_data,
+                p_data,
+                i_copy );
+        p_data += i_copy;
+        i_size -= i_copy;
+
+        /* chain buffers */
+        if( i_first )
+        {
+            *pp_ts        = p_ts;
+            p_last_buffer = p_ts;
+        }
+        else
+        {
+            p_last_buffer->p_next = p_ts;
+            p_last_buffer         = p_ts;
+        }
+        i_first = 0;
+
+        if( i_size <= 0 )
+        {
+            sout_buffer_t *p_next;
+
+            p_next = p_pes->p_next;
+            p_pes->p_next = NULL;
+            sout_BufferDelete( p_sout, p_pes );
+            p_pes = p_next;
+            b_new_pes = 1;
+            if( p_pes )
+            {
+                i_size = p_pes->i_size;
+                p_data = p_pes->p_buffer;
+            }
+            else
+            {
+                break;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int GetPAT( sout_instance_t *p_sout,
+                   sout_buffer_t **pp_ts )
+{
+    sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
+    sout_buffer_t       *p_pat;
+    bits_buffer_t bits;
+
+    p_pat = sout_BufferNew( p_sout, 1024 );
+
+    p_pat->i_pts = 0;
+    p_pat->i_dts = 0;
+    p_pat->i_length = 0;
+
+    bits_initwrite( &bits, 1024, p_pat->p_buffer );
+
+    bits_write( &bits, 8, 0 );      // pointer
+    bits_write( &bits, 8, 0x00 );   // table id
+    bits_write( &bits, 1,  1 );     // section_syntax_indicator
+    bits_write( &bits, 1,  0 );     // 0
+    bits_write( &bits, 2,  0 );     // reserved FIXME
+    bits_write( &bits, 12, 13 );    // XXX for one program only XXX 
+    bits_write( &bits, 16, 0x01 );  // FIXME stream id
+    bits_write( &bits, 2,  0 );     //  FIXME
+    bits_write( &bits, 5,  p_mux->i_pat_version_number );
+    bits_write( &bits, 1,  1 );     // current_next_indicator
+    bits_write( &bits, 8,  0 );     // section number
+    bits_write( &bits, 8,  0 );     // last section number
+
+    bits_write( &bits, 16, 1 );     // program number
+    bits_write( &bits,  3, 0 );     // reserved
+    bits_write( &bits, 13, p_mux->pmt.i_pid );  // program map pid
+
+    bits_write( &bits, 32, 0 );     // FIXME FIXME FIXME
+
+    p_pat->i_size = bits.i_data;
+
+    return( PEStoTS( p_sout, pp_ts, p_pat, &p_mux->pat ) );
+}
+
+static int GetPMT( sout_instance_t *p_sout,
+                   sout_buffer_t **pp_ts )
+{
+    sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
+    sout_buffer_t       *p_pmt;
+    bits_buffer_t bits;
+    int           i_stream;
+
+    p_pmt = sout_BufferNew( p_sout, 1024 );
+
+    p_pmt->i_pts = 0;
+    p_pmt->i_dts = 0;
+    p_pmt->i_length = 0;
+
+    bits_initwrite( &bits, 1024, p_pmt->p_buffer );
+
+    bits_write( &bits, 8, 0 );      // pointer
+    bits_write( &bits, 8, 0x02 );   // table id
+    bits_write( &bits, 1,  1 );     // section_syntax_indicator
+    bits_write( &bits, 1,  0 );     // 0
+    bits_write( &bits, 2,  0 );     // reserved FIXME
+    bits_write( &bits, 12, 13 + 5 * p_sout->i_nb_inputs );
+    bits_write( &bits, 16, 1 );     // FIXME program number
+    bits_write( &bits, 2,  0 );     //  FIXME
+    bits_write( &bits, 5,  p_mux->i_pmt_version_number );
+    bits_write( &bits, 1,  1 );     // current_next_indicator
+    bits_write( &bits, 8,  0 );     // section number
+    bits_write( &bits, 8,  0 );     // last section number
+
+    bits_write( &bits,  3, 0 );     // reserved
+
+    bits_write( &bits, 13, p_mux->i_pcr_pid );     //  FIXME FXIME PCR_PID FIXME
+    bits_write( &bits,  4, 0 );     // reserved FIXME
+
+    bits_write( &bits, 12, 0 );    // program info len FIXME
+
+    for( i_stream = 0; i_stream < p_sout->i_nb_inputs; i_stream++ )
+    {
+        ts_stream_t *p_stream;
+
+        p_stream = (ts_stream_t*)p_sout->pp_inputs[i_stream]->p_mux_data;
+
+        bits_write( &bits,  8, p_stream->i_stream_type ); // stream_type
+        bits_write( &bits,  3, 0 );                 // reserved
+        bits_write( &bits, 13, p_stream->i_pid );   // es pid
+        bits_write( &bits,  4, 0 );                 //reserved
+        bits_write( &bits, 12, 0 );                 // es info len FIXME
+    }
+
+    bits_write( &bits, 32, 0 );     // FIXME FIXME FIXME
+
+    p_pmt->i_size = bits.i_data;
+
+    return( PEStoTS( p_sout, pp_ts, p_pmt, &p_mux->pmt ) );
+
+}
+
+static void SetTSDate( sout_buffer_t *p_ts, mtime_t i_dts, mtime_t i_length )
+{
+    int i_count;
+    sout_buffer_t *p_tmp;
+    mtime_t i_delta;
+
+    for( p_tmp = p_ts, i_count = 0; p_tmp != NULL; p_tmp = p_tmp->p_next )
+    {
+        i_count++;
+    }
+    i_delta = i_length / i_count;
+
+    for( p_tmp = p_ts; p_tmp != NULL; p_tmp = p_tmp->p_next )
+    {
+        p_tmp->i_dts    = i_dts;
+        p_tmp->i_length = i_delta;
+
+        i_dts += i_delta;
+    }
+}
+
+static int Mux( sout_instance_t *p_sout )
+{
+    sout_mux_t          *p_mux = (sout_mux_t*)p_sout->p_mux_data;
+    mtime_t i_dts;
+    int     i_stream;
+
+    sout_buffer_t *p_pat, *p_pmt, *p_ts;
+
+    for( ;; )
+    {
+        mtime_t i_dts, i_length;
+
+        sout_input_t *p_input;
+        ts_stream_t *p_stream;
+        sout_fifo_t  *p_fifo;
+        sout_buffer_t *p_data;
+
+        if( MuxGetStream( p_sout, &i_stream, &i_dts ) < 0 )
+        {
+            return( 0 );
+        }
+
+        p_input = p_sout->pp_inputs[i_stream];
+        p_fifo = p_input->p_fifo;
+        p_stream = (ts_stream_t*)p_input->p_mux_data;
+
+        p_data   = sout_FifoGet( p_fifo );
+        i_dts    = p_data->i_dts;
+        i_length = p_data->i_length;
+
+        EStoPES( p_sout, &p_data, p_data, p_stream->i_stream_id, 1);
+        PEStoTS( p_sout, &p_data, p_data, p_stream );
+
+        if( p_mux->i_ts_packet % 30 == 0 )
+        {
+            /* create pat/pmt */
+            GetPAT( p_sout, &p_pat );
+            GetPMT( p_sout, &p_pmt );
+
+            p_ts = p_pat;
+            p_pat->p_next = p_pmt;
+            p_pmt->p_next = p_data;
+        }
+        else
+        {
+            p_pat = NULL;
+            p_pmt = NULL;
+            p_ts = p_data;
+        }
+
+        p_mux->i_ts_packet++;
+
+        SetTSDate( p_ts, i_dts, i_length );
+
+        p_sout->pf_write( p_sout, p_ts );
+    }
+
+    return( 0 );
+}
+
+
diff --git a/modules/packetizer/.cvsignore b/modules/packetizer/.cvsignore
new file mode 100644 (file)
index 0000000..ec96903
--- /dev/null
@@ -0,0 +1,2 @@
+.deps
+.dirstamp
diff --git a/modules/packetizer/Modules.am b/modules/packetizer/Modules.am
new file mode 100644 (file)
index 0000000..bff53dd
--- /dev/null
@@ -0,0 +1,5 @@
+SOURCES_packetizer_copy = modules/packetizer/copy.c
+SOURCES_packetizer_a52 = modules/packetizer/a52.c
+SOURCES_packetizer_mpegaudio = modules/packetizer/mpegaudio.c
+SOURCES_packetizer_mpegvideo = modules/packetizer/mpegvideo.c
+SOURCES_packetizer_mpeg4video = modules/packetizer/mpeg4video.c
diff --git a/modules/packetizer/a52.c b/modules/packetizer/a52.c
new file mode 100644 (file)
index 0000000..b0f7ca7
--- /dev/null
@@ -0,0 +1,393 @@
+/*****************************************************************************
+ * a52.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: a52.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
+ *
+ * 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 <vlc/vlc.h>
+#include <vlc/aout.h>
+#include <vlc/decoder.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>                                              /* strdup() */
+#include "codecs.h"                         /* WAVEFORMATEX BITMAPINFOHEADER */
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+typedef struct packetizer_s
+{
+    /* Input properties */
+    decoder_fifo_t          *p_fifo;
+    bit_stream_t            bit_stream;
+
+    /* Output properties */
+    sout_input_t            *p_sout_input;
+    sout_packet_format_t    output_format;
+
+    uint64_t                i_samplescount;
+
+} packetizer_t;
+
+static int  Open    ( vlc_object_t * );
+static int  Run     ( decoder_fifo_t * );
+
+static int  InitThread     ( packetizer_t * );
+static void PacketizeThread   ( packetizer_t * );
+static void EndThread      ( packetizer_t * );
+
+static int SyncInfo( const byte_t *, int *, int *, int * );
+
+#define FREE( p ) if( p ) free( p ); p = NULL
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+
+vlc_module_begin();
+    set_description( _("A/52 audio packetizer") );
+    set_capability( "packetizer", 10 );
+    set_callbacks( Open, NULL );
+vlc_module_end();
+
+
+
+/*****************************************************************************
+ * OpenDecoder: probe the packetizer and return score
+ *****************************************************************************
+ * Tries to launch a decoder and return score so that the interface is able
+ * to choose.
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
+
+    if( p_fifo->i_fourcc != VLC_FOURCC( 'a', '5', '2', ' ') &&
+        p_fifo->i_fourcc != VLC_FOURCC( 'a', '5', '2', 'b') )
+    {
+        return VLC_EGENERIC;
+    }
+
+    p_fifo->pf_run = Run;
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * RunDecoder: this function is called just after the thread is created
+ *****************************************************************************/
+static int Run( decoder_fifo_t *p_fifo )
+{
+    packetizer_t *p_pack;
+    int b_error;
+
+    msg_Info( p_fifo, "Running A/52 packetizer" );
+    if( !( p_pack = malloc( sizeof( packetizer_t ) ) ) )
+    {
+        msg_Err( p_fifo, "out of memory" );
+        DecoderError( p_fifo );
+        return( -1 );
+    }
+    memset( p_pack, 0, sizeof( packetizer_t ) );
+
+    p_pack->p_fifo = p_fifo;
+
+    if( InitThread( p_pack ) != 0 )
+    {
+        DecoderError( p_fifo );
+        return( -1 );
+    }
+
+    while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) )
+    {
+        PacketizeThread( p_pack );
+    }
+
+
+    if( ( b_error = p_pack->p_fifo->b_error ) )
+    {
+        DecoderError( p_pack->p_fifo );
+    }
+
+    EndThread( p_pack );
+
+    FREE( p_pack );
+
+    if( b_error )
+    {
+        return( -1 );
+    }
+
+    return( 0 );
+}
+
+
+
+/*****************************************************************************
+ * InitThread: initialize data before entering main loop
+ *****************************************************************************/
+
+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;
+
+    if( InitBitstream( &p_pack->bit_stream, p_pack->p_fifo,
+                       NULL, NULL ) != VLC_SUCCESS )
+    {
+        msg_Err( p_pack->p_fifo, "cannot initialize bitstream" );
+        return -1;
+    }
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * PacketizeThread: packetize an unit (here copy a complete pes)
+ *****************************************************************************/
+static void PacketizeThread( packetizer_t *p_pack )
+{
+    sout_buffer_t   *p_sout_buffer;
+
+
+    uint8_t p_header[7];
+    int i_channels, i_samplerate, i_bitrate;
+    int i_framelength;
+
+    /* search a valid start code */
+    for( ;; )
+    {
+        int i_skip = 0;
+
+        RealignBits( &p_pack->bit_stream );
+        while( ShowBits( &p_pack->bit_stream, 16 ) != 0x0b77 &&
+               !p_pack->p_fifo->b_die && !p_pack->p_fifo->b_error )
+        {
+            RemoveBits( &p_pack->bit_stream, 8 );
+            i_skip++;
+        }
+        if( i_skip )
+        {
+            msg_Warn( p_pack->p_fifo, "trashing %d bytes", i_skip );
+        }
+        if( p_pack->p_fifo->b_die || p_pack->p_fifo->b_error )
+        {
+            return;
+        }
+
+        GetChunk( &p_pack->bit_stream, p_header, 7 );
+        if( p_pack->p_fifo->b_die ) return;
+
+        /* Check if frame is valid and get frame info */
+        i_framelength = SyncInfo( p_header, &i_channels, &i_samplerate,
+                                  &i_bitrate );
+
+        if( !i_framelength )
+        {
+            msg_Warn( p_pack->p_fifo, "invalid header found" );
+            continue;
+        }
+        else
+        {
+//            msg_Dbg( p_pack->p_fifo, "frame length %d b", i_framelength );
+            break;
+        }
+    }
+
+    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->p_sout_input =
+            sout_InputNew( p_pack->p_fifo,
+                           &p_pack->output_format );
+
+        if( !p_pack->p_sout_input )
+        {
+            msg_Err( p_pack->p_fifo,
+                     "cannot add a new stream" );
+            p_pack->p_fifo->b_error = 1;
+            return;
+        }
+        msg_Info( p_pack->p_fifo,
+                 "A/52 channels:%d samplerate:%d bitrate:%d",
+                 i_channels, i_samplerate, i_bitrate );
+    }
+
+    p_sout_buffer =
+        sout_BufferNew( p_pack->p_sout_input->p_sout, i_framelength );
+    if( !p_sout_buffer )
+    {
+        p_pack->p_fifo->b_error = 1;
+        return;
+    }
+    memcpy( p_sout_buffer->p_buffer, p_header, 7 );
+    p_sout_buffer->i_bitrate = i_bitrate;
+
+    p_sout_buffer->i_pts =
+        p_sout_buffer->i_dts =
+            (uint64_t)1000000 *
+            (uint64_t)p_pack->i_samplescount /
+            (uint64_t)i_samplerate;
+    p_sout_buffer->i_length =
+            (uint64_t)1000000 *
+            (uint64_t)A52_FRAME_NB /
+            (uint64_t)i_samplerate;
+
+    p_pack->i_samplescount += A52_FRAME_NB;
+
+    /* we are already aligned */
+    GetChunk( &p_pack->bit_stream,
+              p_sout_buffer->p_buffer + 7,
+              i_framelength - 7 );
+
+    sout_InputSendBuffer( p_pack->p_sout_input,
+                          p_sout_buffer );
+}
+
+
+/*****************************************************************************
+ * EndThread : packetizer thread destruction
+ *****************************************************************************/
+static void EndThread ( packetizer_t *p_pack)
+{
+    if( p_pack->p_sout_input )
+    {
+        sout_InputDelete( p_pack->p_sout_input );
+    }
+}
+
+/*****************************************************************************
+ * SyncInfo: parse A52 sync info
+ *****************************************************************************
+ * This code is borrowed from liba52 by Aaron Holtzman & Michel Lespinasse,
+ * since we don't want to oblige S/PDIF people to use liba52 just to get
+ * their SyncInfo...
+ * fenrir: I've change it to report channels count
+ *****************************************************************************/
+static int SyncInfo( const byte_t * p_buf, int * pi_channels,
+                     int * pi_sample_rate, int * pi_bit_rate )
+{
+    static const uint8_t halfrate[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 };
+    static const int rate[] = { 32,  40,  48,  56,  64,  80,  96, 112,
+                                128, 160, 192, 224, 256, 320, 384, 448,
+                                512, 576, 640 };
+    static const uint8_t lfeon[8] = { 0x10, 0x10, 0x04, 0x04,
+                                      0x04, 0x01, 0x04, 0x01 };
+    int frmsizecod;
+    int bitrate;
+    int half;
+    int acmod;
+
+    if ((p_buf[0] != 0x0b) || (p_buf[1] != 0x77))        /* syncword */
+        return 0;
+
+    if (p_buf[5] >= 0x60)                /* bsid >= 12 */
+        return 0;
+    half = halfrate[p_buf[5] >> 3];
+
+    /* acmod, dsurmod and lfeon */
+    acmod = p_buf[6] >> 5;
+    if ( (p_buf[6] & 0xf8) == 0x50 )
+    {
+        /* Dolby surround = stereo + Dolby */
+/*        *pi_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
+                        | AOUT_CHAN_DOLBYSTEREO;*/
+        *pi_channels = 2; /* FIXME ???  */
+    }
+    else switch ( acmod )
+    {
+    case 0x0:
+        /* Dual-mono = stereo + dual-mono */
+//        *pi_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
+//                        | AOUT_CHAN_DUALMONO;
+        *pi_channels = 2; /* FIXME ???  */
+        break;
+    case 0x1:
+        /* Mono */
+        *pi_channels = 1;
+        break;
+    case 0x2:
+        /* Stereo */
+        *pi_channels = 2;
+        break;
+    case 0x3: /* 3F */
+    case 0x4: /* 2F1R */
+        *pi_channels = 3;
+        break;
+    case 0x5: /* 3F1R */
+    case 0x6: /* 2F2R */
+        *pi_channels = 4;
+        break;
+    case 0x7:
+        /* 3F2R */
+        *pi_channels = 5;
+        break;
+    default:
+        return 0;
+    }
+
+    if ( p_buf[6] & lfeon[acmod] ) *pi_channels += 1;//|= AOUT_CHAN_LFEA;
+
+    frmsizecod = p_buf[4] & 63;
+    if (frmsizecod >= 38)
+        return 0;
+    bitrate = rate [frmsizecod >> 1];
+    *pi_bit_rate = (bitrate * 1000) >> half;
+
+    switch (p_buf[4] & 0xc0) {
+    case 0:
+        *pi_sample_rate = 48000 >> half;
+        return 4 * bitrate;
+    case 0x40:
+        *pi_sample_rate = 44100 >> half;
+        return 2 * (320 * bitrate / 147 + (frmsizecod & 1));
+    case 0x80:
+        *pi_sample_rate = 32000 >> half;
+        return 6 * bitrate;
+    default:
+        return 0;
+    }
+}
+
+
diff --git a/modules/packetizer/copy.c b/modules/packetizer/copy.c
new file mode 100644 (file)
index 0000000..c0cd614
--- /dev/null
@@ -0,0 +1,227 @@
+/*****************************************************************************
+ * copy.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: copy.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
+ *
+ * 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 <vlc/vlc.h>
+#include <vlc/aout.h>
+#include <vlc/decoder.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>                                              /* strdup() */
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+typedef struct packetizer_thread_s
+{
+    /* Input properties */
+    decoder_fifo_t          *p_fifo;
+
+    /* Output properties */
+    sout_input_t            *p_sout_input;
+    sout_packet_format_t    output_format;
+
+} packetizer_thread_t;
+
+static int  Open    ( vlc_object_t * );
+static int  Run     ( decoder_fifo_t * );
+
+static int  InitThread     ( packetizer_thread_t * );
+static void PacketizeThread   ( packetizer_thread_t * );
+static void EndThread      ( packetizer_thread_t * );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+
+vlc_module_begin();
+    set_description( _("Copy packetizer") );
+    set_capability( "packetizer", 0 );
+    set_callbacks( Open, NULL );
+vlc_module_end();
+
+
+/*****************************************************************************
+ * OpenDecoder: probe the packetizer and return score
+ *****************************************************************************
+ * Tries to launch a decoder and return score so that the interface is able
+ * to choose.
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
+
+    p_fifo->pf_run = Run;
+
+    return VLC_SUCCESS;
+
+#if 0
+    if( p_fifo->i_fourcc == VLC_FOURCC( 'm', 'p', 'g', 'a') )
+        ....
+#endif
+}
+
+/*****************************************************************************
+ * RunDecoder: this function is called just after the thread is created
+ *****************************************************************************/
+static int Run( decoder_fifo_t *p_fifo )
+{
+    packetizer_thread_t *p_pack;
+    int b_error;
+
+    msg_Info( p_fifo, "Running copy packetizer" );
+    if( !( p_pack = malloc( sizeof( packetizer_thread_t ) ) ) )
+    {
+        msg_Err( p_fifo, "out of memory" );
+        DecoderError( p_fifo );
+        return( -1 );
+    }
+    memset( p_pack, 0, sizeof( packetizer_thread_t ) );
+
+    p_pack->p_fifo = p_fifo;
+
+    if( InitThread( p_pack ) != 0 )
+    {
+        DecoderError( p_fifo );
+        return( -1 );
+    }
+
+    while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) )
+    {
+        PacketizeThread( p_pack );
+    }
+
+
+    if( ( b_error = p_pack->p_fifo->b_error ) )
+    {
+        DecoderError( p_pack->p_fifo );
+    }
+
+    EndThread( p_pack );
+    if( b_error )
+    {
+        return( -1 );
+    }
+
+    return( 0 );
+}
+
+
+#define FREE( p ) if( p ) free( p ); p = NULL
+
+/*****************************************************************************
+ * InitThread: initialize data before entering main loop
+ *****************************************************************************/
+
+static int InitThread( packetizer_thread_t *p_pack )
+{
+
+//    p_pack->output_format.i_cat = p_pack->p_fifo->i_cat;
+    p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc;
+
+    p_pack->p_sout_input = 
+        sout_InputNew( p_pack->p_fifo,
+                       &p_pack->output_format );
+
+    if( !p_pack->p_sout_input )
+    {
+        msg_Err( p_pack->p_fifo, 
+                 "cannot add a new stream" );
+        return( -1 );
+    }
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * PacketizeThread: packetize an unit (here copy a complete pes)
+ *****************************************************************************/
+static void PacketizeThread( packetizer_thread_t *p_pack )
+{
+    sout_buffer_t   *p_sout_buffer;
+    pes_packet_t    *p_pes;
+    size_t          i_size;
+
+    /* **** get samples count **** */
+    input_ExtractPES( p_pack->p_fifo, &p_pes );
+    if( !p_pes )
+    {
+        p_pack->p_fifo->b_error = 1;
+        return;
+    }
+    i_size = p_pes->i_pes_size;
+
+    if( i_size > 0 )
+    {
+        data_packet_t   *p_data;
+        size_t          i_buffer;
+
+        p_sout_buffer = 
+            sout_BufferNew( p_pack->p_sout_input->p_sout, i_size );
+        if( !p_sout_buffer )
+        {
+            p_pack->p_fifo->b_error = 1;
+            return;
+        }
+        /* TODO: memcpy of the pes packet */
+        for( i_buffer = 0, p_data = p_pes->p_first;
+             p_data != NULL && i_buffer < i_size;
+             p_data = p_data->p_next)
+        {
+            size_t          i_copy;
+
+            i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start, 
+                            i_size - i_buffer );
+            if( i_copy > 0 )
+            {
+                p_pack->p_fifo->p_vlc->pf_memcpy( p_sout_buffer->p_buffer + i_buffer,
+                                                  p_data->p_payload_start,
+                                                  i_copy );
+            }
+            i_buffer += i_copy;
+        }
+
+        sout_InputSendBuffer( p_pack->p_sout_input,
+                               p_sout_buffer );
+    }
+
+    input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
+}
+
+
+/*****************************************************************************
+ * EndThread : packetizer thread destruction
+ *****************************************************************************/
+static void EndThread ( packetizer_thread_t *p_pack)
+{
+    if( p_pack->p_sout_input )
+    {
+        sout_InputDelete( p_pack->p_sout_input );
+    }
+}
+
diff --git a/modules/packetizer/mpeg4video.c b/modules/packetizer/mpeg4video.c
new file mode 100644 (file)
index 0000000..8f2055d
--- /dev/null
@@ -0,0 +1,358 @@
+/*****************************************************************************
+ * mpeg4video.c:
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: mpeg4video.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
+ *
+ * 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 <vlc/vlc.h>
+#include <vlc/aout.h>
+#include <vlc/decoder.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>                                              /* strdup() */
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+typedef struct packetizer_thread_s
+{
+    /* Input properties */
+    decoder_fifo_t          *p_fifo;
+    bit_stream_t            bit_stream;
+
+    mtime_t                 i_dts;
+
+    /* Output properties */
+    sout_input_t            *p_sout_input;
+    sout_packet_format_t    output_format;
+
+
+    sout_buffer_t           *p_vol;
+    int                     i_vop_since_vol;
+} packetizer_thread_t;
+
+static int  Open    ( vlc_object_t * );
+static int  Run     ( decoder_fifo_t * );
+
+static int  InitThread     ( packetizer_thread_t * );
+static void PacketizeThread   ( packetizer_thread_t * );
+static void EndThread      ( packetizer_thread_t * );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+
+vlc_module_begin();
+    set_description( _("MPEG-4 packetizer") );
+    set_capability( "packetizer", 50 );
+    set_callbacks( Open, NULL );
+vlc_module_end();
+
+#define VIDEO_OBJECT_MASK                       0x01f
+#define VIDEO_OBJECT_LAYER_MASK                 0x00f
+
+#define VIDEO_OBJECT_START_CODE                 0x100
+#define VIDEO_OBJECT_LAYER_START_CODE           0x120
+#define VISUAL_OBJECT_SEQUENCE_START_CODE       0x1b0
+#define VISUAL_OBJECT_SEQUENCE_END_CODE         0x1b1
+#define USER_DATA_START_CODE                    0x1b2
+#define GROUP_OF_VOP_START_CODE                 0x1b3
+#define VIDEO_SESSION_ERROR_CODE                0x1b4
+#define VISUAL_OBJECT_START_CODE                0x1b5
+#define VOP_START_CODE                          0x1b6
+#define FACE_OBJECT_START_CODE                  0x1ba
+#define FACE_OBJECT_PLANE_START_CODE            0x1bb
+#define MESH_OBJECT_START_CODE                  0x1bc
+#define MESH_OBJECT_PLANE_START_CODE            0x1bd
+#define STILL_TEXTURE_OBJECT_START_CODE         0x1be
+#define TEXTURE_SPATIAL_LAYER_START_CODE        0x1bf
+#define TEXTURE_SNR_LAYER_START_CODE            0x1c0
+
+/*****************************************************************************
+ * OpenDecoder: probe the packetizer and return score
+ *****************************************************************************
+ * Tries to launch a decoder and return score so that the interface is able
+ * to choose.
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
+
+    p_fifo->pf_run = Run;
+
+    switch(  p_fifo->i_fourcc )
+    {
+        case VLC_FOURCC( 'm', 'p', '4', 'v'):
+        case VLC_FOURCC( 'D', 'I', 'V', 'X'):
+        case VLC_FOURCC( 'd', 'i', 'v', 'x'):
+        case VLC_FOURCC( 'X', 'V', 'I', 'D'):
+        case VLC_FOURCC( 'X', 'v', 'i', 'D'):
+        case VLC_FOURCC( 'x', 'v', 'i', 'd'):
+        case VLC_FOURCC( 'D', 'X', '5', '0'):
+            return VLC_SUCCESS;
+        default:
+            return VLC_EGENERIC;
+    }
+}
+
+/*****************************************************************************
+ * RunDecoder: this function is called just after the thread is created
+ *****************************************************************************/
+static int Run( decoder_fifo_t *p_fifo )
+{
+    packetizer_thread_t *p_pack;
+    int b_error;
+
+    msg_Info( p_fifo, "Running MPEG-4 packetizer" );
+    if( !( p_pack = malloc( sizeof( packetizer_thread_t ) ) ) )
+    {
+        msg_Err( p_fifo, "out of memory" );
+        DecoderError( p_fifo );
+        return( -1 );
+    }
+    memset( p_pack, 0, sizeof( packetizer_thread_t ) );
+
+    p_pack->p_fifo = p_fifo;
+
+    if( InitThread( p_pack ) != 0 )
+    {
+        DecoderError( p_fifo );
+        return( -1 );
+    }
+
+    while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) )
+    {
+        PacketizeThread( p_pack );
+    }
+
+
+    if( ( b_error = p_pack->p_fifo->b_error ) )
+    {
+        DecoderError( p_pack->p_fifo );
+    }
+
+    EndThread( p_pack );
+    if( b_error )
+    {
+        return( -1 );
+    }
+
+    return( 0 );
+}
+
+
+#define FREE( p ) if( p ) free( p ); p = NULL
+
+static int CopyUntilNextStartCode( packetizer_thread_t   *p_pack,
+                                   sout_buffer_t  *p_sout_buffer,
+                                   int            *pi_pos )
+{
+    int i_copy = 0;
+
+    do
+    {
+        p_sout_buffer->p_buffer[(*pi_pos)++] =
+        GetBits( &p_pack->bit_stream, 8 );
+        i_copy++;
+
+        if( *pi_pos + 2048 > p_sout_buffer->i_allocated_size )
+        {
+            sout_BufferRealloc( p_pack->p_sout_input->p_sout,
+                                p_sout_buffer,
+                                p_sout_buffer->i_allocated_size + 50 * 1024);
+        }
+
+    } while( ShowBits( &p_pack->bit_stream, 24 ) != 0x01 &&
+             !p_pack->p_fifo->b_die && !p_pack->p_fifo->b_error );
+
+    return( i_copy );
+}
+
+static int sout_BufferAddMem( sout_instance_t *p_sout,
+                              sout_buffer_t   *p_buffer,
+                              int             i_mem,
+                              uint8_t         *p_mem )
+{
+    if( p_buffer->i_size + i_mem >= p_buffer->i_allocated_size )
+    {
+        sout_BufferRealloc( p_sout,
+                            p_buffer,
+                            p_buffer->i_size + i_mem + 1024 );
+    }
+    memcpy( p_buffer->p_buffer + p_buffer->i_size, p_mem, i_mem );
+    p_buffer->i_size += i_mem;
+
+    return( i_mem );
+}
+
+/*****************************************************************************
+ * InitThread: initialize data before entering main loop
+ *****************************************************************************/
+
+static int InitThread( packetizer_thread_t *p_pack )
+{
+    p_pack->i_dts = 0;
+    p_pack->p_vol = NULL;
+    p_pack->i_vop_since_vol = 0;
+    p_pack->output_format.i_cat = VIDEO_ES;
+    p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v' );
+
+    if( InitBitstream( &p_pack->bit_stream, p_pack->p_fifo,
+                       NULL, NULL ) != VLC_SUCCESS )
+    {
+        msg_Err( p_pack->p_fifo, "cannot initialize bitstream" );
+        return -1;
+    }
+
+    p_pack->p_sout_input =
+        sout_InputNew( p_pack->p_fifo,
+                       &p_pack->output_format );
+
+    if( !p_pack->p_sout_input )
+    {
+        msg_Err( p_pack->p_fifo,
+                 "cannot add a new stream" );
+        return( -1 );
+    }
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * PacketizeThread: packetize an unit (here copy a complete pes)
+ *****************************************************************************/
+static void PacketizeThread( packetizer_thread_t *p_pack )
+{
+    sout_instance_t *p_sout = p_pack->p_sout_input->p_sout;
+    sout_buffer_t   *p_frame;
+
+    uint32_t        i_startcode;
+
+    /* Idea: Copy until a vop has been found
+     *       Once a videoobject & videoobjectlayer has been found we save it
+     */
+
+    p_frame = sout_BufferNew( p_sout, 20*1024 );    // FIXME
+    p_frame->i_size = 0;
+
+    for( ;; )
+    {
+        while( ( ( i_startcode = ShowBits( &p_pack->bit_stream, 32 ) )&0xffffff00 ) != 0x00000100 )
+        {
+            RemoveBits( &p_pack->bit_stream, 8 );
+        }
+
+        if( i_startcode == VISUAL_OBJECT_SEQUENCE_START_CODE )
+        {
+            msg_Dbg( p_pack->p_fifo, "<visuel_object_sequence>" );
+            RemoveBits32( &p_pack->bit_stream );
+        }
+        else if( i_startcode == VISUAL_OBJECT_SEQUENCE_END_CODE )
+        {
+            msg_Dbg( p_pack->p_fifo, "</visuel_object_sequence>" );
+            RemoveBits32( &p_pack->bit_stream );
+        }
+        else
+        {
+            msg_Dbg( p_pack->p_fifo, "start code:0x%8.8x", i_startcode );
+
+            if( ( i_startcode & ~VIDEO_OBJECT_MASK ) == VIDEO_OBJECT_START_CODE )
+            {
+                msg_Dbg( p_pack->p_fifo, "<video_object>" );
+                CopyUntilNextStartCode( p_pack, p_frame, &p_frame->i_size );
+            }
+            else if( ( i_startcode & ~VIDEO_OBJECT_LAYER_MASK ) == VIDEO_OBJECT_LAYER_START_CODE )
+            {
+                /* first: save it */
+                if( p_pack->p_vol == NULL )
+                {
+                    p_pack->p_vol = sout_BufferNew( p_sout, 1024 );
+                }
+                p_pack->p_vol->i_size = 0;
+                CopyUntilNextStartCode( p_pack, p_pack->p_vol, &p_pack->p_vol->i_size );
+                p_pack->i_vop_since_vol = 0;
+
+                /* then: add it to p_frame */
+                sout_BufferAddMem( p_sout, p_frame,
+                                   p_pack->p_vol->i_size,
+                                   p_pack->p_vol->p_buffer );
+            }
+            else if( i_startcode == GROUP_OF_VOP_START_CODE )
+            {
+                msg_Dbg( p_pack->p_fifo, "<group_of_vop>" );
+                if( p_pack->p_vol && p_pack->i_vop_since_vol > 100 ) // FIXME
+                {
+                    sout_BufferAddMem( p_sout, p_frame,
+                                       p_pack->p_vol->i_size,
+                                       p_pack->p_vol->p_buffer );
+                    p_pack->i_vop_since_vol = 0;
+                }
+                CopyUntilNextStartCode( p_pack, p_frame, &p_frame->i_size );
+            }
+            else if( i_startcode == VOP_START_CODE )
+            {
+                msg_Dbg( p_pack->p_fifo, "<vop>" );
+                if( p_pack->p_vol && p_pack->i_vop_since_vol > 100 ) // FIXME
+                {
+                    sout_BufferAddMem( p_sout, p_frame,
+                                       p_pack->p_vol->i_size,
+                                       p_pack->p_vol->p_buffer );
+                    p_pack->i_vop_since_vol = 0;
+                }
+                CopyUntilNextStartCode( p_pack, p_frame, &p_frame->i_size );
+                p_pack->i_vop_since_vol++;
+                break;
+            }
+            else
+            {
+                msg_Dbg( p_pack->p_fifo, "unknown start code" );
+                CopyUntilNextStartCode( p_pack, p_frame, &p_frame->i_size );
+            }
+
+        }
+    }
+
+    p_frame->i_length = 1000000 / 25;
+    p_frame->i_bitrate= 0;
+    p_frame->i_dts = p_pack->i_dts;
+    p_frame->i_pts = p_pack->i_dts;
+
+    p_pack->i_dts += 1000000 / 25;
+    sout_InputSendBuffer( p_pack->p_sout_input, p_frame );
+}
+
+
+/*****************************************************************************
+ * EndThread : packetizer thread destruction
+ *****************************************************************************/
+static void EndThread ( packetizer_thread_t *p_pack)
+{
+    if( p_pack->p_sout_input )
+    {
+        sout_InputDelete( p_pack->p_sout_input );
+    }
+}
+
diff --git a/modules/packetizer/mpegaudio.c b/modules/packetizer/mpegaudio.c
new file mode 100644 (file)
index 0000000..a7148f4
--- /dev/null
@@ -0,0 +1,370 @@
+/*****************************************************************************
+ * mpegaudio.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: mpegaudio.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
+ *
+ * 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 <vlc/vlc.h>
+#include <vlc/aout.h>
+#include <vlc/decoder.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>                                              /* strdup() */
+#include "codecs.h"                         /* WAVEFORMATEX BITMAPINFOHEADER */
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+typedef struct packetizer_s
+{
+    /* Input properties */
+    decoder_fifo_t          *p_fifo;
+    bit_stream_t            bit_stream;
+
+    /* Output properties */
+    sout_input_t            *p_sout_input;
+    sout_packet_format_t    output_format;
+
+    uint64_t                i_samplescount;
+    uint32_t                i_samplespersecond;
+
+} packetizer_t;
+
+static int  Open    ( vlc_object_t * );
+static int  Run     ( decoder_fifo_t * );
+
+static int  InitThread     ( packetizer_t * );
+static void PacketizeThread   ( packetizer_t * );
+static void EndThread      ( packetizer_t * );
+
+#define FREE( p ) if( p ) free( p ); p = NULL
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+
+vlc_module_begin();
+    set_description( _("MPEG-I/II audio packetizer") );
+    set_capability( "packetizer", 50 );
+    set_callbacks( Open, NULL );
+vlc_module_end();
+
+
+static int mpegaudio_bitrate[2][3][16] =
+{
+  {
+    /* v1 l1 */
+    { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0},
+    /* v1 l2 */
+    { 0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384, 0},
+    /* v1 l3 */
+    { 0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 0} 
+  },
+
+  {
+     /* v2 l1 */
+    { 0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256, 0},
+    /* v2 l2 */
+    { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0},
+    /* v2 l3 */
+    { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0} 
+  }
+
+};
+
+static int mpegaudio_samplerate[2][4] = /* version 1 then 2 */
+{
+    { 44100, 48000, 32000, 0 },
+    { 22050, 24000, 16000, 0 }
+};
+
+
+/*****************************************************************************
+ * OpenDecoder: probe the packetizer and return score
+ *****************************************************************************
+ * Tries to launch a decoder and return score so that the interface is able
+ * to choose.
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
+
+    if( p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', 'a') )
+    {
+        return VLC_EGENERIC;
+    }
+
+    p_fifo->pf_run = Run;
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * RunDecoder: this function is called just after the thread is created
+ *****************************************************************************/
+static int Run( decoder_fifo_t *p_fifo )
+{
+    packetizer_t *p_pack;
+    int b_error;
+
+    msg_Info( p_fifo, "Running mpegaudio packetizer" );
+    if( !( p_pack = malloc( sizeof( packetizer_t ) ) ) )
+    {
+        msg_Err( p_fifo, "out of memory" );
+        DecoderError( p_fifo );
+        return( -1 );
+    }
+    memset( p_pack, 0, sizeof( packetizer_t ) );
+
+    p_pack->p_fifo = p_fifo;
+
+    if( InitThread( p_pack ) != 0 )
+    {
+        DecoderError( p_fifo );
+        return( -1 );
+    }
+
+    while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) )
+    {
+        PacketizeThread( p_pack );
+    }
+
+
+    if( ( b_error = p_pack->p_fifo->b_error ) )
+    {
+        DecoderError( p_pack->p_fifo );
+    }
+
+    EndThread( p_pack );
+
+    FREE( p_pack );
+
+    if( b_error )
+    {
+        return( -1 );
+    }
+
+    return( 0 );
+}
+
+
+
+/*****************************************************************************
+ * InitThread: initialize data before entering main loop
+ *****************************************************************************/
+
+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.p_format = NULL;
+
+    p_pack->p_sout_input = NULL;
+
+    p_pack->i_samplescount = 0;
+    p_pack->i_samplespersecond = 0;
+
+    if( InitBitstream( &p_pack->bit_stream, p_pack->p_fifo,
+                       NULL, NULL ) != VLC_SUCCESS )
+    {
+        msg_Err( p_pack->p_fifo, "cannot initialize bitstream" );
+        return -1;
+    }
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * PacketizeThread: packetize an unit (here copy a complete pes)
+ *****************************************************************************/
+static void PacketizeThread( packetizer_t *p_pack )
+{
+    sout_buffer_t   *p_sout_buffer;
+    size_t          i_size;
+
+    uint32_t        i_sync, i_header;
+    int             i_version, i_layer;
+    int             i_channels, i_samplerate, i_bitrate;
+    int             i_samplesperframe, i_framelength;
+    int i_skip = 0;
+    /* search a valid start code */
+    for( ;; )
+    {
+        int i_crc, i_bitrate_index, i_samplerate_index;
+        int i_padding, i_extention, i_mode, i_modeext, i_copyright;
+        int i_original, i_emphasis;
+
+        RealignBits( &p_pack->bit_stream );
+
+
+        while( ShowBits( &p_pack->bit_stream, 12 ) != 0x0fff &&
+               !p_pack->p_fifo->b_die && !p_pack->p_fifo->b_error )
+        {
+            //msg_Warn( p_pack->p_fifo, "trash..." );
+            RemoveBits( &p_pack->bit_stream, 8 );
+            i_skip++;
+        }
+
+        if( p_pack->p_fifo->b_die || p_pack->p_fifo->b_error )
+        {
+            return;
+        }
+
+        i_sync      = GetBits( &p_pack->bit_stream, 12 );
+        i_header    = ShowBits( &p_pack->bit_stream, 20 );
+
+        i_version   = 1 - GetBits( &p_pack->bit_stream, 1 );
+        i_layer     = 3 - GetBits( &p_pack->bit_stream, 2 );
+        i_crc       = 1 - GetBits( &p_pack->bit_stream, 1 );
+        i_bitrate_index = GetBits( &p_pack->bit_stream, 4 );
+        i_samplerate_index = GetBits( &p_pack->bit_stream, 2 );
+        i_padding   = GetBits( &p_pack->bit_stream, 1 );
+        i_extention = GetBits( &p_pack->bit_stream, 1 );
+        i_mode      = GetBits( &p_pack->bit_stream, 2 );
+        i_modeext   = GetBits( &p_pack->bit_stream, 2 );
+        i_copyright = GetBits( &p_pack->bit_stream, 1 );
+        i_original  = GetBits( &p_pack->bit_stream, 1 );
+        i_emphasis  = GetBits( &p_pack->bit_stream, 2 );
+
+        if( i_layer != 3 &&
+            i_bitrate_index > 0x00 && i_bitrate_index < 0x0f &&
+            i_samplerate_index != 0x03 &&
+            i_emphasis != 0x02 )
+        {
+            i_channels = ( i_mode == 3 ) ? 1 : 2;
+            i_bitrate = mpegaudio_bitrate[i_version][i_layer][i_bitrate_index];
+            i_samplerate = mpegaudio_samplerate[i_version][i_samplerate_index];
+            switch( i_layer )
+            {
+                case 0:
+                    i_framelength = ( ( i_version ? 6000 : 12000 ) *
+                                    i_bitrate / i_samplerate + i_padding ) * 4;
+                    break;
+                 case 1:
+                 case 2:
+                    i_framelength = ( i_version ? 72000 : 144000 ) *
+                                    i_bitrate / i_samplerate + i_padding;
+                    break;
+                default:
+                    i_framelength = 0;
+            }
+            switch( i_layer )
+            {
+                case 0:
+                    i_samplesperframe = 384;
+                    break;
+                case 1:
+                    i_samplesperframe = 1152;
+                    break;
+                case 2:
+                    i_samplesperframe = i_version ? 1152 : 576;
+                    break;
+            }
+            break;
+        }
+    }
+
+    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->p_sout_input =
+            sout_InputNew( p_pack->p_fifo,
+                           &p_pack->output_format );
+
+        if( !p_pack->p_sout_input )
+        {
+            msg_Err( p_pack->p_fifo,
+                     "cannot add a new stream" );
+            p_pack->p_fifo->b_error = 1;
+            return;
+        }
+        msg_Dbg( p_pack->p_fifo,
+                 "v:%d l:%d channels:%d samplerate:%d bitrate:%d size:%d",
+                 i_version, i_layer, i_channels, i_samplerate,
+                 i_bitrate, i_framelength );
+    }
+
+    i_size = __MAX( i_framelength, 4 );
+//    msg_Dbg( p_pack->p_fifo, "frame length %d b", i_size );
+    p_sout_buffer =
+        sout_BufferNew( p_pack->p_sout_input->p_sout, i_size );
+    if( !p_sout_buffer )
+    {
+        p_pack->p_fifo->b_error = 1;
+        return;
+    }
+    p_sout_buffer->p_buffer[0] = ( i_sync >> 4 )&0xff;
+    p_sout_buffer->p_buffer[1] = 
+        ( ( i_sync << 4 )&0xf0 ) | ( ( i_header >> 16 )&0x0f );
+    p_sout_buffer->p_buffer[2] = ( i_header >> 8 )&0xff;
+    p_sout_buffer->p_buffer[3] = ( i_header      )&0xff;
+    p_sout_buffer->i_bitrate = i_bitrate;
+
+    p_sout_buffer->i_pts =
+        p_sout_buffer->i_dts =
+            (uint64_t)1000000 *
+            (uint64_t)p_pack->i_samplescount /
+            (uint64_t)i_samplerate;
+    p_sout_buffer->i_length =
+            (uint64_t)1000000 *
+            (uint64_t)i_samplesperframe /
+            (uint64_t)i_samplerate;
+
+    p_pack->i_samplescount += i_samplesperframe;
+
+    /* we are already aligned */
+    GetChunk( &p_pack->bit_stream,
+              p_sout_buffer->p_buffer + 4,
+              i_size - 4 );
+
+    sout_InputSendBuffer( p_pack->p_sout_input,
+                          p_sout_buffer );
+}
+
+
+/*****************************************************************************
+ * EndThread : packetizer thread destruction
+ *****************************************************************************/
+static void EndThread ( packetizer_t *p_pack)
+{
+    if( p_pack->p_sout_input )
+    {
+        sout_InputDelete( p_pack->p_sout_input );
+    }
+}
diff --git a/modules/packetizer/mpegvideo.c b/modules/packetizer/mpegvideo.c
new file mode 100644 (file)
index 0000000..cc8f859
--- /dev/null
@@ -0,0 +1,395 @@
+/*****************************************************************************
+ * mpegvideo.c
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: mpegvideo.c,v 1.1 2002/12/14 21:32:41 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Eric Petit <titer@videolan.org>
+ *
+ * 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 <vlc/vlc.h>
+#include <vlc/decoder.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+#include "codecs.h"                         /* WAVEFORMATEX BITMAPINFOHEADER */
+
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>                                              /* strdup() */
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+typedef struct packetizer_s
+{
+    /* Input properties */
+    decoder_fifo_t          *p_fifo;
+    bit_stream_t            bit_stream;
+
+    /* Output properties */
+    sout_input_t            *p_sout_input;
+    sout_packet_format_t    output_format;
+
+    mtime_t                 i_last_dts;
+    mtime_t                 i_last_ref_pts;
+    double                  d_frame_rate;
+    uint8_t                 p_sequence_header[150];
+    int                     i_sequence_header_length;
+    int                     i_last_sequence_header;
+
+} packetizer_t;
+
+static int  Open    ( vlc_object_t * );
+static int  Run     ( decoder_fifo_t * );
+
+static int  InitThread     ( packetizer_t * );
+static void PacketizeThread   ( packetizer_t * );
+static void EndThread      ( packetizer_t * );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+
+vlc_module_begin();
+    set_description( _("MPEG-I/II video packetizer") );
+    set_capability( "packetizer", 50 );
+    set_callbacks( Open, NULL );
+vlc_module_end();
+
+/*****************************************************************************
+ * OpenDecoder: probe the packetizer and return score
+ *****************************************************************************
+ * Tries to launch a decoder and return score so that the interface is able
+ * to choose.
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
+
+    if( p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', 'v') )
+    {
+        return VLC_EGENERIC;
+    }
+
+    p_fifo->pf_run = Run;
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * RunDecoder: this function is called just after the thread is created
+ *****************************************************************************/
+static int Run( decoder_fifo_t *p_fifo )
+{
+    packetizer_t *p_pack;
+    int b_error;
+
+    msg_Info( p_fifo, "Running mpegvideo packetizer" );
+    if( !( p_pack = malloc( sizeof( packetizer_t ) ) ) )
+    {
+        msg_Err( p_fifo, "out of memory" );
+        DecoderError( p_fifo );
+        return( -1 );
+    }
+    memset( p_pack, 0, sizeof( packetizer_t ) );
+
+    p_pack->p_fifo = p_fifo;
+
+    if( InitThread( p_pack ) != 0 )
+    {
+        DecoderError( p_fifo );
+        return( -1 );
+    }
+
+    while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) )
+    {
+        PacketizeThread( p_pack );
+    }
+
+
+    if( ( b_error = p_pack->p_fifo->b_error ) )
+    {
+        DecoderError( p_pack->p_fifo );
+    }
+
+    EndThread( p_pack );
+
+    if( p_pack )
+    {
+        free( p_pack );
+    }
+
+    if( b_error )
+    {
+        return( -1 );
+    }
+
+    return( 0 );
+}
+
+
+/*****************************************************************************
+ * InitThread: initialize data before entering main loop
+ *****************************************************************************/
+
+static int InitThread( packetizer_t *p_pack )
+{
+
+    p_pack->output_format.i_cat = VIDEO_ES;
+    p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc;
+
+    p_pack->p_sout_input = NULL;
+
+    if( InitBitstream( &p_pack->bit_stream, p_pack->p_fifo,
+                       NULL, NULL ) != VLC_SUCCESS )
+    {
+        msg_Err( p_pack->p_fifo, "cannot initialize bitstream" );
+        return -1;
+    }
+
+    return( 0 );
+}
+
+/* from ISO 13818-2 */
+/* converting frame_rate_code to frame_rate */
+static const double pd_frame_rates[16] =
+{
+    0, 24000/1001, 24, 25, 30000/1001, 30, 50, 60000/1001, 60,
+    0, 0, 0, 0, 0, 0, 0
+};
+
+static int CopyUntilNextStartCode( packetizer_t   *p_pack,
+                                   sout_buffer_t  *p_sout_buffer,
+                                   int            *pi_pos )
+{
+    int i_copy = 0;
+
+    do
+    {
+        p_sout_buffer->p_buffer[(*pi_pos)++] =
+                GetBits( &p_pack->bit_stream, 8 );
+        i_copy++;
+
+        if( *pi_pos + 2048 > p_sout_buffer->i_allocated_size )
+        {
+            sout_BufferRealloc( p_pack->p_sout_input->p_sout,
+                                p_sout_buffer,
+                                p_sout_buffer->i_allocated_size + 50 * 1024);
+        }
+
+    } while( ShowBits( &p_pack->bit_stream, 24 ) != 0x01 &&
+             !p_pack->p_fifo->b_die && !p_pack->p_fifo->b_error );
+
+    return( i_copy );
+}
+
+/*****************************************************************************
+ * PacketizeThread: packetize an unit (here copy a complete pes)
+ *****************************************************************************/
+static void PacketizeThread( packetizer_t *p_pack )
+{
+    sout_buffer_t *p_sout_buffer = NULL;
+    int32_t i_pos;
+    int i_temporal_ref = 0;
+    int i_skipped;
+
+    if( !p_pack->p_sout_input )
+    {
+        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
+         * after the input is created */
+        i_skipped = 0;
+        while( ShowBits( &p_pack->bit_stream, 32 ) != 0x1B3 )
+        {
+            RemoveBits( &p_pack->bit_stream, 8 );
+            i_skipped++;
+        }
+        msg_Warn( p_pack->p_fifo, "sequence_header_code found (%d skipped)",
+                 i_skipped );
+
+        /* copy the start_code */
+        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 );
+        /* vertical_size_value */
+        p_bih->biHeight = 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 = 0x6D706732; /* mpg2 */
+        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;
+
+        /* intra_quantiser_matrix [non_intra_quantiser_matrix] */
+        if( ShowBits( &p_pack->bit_stream, 7 ) & 0x1 )
+        {
+
+            GetChunk( &p_pack->bit_stream, p_temp + i_pos, 64 ); i_pos += 64;
+
+            if( ShowBits( &p_pack->bit_stream, 8 ) & 0x1 )
+            {
+                GetChunk( &p_pack->bit_stream, p_temp + i_pos, 65); i_pos += 65;
+            }
+        }
+        /* non_intra_quantiser_matrix */
+        else if( ShowBits( &p_pack->bit_stream, 8 ) & 0x1 )
+        {
+            GetChunk( &p_pack->bit_stream, p_temp + i_pos, 65); i_pos += 65;
+        }
+        /* nothing */
+        else
+        {
+            GetChunk( &p_pack->bit_stream, p_temp + i_pos, 1 ); i_pos += 1;
+        }
+
+        /* sequence_extension (10 bytes) */
+        if( ShowBits( &p_pack->bit_stream, 32 ) != 0x1B5 )
+            msg_Dbg( p_pack->p_fifo, "ARRGG no extension_start_code" );
+        else
+            GetChunk( &p_pack->bit_stream, p_temp + i_pos, 10 ); i_pos += 10;
+
+        /* remember sequence_header and sequence_extention */
+        memcpy( p_pack->p_sequence_header, p_temp, i_pos );
+        p_pack->i_sequence_header_length = i_pos;
+
+        p_pack->d_frame_rate =  pd_frame_rates[i_frame_rate_code];
+
+        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 );
+
+        /* now we have informations to create the input */
+        p_pack->p_sout_input = sout_InputNew( p_pack->p_fifo,
+                                              &p_pack->output_format );
+
+        if( !p_pack->p_sout_input )
+        {
+            msg_Err( p_pack->p_fifo, "cannot add a new stream" );
+            return;
+        }
+
+        p_sout_buffer = sout_BufferNew( p_pack->p_sout_input->p_sout,
+                                        100 * 1024 );
+        p_sout_buffer->i_size = i_pos;
+        memcpy( p_sout_buffer->p_buffer, p_temp, i_pos );
+
+    }
+    else
+    {
+        p_sout_buffer =
+                sout_BufferNew( p_pack->p_sout_input->p_sout, 100 * 1024 );
+        i_pos = 0;
+    }
+
+    p_pack->i_last_sequence_header++;
+
+    for( ;; )
+    {
+        uint32_t i_code;
+        if( p_pack->p_fifo->b_die || p_pack->p_fifo->b_error )
+        {
+            break;
+        }
+
+        i_code = ShowBits( &p_pack->bit_stream, 32 );
+
+        if( i_code == 0x1B8 ) /* GOP */
+        {
+            /* usefull for bad MPEG-1 : repeat the sequence_header
+               every second */
+            if( p_pack->i_last_sequence_header > (int) p_pack->d_frame_rate )
+            {
+               memcpy( p_sout_buffer->p_buffer + i_pos,
+                       p_pack->p_sequence_header,
+                       p_pack->i_sequence_header_length );
+               i_pos += p_pack->i_sequence_header_length;
+               p_pack->i_last_sequence_header = 0;
+            }
+
+            p_pack->i_last_ref_pts =
+                   p_pack->i_last_dts + 40000; /* FIXME */
+            CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos );
+        }
+        else if( i_code == 0x100 ) /* Picture */
+        {
+            /* picture_start_code */
+            GetChunk( &p_pack->bit_stream,
+                      p_sout_buffer->p_buffer + i_pos, 4 ); i_pos += 4;
+            i_temporal_ref = ShowBits( &p_pack->bit_stream, 10 );
+
+            CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos );
+            break;
+        }
+        else
+        {
+            if( i_code == 0x1B3 )
+            {
+                p_pack->i_last_sequence_header = 0;
+            }
+            CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos );
+        }
+    }
+
+    sout_BufferRealloc( p_pack->p_sout_input->p_sout,
+                        p_sout_buffer, i_pos );
+    p_sout_buffer->i_size = i_pos;
+
+    p_sout_buffer->i_dts = p_pack->i_last_dts;
+    p_sout_buffer->i_pts = p_pack->i_last_ref_pts +
+        i_temporal_ref * (mtime_t)( 1000000 / p_pack->d_frame_rate );
+
+    p_sout_buffer->i_length = (uint64_t)1000000 / p_pack->d_frame_rate;
+    p_sout_buffer->i_bitrate = (int)( 8 * i_pos * p_pack->d_frame_rate );
+
+//    msg_Dbg( p_pack->p_fifo, "frame length %d b", i_pos );
+
+    sout_InputSendBuffer( p_pack->p_sout_input, p_sout_buffer );
+
+    p_pack->i_last_dts += (mtime_t)( 1000000 / p_pack->d_frame_rate );
+}
+
+
+/*****************************************************************************
+ * EndThread : packetizer thread destruction
+ *****************************************************************************/
+static void EndThread ( packetizer_t *p_pack)
+{
+    if( p_pack->p_sout_input )
+    {
+        sout_InputDelete( p_pack->p_sout_input );
+    }
+}
index 783ac551d20b34ccb01bbd7fc547ed5284ea64d2..89965c1fe79c8ef42808013dfa3b27a4dfa8e194 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.52 2002/12/06 16:34:08 sam Exp $
+ * $Id: input_dec.c,v 1.53 2002/12/14 21:32:42 fenrir Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -44,6 +44,7 @@ static void             DeleteDecoderFifo( decoder_fifo_t * );
 decoder_fifo_t * input_RunDecoder( input_thread_t * p_input,
                                    es_descriptor_t * p_es )
 {
+    char           *psz_sout;
     decoder_fifo_t *p_fifo;
     int i_priority;
 
@@ -56,8 +57,23 @@ decoder_fifo_t * input_RunDecoder( input_thread_t * p_input,
         return NULL;
     }
 
+    p_fifo->p_module = NULL;
+    /* If we are in sout mode, search first for packetizer module then
+     * codec to do transcoding */
+    psz_sout = config_GetPsz( p_input, "sout" );
+    if( psz_sout != NULL && *psz_sout != 0 )
+    {
+        p_fifo->p_module = module_Need( p_fifo, "packetizer", "$packetizer" );
+    }
+    /* default Get a suitable decoder module */
+    if( p_fifo->p_module == NULL )
+    {
+        p_fifo->p_module = module_Need( p_fifo, "decoder", "$codec" );
+    }
+#if 0
     /* Get a suitable module */
     p_fifo->p_module = module_Need( p_fifo, "decoder", "$codec" );
+#endif
     if( p_fifo->p_module == NULL )
     {
         msg_Err( p_fifo, "no suitable decoder module for fourcc `%4.4s'",
index b0e05a9f53c18899a42b163eee6716d732d07c0b..e466f18f57ee38f1d4ae204acf055308f825cae8 100644 (file)
@@ -2,7 +2,7 @@
  * libvlc.h: main libvlc header
  *****************************************************************************
  * Copyright (C) 1998-2002 VideoLAN
- * $Id: libvlc.h,v 1.28 2002/12/09 00:52:42 babal Exp $
+ * $Id: libvlc.h,v 1.29 2002/12/14 21:32:42 fenrir Exp $
  *
  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
 #define SOUT_TEXT N_("choose a stream output")
 #define SOUT_LONGTEXT N_( \
     "Empty if no stream output.")
+#define PACKETIZER_TEXT N_("choose prefered packetizer list")
+#define PACKETIZER_LONGTEXT N_( \
+    "This allows you to select the order in which vlc will choose its " \
+    "packetizers."  )
+#define MUX_TEXT N_("mux module")
+#define MUX_LONGTEXT N_( \
+    "This is a legacy entry to let you configure mux modules")
+#define ACCESS_OUTPUT_TEXT N_("access output module")
+#define ACCESS_OUTPUT_LONGTEXT N_( \
+    "This is a legacy entry to let you configure access output modules")
+
 
 #define MMX_TEXT N_("enable CPU MMX support")
 #define MMX_LONGTEXT N_( \
@@ -475,6 +486,13 @@ vlc_module_begin();
     add_category_hint( N_("Decoders"), NULL );
     add_module( "codec", "decoder", NULL, NULL, CODEC_TEXT, CODEC_LONGTEXT );
 
+    /* Stream output */
+    add_category_hint( N_("Stream output"), NULL );
+    add_module( "packetizer", "packetizer", NULL, NULL, PACKETIZER_TEXT, PACKETIZER_LONGTEXT );
+    add_module( "mux", "mux", NULL, NULL, MUX_TEXT, MUX_LONGTEXT );
+    add_module( "access_output", "access_output", NULL, NULL, ACCESS_OUTPUT_TEXT, ACCESS_OUTPUT_LONGTEXT );
+    add_string( "sout", NULL, NULL, SOUT_TEXT, SOUT_LONGTEXT );
+
     /* CPU options */
     add_category_hint( N_("CPU"), NULL );
 #if defined( __i386__ )
@@ -504,7 +522,6 @@ vlc_module_begin();
     add_module( "memcpy", "memcpy", NULL, NULL, MEMCPY_TEXT, MEMCPY_LONGTEXT );
     add_module( "access", "access", NULL, NULL, ACCESS_TEXT, ACCESS_LONGTEXT );
     add_module( "demux", "demux", NULL, NULL, DEMUX_TEXT, DEMUX_LONGTEXT );
-    add_string( "sout", NULL, NULL, SOUT_TEXT, SOUT_LONGTEXT );
 
 #if defined(WIN32)
     add_bool( "fast-mutex", 0, NULL, FAST_MUTEX_TEXT, FAST_MUTEX_LONGTEXT );
index 21bfd720c12b7ac6c7f6b1ef8a6409791995c628..28c5d39392dd5bac504cc1e56dc1873c387745ba 100644 (file)
@@ -2,9 +2,11 @@
  * stream_output.c : stream output module
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: stream_output.c,v 1.5 2002/11/11 14:39:12 sam Exp $
+ * $Id: stream_output.c,v 1.6 2002/12/14 21:32:42 fenrir Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
+ *          Laurent Aimar <fenrir@via.ecp.fr>
+ *          Erioc Petit <titer@videolan.org>
  *
  * 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
@@ -31,7 +33,7 @@
 #include <vlc/vlc.h>
 
 #include <vlc/sout.h>
-
+#undef DEBUG_BUFFER
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -53,13 +55,16 @@ sout_instance_t * __sout_NewInstance ( vlc_object_t *p_parent,
         return NULL;
     }
 
-    p_sout->psz_dest = psz_dest;
+    p_sout->psz_dest = strdup( psz_dest );
+
     if ( InitInstance( p_sout ) == -1 )
     {
         vlc_object_destroy( p_sout );
         return NULL;
     }
 
+    vlc_object_attach( p_sout, p_parent );
+
     return p_sout;
 }
 
@@ -72,6 +77,15 @@ static int InitInstance( sout_instance_t * p_sout )
     /* This code is identical to input.c:InitThread. FIXME : factorize it ? */
     char * psz_parser = p_sout->psz_dest;
 
+    p_sout->psz_access = "";
+    p_sout->psz_mux = "";
+    p_sout->psz_name = "";
+    p_sout->p_access = NULL;
+    p_sout->p_mux = NULL;
+    p_sout->i_nb_inputs = 0;
+    p_sout->pp_inputs = NULL;
+    vlc_mutex_init( p_sout, &p_sout->lock );
+
     /* Skip the plug-in names */
     while( *psz_parser && *psz_parser != ':' )
     {
@@ -170,6 +184,9 @@ static int InitInstance( sout_instance_t * p_sout )
         return -1;
     }
 
+    p_sout->i_nb_inputs = 0;
+    p_sout->pp_inputs = NULL;
+
     return 0;
 }
 
@@ -181,8 +198,343 @@ void sout_DeleteInstance( sout_instance_t * p_sout )
 {
     /* Unlink object */
     vlc_object_detach( p_sout );
+    if( p_sout->p_mux )
+    {
+        module_Unneed( p_sout, p_sout->p_mux );
+    }
+    if( p_sout->p_access )
+    {
+        module_Unneed( p_sout, p_sout->p_access );
+    }
+
+    vlc_mutex_destroy( &p_sout->lock );
 
     /* Free structure */
     vlc_object_destroy( p_sout );
 }
 
+
+/*****************************************************************************
+ *
+ *****************************************************************************/
+sout_input_t *__sout_InputNew( vlc_object_t *p_this,
+                                sout_packet_format_t *p_format )
+{
+    sout_instance_t *p_sout = NULL;
+    sout_input_t    *p_input;
+    int             i_try;
+
+    /* search an stream output */
+    for( i_try = 0; i_try < 200; 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 new sout input */
+    p_input = malloc( sizeof( sout_input_t ) );
+
+    p_input->p_sout = p_sout;
+    vlc_mutex_init( p_sout, &p_input->lock );
+    memcpy( &p_input->input_format,
+            p_format,
+            sizeof( sout_packet_format_t ) );
+    p_input->p_fifo = sout_FifoCreate( p_sout );
+    p_input->p_mux_data = NULL;
+
+    /* add this new one to p_sout */
+    vlc_mutex_lock( &p_sout->lock );
+    if( p_sout->i_nb_inputs == 0 )
+    {
+        p_sout->pp_inputs = malloc( sizeof( sout_input_t * ) );
+    }
+    else
+    {
+        p_sout->pp_inputs = realloc( p_sout->pp_inputs,
+                                    sizeof( sout_input_t * ) *
+                                            ( p_sout->i_nb_inputs + 1 ) );
+    }
+    p_sout->pp_inputs[p_sout->i_nb_inputs] = p_input;
+    p_sout->i_nb_inputs++;
+
+    if( p_sout->pf_mux_addstream( p_sout, p_input ) < 0 )
+    {
+        /* vlc_mutex_unlock( &p_sout->lock ); */
+        msg_Err( p_sout, "cannot add this stream" );
+        /* FIXME FIXME */
+    }
+    vlc_mutex_unlock( &p_sout->lock );
+
+    vlc_object_release( p_sout );
+
+    return( p_input );
+}
+
+
+int sout_InputDelete( sout_input_t *p_input )
+{
+    sout_instance_t     *p_sout = p_input->p_sout;
+    int                 i_input;
+
+
+    vlc_mutex_lock( &p_sout->lock );
+    for( i_input = 0; i_input < p_sout->i_nb_inputs; i_input++ )
+    {
+        if( p_sout->pp_inputs[i_input] == p_input )
+        {
+            break;
+        }
+    }
+
+    if( i_input >= p_sout->i_nb_inputs )
+    {
+        msg_Err( p_sout, "cannot find input to delete" );
+        return( -1 );
+    }
+
+    msg_Dbg( p_sout, "removing an input" );
+
+    if( p_sout->pf_mux_delstream( p_sout, p_input ) < 0 )
+    {
+        msg_Err( p_sout, "cannot del this stream" );
+        /* FIXME FIXME */
+    }
+
+    /* remove the entry */
+    if( p_sout->i_nb_inputs > 1 )
+    {
+        memmove( &p_sout->pp_inputs[i_input],
+                 &p_sout->pp_inputs[i_input+1],
+                 (p_sout->i_nb_inputs - i_input - 1) * sizeof( sout_input_t*) );
+    }
+    else
+    {
+        free( p_sout->pp_inputs );
+    }
+    p_sout->i_nb_inputs--;
+
+    /* FIXME --> send message to mux to declare this stream removing */
+
+    sout_FifoDestroy( p_sout, p_input->p_fifo );
+    vlc_mutex_destroy( &p_input->lock );
+    free( p_input );
+
+    if( p_sout->i_nb_inputs == 0 )
+    {
+        msg_Warn( p_sout, "no more input stream" );
+    }
+    vlc_mutex_unlock( &p_sout->lock );
+
+    return( 0 );
+}
+
+
+int sout_InputSendBuffer( sout_input_t *p_input, sout_buffer_t *p_buffer )
+{
+/*    msg_Dbg( p_input->p_sout,
+             "send buffer, size:%d", p_buffer->i_size ); */
+    sout_FifoPut( p_input->p_fifo, p_buffer );
+
+    vlc_mutex_lock( &p_input->p_sout->lock );
+    p_input->p_sout->pf_mux( p_input->p_sout );
+    vlc_mutex_unlock( &p_input->p_sout->lock );
+    return( 0 );
+}
+
+sout_fifo_t *sout_FifoCreate( sout_instance_t *p_sout )
+{
+    sout_fifo_t *p_fifo;
+
+    if( !( p_fifo = malloc( sizeof( sout_fifo_t ) ) ) )
+    {
+        return( NULL );
+    }
+
+    vlc_mutex_init( p_sout, &p_fifo->lock );
+    vlc_cond_init ( p_sout, &p_fifo->wait );
+    p_fifo->i_depth = 0;
+    p_fifo->p_first = NULL;
+    p_fifo->pp_last = &p_fifo->p_first;
+
+    return( p_fifo );
+}
+
+void       sout_FifoFree( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
+{
+    sout_buffer_t *p_buffer;
+
+    vlc_mutex_lock( &p_fifo->lock );
+    p_buffer = p_fifo->p_first;
+    while( p_buffer )
+    {
+        sout_buffer_t *p_next;
+        p_next = p_buffer->p_next;
+        sout_BufferDelete( p_sout, p_buffer );
+        p_buffer = p_next;
+    }
+    vlc_mutex_unlock( &p_fifo->lock );
+
+    return;
+}
+void       sout_FifoDestroy( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
+{
+    sout_FifoFree( p_sout, p_fifo );
+    vlc_mutex_destroy( &p_fifo->lock );
+    vlc_cond_destroy ( &p_fifo->wait );
+
+    free( p_fifo );
+}
+
+void        sout_FifoPut( sout_fifo_t *p_fifo, sout_buffer_t *p_buffer )
+{
+    vlc_mutex_lock( &p_fifo->lock );
+
+    do
+    {
+        *p_fifo->pp_last = p_buffer;
+        p_fifo->pp_last = &p_buffer->p_next;
+        p_fifo->i_depth++;
+
+        p_buffer = p_buffer->p_next;
+
+    } while( p_buffer );
+
+    /* warm there is data in this fifo */
+    vlc_cond_signal( &p_fifo->wait );
+    vlc_mutex_unlock( &p_fifo->lock );
+}
+
+sout_buffer_t *sout_FifoGet( sout_fifo_t *p_fifo )
+{
+    sout_buffer_t *p_buffer;
+
+    vlc_mutex_lock( &p_fifo->lock );
+
+    if( p_fifo->p_first == NULL )
+    {
+        vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
+    }
+
+    p_buffer = p_fifo->p_first;
+
+    p_fifo->p_first = p_buffer->p_next;
+    p_fifo->i_depth--;
+
+    if( p_fifo->p_first == NULL )
+    {
+        p_fifo->pp_last = &p_fifo->p_first;
+    }
+
+    vlc_mutex_unlock( &p_fifo->lock );
+
+    p_buffer->p_next = NULL;
+    return( p_buffer );
+}
+
+sout_buffer_t *sout_FifoShow( sout_fifo_t *p_fifo )
+{
+    sout_buffer_t *p_buffer;
+
+    vlc_mutex_lock( &p_fifo->lock );
+
+    if( p_fifo->p_first == NULL )
+    {
+        vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
+    }
+
+    p_buffer = p_fifo->p_first;
+
+    vlc_mutex_unlock( &p_fifo->lock );
+
+    return( p_buffer );
+}
+
+sout_buffer_t *sout_BufferNew( sout_instance_t *p_sout, size_t i_size )
+{
+    sout_buffer_t *p_buffer;
+
+#ifdef DEBUG_BUFFER
+    msg_Dbg( p_sout, "allocating an new buffer, size:%d", (uint32_t)i_size );
+#endif
+
+    p_buffer = malloc( sizeof( sout_buffer_t ) );
+    if( i_size > 0 )
+    {
+        p_buffer->p_buffer = malloc( i_size );
+    }
+    else
+    {
+        p_buffer->p_buffer = NULL;
+    }
+    p_buffer->i_allocated_size = i_size;
+    p_buffer->i_size = i_size;
+    p_buffer->p_next = NULL;
+
+    return( p_buffer );
+}
+int sout_BufferRealloc( sout_instance_t *p_sout, sout_buffer_t *p_buffer, size_t i_size )
+{
+#ifdef DEBUG_BUFFER
+    msg_Dbg( p_sout,
+             "realloc buffer old size:%d new size:%d",
+             (uint32_t)p_buffer->i_allocated_size,
+             (uint32_t)i_size );
+#endif
+    if( !( p_buffer->p_buffer = realloc( p_buffer->p_buffer, i_size ) ) )
+    {
+        msg_Err( p_sout, "realloc failed" );
+        p_buffer->i_allocated_size = 0;
+        p_buffer->i_size = 0;
+
+        return( -1 );
+    }
+
+    p_buffer->i_allocated_size = i_size;
+    return( 0 );
+}
+
+int sout_BufferDelete( sout_instance_t *p_sout, sout_buffer_t *p_buffer )
+{
+#ifdef DEBUG_BUFFER
+    msg_Dbg( p_sout, "freeing buffer, size:%d", p_buffer->i_size );
+#endif
+    if( p_buffer->p_buffer )
+    {
+        free( p_buffer->p_buffer );
+    }
+    free( p_buffer );
+    return( 0 );
+}
+
+sout_buffer_t *sout_BufferDuplicate( sout_instance_t *p_sout,
+                                     sout_buffer_t *p_buffer )
+{
+    sout_buffer_t *p_dup;
+
+    p_dup = sout_BufferNew( p_sout, p_buffer->i_size );
+
+    p_dup->i_bitrate= p_buffer->i_bitrate;
+    p_dup->i_dts    = p_buffer->i_dts;
+    p_dup->i_pts    = p_buffer->i_pts;
+    p_dup->i_length = p_buffer->i_length;
+    memcpy( p_dup->p_buffer, p_buffer->p_buffer, p_buffer->i_size );
+
+    return( p_dup );
+}
+