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
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,,[
[ --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
* 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
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
*****************************************************************************/
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 * ) );
* 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>
/* 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;
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 \
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 \
--- /dev/null
+.deps
+.dirstamp
--- /dev/null
+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
--- /dev/null
+/*****************************************************************************
+ * 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 );
+}
+
+
+
--- /dev/null
+/*****************************************************************************
+ * 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 ) );
+}
+
+
+
--- /dev/null
+/*****************************************************************************
+ * 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 );
+ }
+}
+
+
--- /dev/null
+.deps
+.dirstamp
--- /dev/null
+SOURCES_mux_dummy = modules/mux/dummy.c
--- /dev/null
+/*****************************************************************************
+ * 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 );
+}
+
--- /dev/null
+.deps
+.dirstamp
--- /dev/null
+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)
+
+
--- /dev/null
+/*****************************************************************************
+ * 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--;
+ }
+}
+
+
--- /dev/null
+/*****************************************************************************
+ * 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 );
+}
+
--- /dev/null
+/*****************************************************************************
+ * 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 );
--- /dev/null
+/*****************************************************************************
+ * 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 );
+}
+
--- /dev/null
+/*****************************************************************************
+ * 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 );
+}
+
+
--- /dev/null
+.deps
+.dirstamp
--- /dev/null
+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
--- /dev/null
+/*****************************************************************************
+ * 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;
+ }
+}
+
+
--- /dev/null
+/*****************************************************************************
+ * 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 );
+ }
+}
+
--- /dev/null
+/*****************************************************************************
+ * 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 );
+ }
+}
+
--- /dev/null
+/*****************************************************************************
+ * 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 );
+ }
+}
--- /dev/null
+/*****************************************************************************
+ * 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 );
+ }
+}
* 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>
*
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;
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'",
* 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_( \
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__ )
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 );
* 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
#include <vlc/vlc.h>
#include <vlc/sout.h>
-
+#undef DEBUG_BUFFER
/*****************************************************************************
* Local prototypes
*****************************************************************************/
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;
}
/* 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 != ':' )
{
return -1;
}
+ p_sout->i_nb_inputs = 0;
+ p_sout->pp_inputs = NULL;
+
return 0;
}
{
/* 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 );
+}
+