demux plugins (ps, ts, but also dvd*).
* ./src/input/mpeg_system.c: removed MPEG-related stuff from the vlc core.
* ./src/misc/modules.c: max recursion level is now 5.
* ./modules/access/dvdplay/es.c: fixed a buffer overflow.
LIBVLC := libvlc
INTERFACE := interface intf_eject
PLAYLIST := playlist
-INPUT := input input_ext-plugins input_ext-dec input_ext-intf input_dec input_programs input_clock mpeg_system input_info
+INPUT := input input_ext-plugins input_ext-dec input_ext-intf input_dec input_programs input_clock input_info
VIDEO_OUTPUT := video_output video_text vout_pictures vout_subpictures
AUDIO_OUTPUT := audio_output aout_ext-dec aout_pcm aout_spdif
MISC := mtime modules threads cpu configuration netutils iso_lang messages objects extras
# Build environment
#
CC = @CC@
-CFLAGS = @CFLAGS@
+CFLAGS += @CFLAGS@
SHELL = @SHELL@
RANLIB = @RANLIB@
STRIP = @STRIP@
#! /bin/sh
## bootstrap.sh file for vlc, the VideoLAN Client
-## $Id: bootstrap.sh,v 1.8 2002/07/21 15:27:09 sam Exp $
+## $Id: bootstrap.sh,v 1.9 2002/08/07 00:29:36 sam Exp $
##
## Authors: Samuel Hocevar <sam@zoy.org>
echo -n " + fixing glade bugs: "
for file in gnome_interface.c gtk_interface.c
do
-if grep -q "DO NOT EDIT THIS FILE" plugins/gtk/$file
+if grep -q "DO NOT EDIT THIS FILE" modules/gui/gtk/$file
then
rm -f /tmp/$$.$file.bak
cat > /tmp/$$.$file.bak << EOF
#include <vlc/vlc.h>
EOF
- tail +8 plugins/gtk/$file \
+ tail +8 modules/gui/gtk/$file \
| sed 's#DISABLED!!!_("/dev/dvd")#config_GetPsz( "dvd" )#' \
| sed 's#DISABLED!!!11954#config_GetInt( "frequency" )#' \
| sed 's#DISABLED!!!27500#config_GetInt( "symbol-rate" )#' \
| sed 's#_("/dev/dvd")#"/dev/dvd"#' \
| sed 's#_(\("./."\))#\1#' \
>> /tmp/$$.$file.bak
- mv -f /tmp/$$.$file.bak plugins/gtk/$file
+ mv -f /tmp/$$.$file.bak modules/gui/gtk/$file
fi
echo -n "$file "
done
file=gtk_support.h
-if grep -q "DO NOT EDIT THIS FILE" plugins/gtk/$file
+if grep -q "DO NOT EDIT THIS FILE" modules/gui/gtk/$file
then
rm -f /tmp/$$.$file.bak
- sed 's/DO NOT EDIT THIS FILE.*/This file was created automatically by glade and fixed by bootstrap.sh/ ; s/#if.*ENABLE_NLS.*/#if defined( ENABLE_NLS ) \&\& defined ( HAVE_GETTEXT )/' < plugins/gtk/$file > /tmp/$$.$file.bak
- mv -f /tmp/$$.$file.bak plugins/gtk/$file
+ sed 's/DO NOT EDIT THIS FILE.*/This file was created automatically by glade and fixed by bootstrap.sh/ ; s/#if.*ENABLE_NLS.*/#if defined( ENABLE_NLS ) \&\& defined ( HAVE_GETTEXT )/' < modules/gui/gtk/$file > /tmp/$$.$file.bak
+ mv -f /tmp/$$.$file.bak modules/gui/gtk/$file
fi
echo "$file."
BUILTINS="${BUILTINS}"
PLUGINS="${PLUGINS} misc/dummy/dummy misc/null/null"
PLUGINS="${PLUGINS} control/rc/rc misc/logger/logger access/file access/udp access/http misc/network/ipv4 misc/memcpy/memcpy"
-PLUGINS="${PLUGINS} demux/mpeg/es demux/mpeg/audio demux/mpeg/ps demux/mpeg/ts"
+PLUGINS="${PLUGINS} demux/mpeg/es demux/mpeg/audio demux/mpeg/mpeg_system demux/mpeg/ps demux/mpeg/ts"
PLUGINS="${PLUGINS} codec/mpeg_video/idct/idct codec/mpeg_video/idct/idctclassic codec/mpeg_video/motion/motion codec/a52old/imdct/imdct codec/a52old/downmix/downmix codec/mpeg_audio/mpeg_audio codec/a52old/a52old codec/mpeg_video/mpeg_video codec/lpcm/lpcm codec/spdif/spdif codec/spudec/spudec"
PLUGINS="${PLUGINS} video_filter/deinterlace/deinterlace video_filter/invert video_filter/wall video_filter/transform video_filter/distort video_filter/clone video_filter/crop"
PLUGINS="${PLUGINS} visualization/scope/scope"
BUILTINS="${BUILTINS}"
PLUGINS="${PLUGINS} misc/dummy/dummy misc/null/null"
PLUGINS="${PLUGINS} control/rc/rc misc/logger/logger access/file access/udp access/http misc/network/ipv4 misc/memcpy/memcpy"
-PLUGINS="${PLUGINS} demux/mpeg/es demux/mpeg/audio demux/mpeg/ps demux/mpeg/ts"
+PLUGINS="${PLUGINS} demux/mpeg/es demux/mpeg/audio demux/mpeg/mpeg_system demux/mpeg/ps demux/mpeg/ts"
PLUGINS="${PLUGINS} codec/mpeg_video/idct/idct codec/mpeg_video/idct/idctclassic codec/mpeg_video/motion/motion codec/a52old/imdct/imdct codec/a52old/downmix/downmix codec/mpeg_audio/mpeg_audio codec/a52old/a52old codec/mpeg_video/mpeg_video codec/lpcm/lpcm codec/spdif/spdif codec/spudec/spudec"
PLUGINS="${PLUGINS} video_filter/deinterlace/deinterlace video_filter/invert video_filter/wall video_filter/transform video_filter/distort video_filter/clone video_filter/crop"
PLUGINS="${PLUGINS} visualization/scope/scope"
* input_ext-dec.h: structures exported to the VideoLAN decoders
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
- * $Id: input_ext-dec.h,v 1.66 2002/08/04 17:23:41 sam Exp $
+ * $Id: input_ext-dec.h,v 1.67 2002/08/07 00:29:36 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Michel Kaempf <maxx@via.ecp.fr>
/* Standard pointers given to the decoders as a toolbox. */
u16 i_id;
vlc_fourcc_t i_fourcc;
- void * p_demux_data;
+ es_sys_t * p_demux_data;
stream_ctrl_t * p_stream_ctrl;
/* Module properties */
* control the pace of reading.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
- * $Id: input_ext-intf.h,v 1.74 2002/08/04 17:23:41 sam Exp $
+ * $Id: input_ext-intf.h,v 1.75 2002/08/07 00:29:36 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* available */
/* Demultiplexer information */
- void * p_demux_data;
+ es_sys_t * p_demux_data;
pgrm_descriptor_t * p_pgrm; /* very convenient in the demultiplexer */
/* PES parser information */
int i_synchro_state;
/* Demultiplexer data */
- void * p_demux_data;
+ pgrm_sys_t * p_demux_data;
int i_es_number; /* size of the following array */
es_descriptor_t ** pp_es; /* array of pointers to ES */
* status change request */
/* Demultiplexer data */
- void * p_demux_data;
+ stream_sys_t * p_demux_data;
/* Programs descriptions */
int i_pgrm_number; /* size of the following array */
int (* pf_set_program )( input_thread_t *, pgrm_descriptor_t * );
int (* pf_set_area )( input_thread_t *, input_area_t * );
void (* pf_seek ) ( input_thread_t *, off_t );
- void * p_access_data;
+ access_sys_t * p_access_data;
size_t i_mtu;
/* Demux module */
int (* pf_rewind ) ( input_thread_t * );
/* NULL if we don't support going *
* backwards (it's gonna be fun) */
- void * p_demux_data; /* data of the demux */
+ demux_sys_t * p_demux_data; /* data of the demux */
/* Buffer manager */
input_buffers_t *p_method_data; /* data of the packet manager */
* but exported to plug-ins
*****************************************************************************
* Copyright (C) 1999-2002 VideoLAN
- * $Id: input_ext-plugins.h,v 1.33 2002/07/31 20:56:50 sam Exp $
+ * $Id: input_ext-plugins.h,v 1.34 2002/08/07 00:29:36 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
}
}
-
-/*
- * Optional MPEG demultiplexing
- */
-
-/*****************************************************************************
- * Constants
- *****************************************************************************/
-#define TS_PACKET_SIZE 188 /* Size of a TS packet */
-#define TS_SYNC_CODE 0x47 /* First byte of a TS packet */
-#define PSI_SECTION_SIZE 4096 /* Maximum size of a PSI section */
-
-#define PAT_UNINITIALIZED (1 << 6)
-#define PMT_UNINITIALIZED (1 << 6)
-
-#define PSI_IS_PAT 0x00
-#define PSI_IS_PMT 0x01
-#define UNKNOWN_PSI 0xff
-
-/****************************************************************************
- * psi_callback_t
- ****************************************************************************
- * Used by TS demux to handle a PSI, either with the builtin decoder, either
- * with a library such as libdvbpsi
- ****************************************************************************/
-typedef void( * psi_callback_t )(
- input_thread_t * p_input,
- data_packet_t * p_data,
- es_descriptor_t * p_es,
- vlc_bool_t b_unit_start );
-
-
-/*****************************************************************************
- * psi_section_t
- *****************************************************************************
- * Describes a PSI section. Beware, it doesn't contain pointers to the TS
- * packets that contain it as for a PES, but the data themselves
- *****************************************************************************/
-typedef struct psi_section_t
-{
- byte_t buffer[PSI_SECTION_SIZE];
-
- u8 i_section_number;
- u8 i_last_section_number;
- u8 i_version_number;
- u16 i_section_length;
- u16 i_read_in_section;
-
- /* the PSI is complete */
- vlc_bool_t b_is_complete;
-
- /* packet missed up ? */
- vlc_bool_t b_trash;
-
- /*about sections */
- vlc_bool_t b_section_complete;
-
- /* where are we currently ? */
- byte_t * p_current;
-
-} psi_section_t;
-
-/*****************************************************************************
- * es_ts_data_t: extension of es_descriptor_t
- *****************************************************************************/
-typedef struct es_ts_data_t
-{
- vlc_bool_t b_psi; /* Does the stream have to be handled by
- * the PSI decoder ? */
-
- int i_psi_type; /* There are different types of PSI */
-
- psi_section_t * p_psi_section; /* PSI packets */
-
- /* Markers */
- int i_continuity_counter;
-} es_ts_data_t;
-
-/*****************************************************************************
- * pgrm_ts_data_t: extension of pgrm_descriptor_t
- *****************************************************************************/
-typedef struct pgrm_ts_data_t
-{
- u16 i_pcr_pid; /* PCR ES, for TS streams */
- int i_pmt_version;
- /* libdvbpsi pmt decoder handle */
- void * p_pmt_handle;
-} pgrm_ts_data_t;
-
-/*****************************************************************************
- * stream_ts_data_t: extension of stream_descriptor_t
- *****************************************************************************/
-typedef struct stream_ts_data_t
-{
- int i_pat_version; /* Current version of the PAT */
- /* libdvbpsi pmt decoder handle */
- void * p_pat_handle;
-} stream_ts_data_t;
-
-/*****************************************************************************
- * stream_ps_data_t: extension of stream_descriptor_t
- *****************************************************************************/
-typedef struct stream_ps_data_t
-{
- vlc_bool_t b_has_PSM; /* very rare, in fact */
-
- u8 i_PSM_version;
-} stream_ps_data_t;
-
-/* PSM version is 5 bits, so -1 is not a valid value */
-#define EMPTY_PSM_VERSION -1
-
-
-/*****************************************************************************
- * Prototypes
- *****************************************************************************/
-VLC_EXPORT( void, input_ParsePES, ( input_thread_t *, es_descriptor_t * ) );
-VLC_EXPORT( void, input_GatherPES, ( input_thread_t *, data_packet_t *, es_descriptor_t *, vlc_bool_t, vlc_bool_t ) );
-VLC_EXPORT( ssize_t, input_ReadPS, ( input_thread_t *, data_packet_t ** ) );
-VLC_EXPORT( es_descriptor_t *, input_ParsePS, ( input_thread_t *, data_packet_t * ) );
-VLC_EXPORT( ssize_t, input_ReadTS, ( input_thread_t *, data_packet_t ** ) );
-VLC_EXPORT( void, input_DemuxPS, ( input_thread_t *, data_packet_t * ) );
-VLC_EXPORT( void, input_DemuxTS, ( input_thread_t *, data_packet_t *, void(*) ( input_thread_t *, data_packet_t *, es_descriptor_t *, vlc_bool_t ) ) );
-
/*
* Optional standard file descriptor operations (input_ext-plugins.h)
*/
* Collection of useful common types and macros definitions
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
- * $Id: vlc_common.h,v 1.13 2002/07/31 20:56:50 sam Exp $
+ * $Id: vlc_common.h,v 1.14 2002/08/07 00:29:36 sam Exp $
*
* Authors: Samuel Hocevar <sam@via.ecp.fr>
* Vincent Seguin <seguin@via.ecp.fr>
VLC_DECLARE_STRUCT(module_t)
VLC_DECLARE_STRUCT(module_config_t)
VLC_DECLARE_STRUCT(module_symbols_t)
-VLC_DECLARE_STRUCT(module_functions_t)
/* Interface */
VLC_DECLARE_STRUCT(intf_thread_t)
/* Input */
VLC_DECLARE_STRUCT(input_thread_t)
VLC_DECLARE_STRUCT(input_channel_t)
-VLC_DECLARE_STRUCT(input_cfg_t)
VLC_DECLARE_STRUCT(input_area_t)
VLC_DECLARE_STRUCT(input_buffers_t)
VLC_DECLARE_STRUCT(input_socket_t)
+VLC_DECLARE_STRUCT(input_info_t)
+VLC_DECLARE_STRUCT(input_info_category_t)
+VLC_DECLARE_STRUCT(access_sys_t)
+VLC_DECLARE_STRUCT(demux_sys_t)
+VLC_DECLARE_STRUCT(es_descriptor_t)
+VLC_DECLARE_STRUCT(es_sys_t)
+VLC_DECLARE_STRUCT(pgrm_descriptor_t)
+VLC_DECLARE_STRUCT(pgrm_sys_t)
+VLC_DECLARE_STRUCT(stream_descriptor_t)
+VLC_DECLARE_STRUCT(stream_sys_t)
/* Audio */
VLC_DECLARE_STRUCT(aout_thread_t)
VLC_DECLARE_STRUCT(decoder_fifo_t)
/* Misc */
-VLC_DECLARE_STRUCT(macroblock_t)
VLC_DECLARE_STRUCT(data_packet_t)
VLC_DECLARE_STRUCT(data_buffer_t)
-VLC_DECLARE_STRUCT(downmix_t)
-VLC_DECLARE_STRUCT(imdct_t)
-VLC_DECLARE_STRUCT(complex_t)
-VLC_DECLARE_STRUCT(dm_par_t)
-VLC_DECLARE_STRUCT(es_descriptor_t)
-VLC_DECLARE_STRUCT(pgrm_descriptor_t)
-VLC_DECLARE_STRUCT(stream_descriptor_t)
VLC_DECLARE_STRUCT(stream_position_t)
VLC_DECLARE_STRUCT(stream_ctrl_t)
VLC_DECLARE_STRUCT(pes_packet_t)
VLC_DECLARE_STRUCT(bit_stream_t)
VLC_DECLARE_STRUCT(network_socket_t)
VLC_DECLARE_STRUCT(iso639_lang_t)
-VLC_DECLARE_STRUCT(input_info_t)
-VLC_DECLARE_STRUCT(input_info_category_t)
/*****************************************************************************
* Plug-in stuff
data_packet_t * (* input_ShareBuffer_inner) ( input_buffers_t *, data_buffer_t * ) ;
es_descriptor_t * (* input_AddES_inner) ( input_thread_t *, pgrm_descriptor_t *, u16, size_t ) ;
es_descriptor_t * (* input_FindES_inner) ( input_thread_t *, u16 ) ;
- es_descriptor_t * (* input_ParsePS_inner) ( input_thread_t *, data_packet_t * ) ;
float (* __config_GetFloat_inner) (vlc_object_t *, const char *) ;
input_area_t * (* input_AddArea_inner) ( input_thread_t * ) ;
input_info_category_t * (* input_InfoCategory_inner) ( input_thread_t *, char * ) ;
ssize_t (* input_FDRead_inner) ( input_thread_t *, byte_t *, size_t ) ;
ssize_t (* input_FillBuffer_inner) ( input_thread_t * ) ;
ssize_t (* input_Peek_inner) ( input_thread_t *, byte_t **, size_t ) ;
- ssize_t (* input_ReadPS_inner) ( input_thread_t *, data_packet_t ** ) ;
- ssize_t (* input_ReadTS_inner) ( input_thread_t *, data_packet_t ** ) ;
ssize_t (* input_SplitBuffer_inner) ( input_thread_t *, data_packet_t **, size_t ) ;
subpicture_t * (* vout_CreateSubPicture_inner) ( vout_thread_t *, int, int ) ;
u32 (* UnalignedGetBits_inner) ( bit_stream_t *, unsigned int ) ;
void (* input_DelProgram_inner) ( input_thread_t *, pgrm_descriptor_t * ) ;
void (* input_DeletePES_inner) ( input_buffers_t *, pes_packet_t * ) ;
void (* input_DeletePacket_inner) ( input_buffers_t *, data_packet_t * ) ;
- void (* input_DemuxPS_inner) ( input_thread_t *, data_packet_t * ) ;
- void (* input_DemuxTS_inner) ( input_thread_t *, data_packet_t *, void(*) ( input_thread_t *, data_packet_t *, es_descriptor_t *, vlc_bool_t ) ) ;
void (* input_DumpStream_inner) ( input_thread_t * ) ;
void (* input_EndStream_inner) ( input_thread_t * ) ;
void (* input_FDSeek_inner) ( input_thread_t *, off_t ) ;
- void (* input_GatherPES_inner) ( input_thread_t *, data_packet_t *, es_descriptor_t *, vlc_bool_t, vlc_bool_t ) ;
- void (* input_ParsePES_inner) ( input_thread_t *, es_descriptor_t * ) ;
void (* input_ReleaseBuffer_inner) ( input_buffers_t *, data_buffer_t * ) ;
void (* intf_Destroy_inner) ( intf_thread_t * ) ;
void (* intf_StopThread_inner) ( intf_thread_t * ) ;
# define input_DelProgram p_symbols->input_DelProgram_inner
# define input_DeletePES p_symbols->input_DeletePES_inner
# define input_DeletePacket p_symbols->input_DeletePacket_inner
-# define input_DemuxPS p_symbols->input_DemuxPS_inner
-# define input_DemuxTS p_symbols->input_DemuxTS_inner
# define input_DumpStream p_symbols->input_DumpStream_inner
# define input_EndStream p_symbols->input_EndStream_inner
# define input_FDNetworkRead p_symbols->input_FDNetworkRead_inner
# define input_FillBuffer p_symbols->input_FillBuffer_inner
# define input_FindES p_symbols->input_FindES_inner
# define input_FindProgram p_symbols->input_FindProgram_inner
-# define input_GatherPES p_symbols->input_GatherPES_inner
# define input_InfoCategory p_symbols->input_InfoCategory_inner
# define input_InitStream p_symbols->input_InitStream_inner
# define input_NewBuffer p_symbols->input_NewBuffer_inner
# define input_NewPES p_symbols->input_NewPES_inner
# define input_NewPacket p_symbols->input_NewPacket_inner
# define input_OffsetToTime p_symbols->input_OffsetToTime_inner
-# define input_ParsePES p_symbols->input_ParsePES_inner
-# define input_ParsePS p_symbols->input_ParsePS_inner
# define input_Peek p_symbols->input_Peek_inner
-# define input_ReadPS p_symbols->input_ReadPS_inner
-# define input_ReadTS p_symbols->input_ReadTS_inner
# define input_ReleaseBuffer p_symbols->input_ReleaseBuffer_inner
# define input_SelectES p_symbols->input_SelectES_inner
# define input_SetProgram p_symbols->input_SetProgram_inner
* -udf.* to find files
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
- * $Id: access.c,v 1.1 2002/08/04 17:23:41 sam Exp $
+ * $Id: access.c,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
#include <vlc/vlc.h>
#include <vlc/input.h>
+#include "../../demux/mpeg/system.h"
+
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
/* demux.c: DVD demux functions.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
- * $Id: demux.c,v 1.1 2002/08/04 17:23:41 sam Exp $
+ * $Id: demux.c,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
#include <vlc/vlc.h>
#include <vlc/input.h>
+#include "../../demux/mpeg/system.h"
+
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
/* how many packets DVDDemux will read in each loop */
#define DVD_READ_ONCE 64
+/*****************************************************************************
+ * Private structure
+ *****************************************************************************/
+struct demux_sys_t
+{
+ module_t * p_module;
+ mpeg_demux_t mpeg;
+};
+
/*****************************************************************************
* Local prototypes
*****************************************************************************/
void DVDLaunchDecoders( input_thread_t * );
-/*
- * Data demux functions
- */
-
/*****************************************************************************
- * DVDInit: initializes DVD structures
+ * DVDInit: initialize DVD structures
*****************************************************************************/
int E_(DVDInit) ( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
+ demux_sys_t * p_demux;
if( p_input->stream.i_method != INPUT_METHOD_DVD )
{
return -1;
}
+ p_demux = p_input->p_demux_data = malloc( sizeof(demux_sys_t ) );
+ if( p_demux == NULL )
+ {
+ return -1;
+ }
+
+ p_input->p_private = (void*)&p_demux->mpeg;
+ p_demux->p_module = module_Need( p_input, "mpeg-system", NULL );
+ if( p_demux->p_module == NULL )
+ {
+ free( p_input->p_demux_data );
+ return -1;
+ }
+
p_input->pf_demux = DVDDemux;
p_input->pf_rewind = NULL;
return 0;
}
+/*****************************************************************************
+ * DVDEnd: free DVD structures
+ *****************************************************************************/
+void E_(DVDEnd) ( vlc_object_t *p_this )
+{
+ input_thread_t *p_input = (input_thread_t *)p_this;
+
+ module_Unneed( p_input, p_input->p_demux_data->p_module );
+ free( p_input->p_demux_data );
+}
+
/*****************************************************************************
* DVDDemux
*****************************************************************************/
/* Read headers to compute payload length */
for( i = 0 ; i < DVD_READ_ONCE ; i++ )
{
- i_result = input_ReadPS( p_input, &p_data );
+ i_result = p_input->p_demux_data->mpeg.pf_read_ps( p_input, &p_data );
if( i_result < 0 )
{
return i;
}
- input_DemuxPS( p_input, p_data );
+ p_input->p_demux_data->mpeg.pf_demux_ps( p_input, p_data );
}
return i;
* dvd.c : DVD input module for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
- * $Id: dvd.c,v 1.1 2002/08/04 17:23:41 sam Exp $
+ * $Id: dvd.c,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
void E_(DVDClose) ( vlc_object_t * );
int E_(DVDInit) ( vlc_object_t * );
+void E_(DVDEnd) ( vlc_object_t * );
#ifdef GOD_DAMN_DMCA
static void *p_libdvdcss;
set_callbacks( E_(DVDOpen), E_(DVDClose) );
add_submodule();
set_capability( "demux", 0 );
- set_callbacks( E_(DVDInit), NULL );
+ set_callbacks( E_(DVDInit), E_(DVDEnd) );
#ifdef GOD_DAMN_DMCA
ProbeLibDVDCSS();
#endif
* access.c: access capabilities for dvdplay plugin.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: access.c,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: access.c,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
#include <vlc/vlc.h>
#include <vlc/input.h>
+#include "../../demux/mpeg/system.h"
+
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
* demux.c: demux functions for dvdplay.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
- * $Id: demux.c,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: demux.c,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
#include <vlc/vlc.h>
#include <vlc/input.h>
+#include "../../demux/mpeg/system.h"
+
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
*****************************************************************************/
static int Demux ( input_thread_t * );
+/*****************************************************************************
+ * Private structure
+ *****************************************************************************/
+struct demux_sys_t
+{
+ dvd_data_t * p_dvd;
+
+ module_t * p_module;
+ mpeg_demux_t mpeg;
+};
+
/*****************************************************************************
* InitDVD: initializes dvdplay structures
*****************************************************************************/
int E_(InitDVD) ( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
- dvd_data_t * p_dvd;
+ dvd_data_t * p_dvd = (dvd_data_t *)p_input->p_access_data;
+ demux_sys_t * p_demux;
char * psz_intf = NULL;
if( p_input->stream.i_method != INPUT_METHOD_DVD )
return -1;
}
- p_input->p_demux_data = (void*)p_input->p_access_data;
- p_dvd = (dvd_data_t *)p_input->p_demux_data;
+ p_demux = p_input->p_demux_data = malloc( sizeof(demux_sys_t ) );
+ if( p_demux == NULL )
+ {
+ return -1;
+ }
+
+ p_input->p_private = (void*)&p_demux->mpeg;
+ p_demux->p_module = module_Need( p_input, "mpeg-system", NULL );
+ if( p_demux->p_module == NULL )
+ {
+ free( p_input->p_demux_data );
+ return -1;
+ }
+
+ p_input->p_demux_data->p_dvd = p_dvd;
p_input->pf_demux = Demux;
p_input->pf_rewind = NULL;
void E_(EndDVD) ( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
- dvd_data_t * p_dvd;
+ dvd_data_t * p_dvd = p_input->p_demux_data->p_dvd;
intf_thread_t * p_intf = NULL;
p_intf = vlc_object_find( p_input, VLC_OBJECT_INTF, FIND_CHILD );
intf_Destroy( p_intf );
}
- p_dvd = (dvd_data_t *)p_input->p_demux_data;
p_dvd->p_intf = NULL;
+
+ module_Unneed( p_input, p_input->p_demux_data->p_module );
+ free( p_input->p_demux_data );
}
/*****************************************************************************
ptrdiff_t i_remains;
int i_data_nb = 0;
- p_dvd = (dvd_data_t *)p_input->p_demux_data;
+ p_dvd = p_input->p_demux_data->p_dvd;
/* Read headers to compute payload length */
do
{
- if( ( i_result = input_ReadPS( p_input, &p_data ) ) <= 0)
+ i_result = p_input->p_demux_data->mpeg.pf_read_ps( p_input, &p_data );
+
+ if( i_result <= 0 )
{
return i_result;
}
i_remains = p_input->p_last_data - p_input->p_current_data;
- input_DemuxPS( p_input, p_data );
+ p_input->p_demux_data->mpeg.pf_demux_ps( p_input, p_data );
++i_data_nb;
* es.c: functions to handle elementary streams.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: es.c,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: es.c,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
if( pi_palette )
{
ADDES( i_id, VLC_FOURCC('s','p','u',' '), SPU_ES,
- p_attr->lang_code, 16*sizeof(u32) );
+ p_attr->lang_code, sizeof(int) + 16*sizeof(u32) );
*(int*)p_es->p_demux_data = 0xBeeF;
memcpy( (void*)p_es->p_demux_data + sizeof(int),
pi_palette, 16*sizeof(u32) );
* dvdread.c : DvdRead input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: dvdread.c,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: dvdread.c,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
void E_(CloseDVD) ( vlc_object_t * );
int E_(InitDVD) ( vlc_object_t * );
+void E_(EndDVD) ( vlc_object_t * );
/*****************************************************************************
* Module descriptor
set_callbacks( E_(OpenDVD), E_(CloseDVD) );
add_submodule();
set_capability( "demux", 0 );
- set_callbacks( E_(InitDVD), NULL );
+ set_callbacks( E_(InitDVD), E_(EndDVD) );
vlc_module_end();
* It depends on: libdvdread for ifo files and block reading.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: input.c,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: input.c,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
#include <vlc/vlc.h>
#include <vlc/input.h>
+#include "../../demux/mpeg/system.h"
+
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
/* how many blocks DVDRead will read in each loop */
#define DVD_BLOCK_READ_ONCE 64
+/*****************************************************************************
+ * Private structure
+ *****************************************************************************/
+struct demux_sys_t
+{
+ module_t * p_module;
+ mpeg_demux_t mpeg;
+};
+
/*****************************************************************************
* Local prototypes
*****************************************************************************/
*/
/*****************************************************************************
- * InitDVD: initializes DVD structures
+ * InitDVD: initialize DVD structures
*****************************************************************************/
int E_(InitDVD) ( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
+ demux_sys_t * p_demux;
if( p_input->stream.i_method != INPUT_METHOD_DVD )
{
return -1;
}
+ p_demux = p_input->p_demux_data = malloc( sizeof(demux_sys_t ) );
+ if( p_demux == NULL )
+ {
+ return -1;
+ }
+
+ p_input->p_private = (void*)&p_demux->mpeg;
+ p_demux->p_module = module_Need( p_input, "mpeg-system", NULL );
+ if( p_demux->p_module == NULL )
+ {
+ free( p_input->p_demux_data );
+ return -1;
+ }
+
p_input->pf_demux = DvdReadDemux;
p_input->pf_rewind = NULL;
return 0;
}
+/*****************************************************************************
+ * EndDVD: end DVD structures
+ *****************************************************************************/
+void E_(EndDVD) ( vlc_object_t *p_this )
+{
+ input_thread_t *p_input = (input_thread_t *)p_this;
+
+ module_Unneed( p_input, p_input->p_demux_data->p_module );
+ free( p_input->p_demux_data );
+}
+
/*****************************************************************************
* DvdReadDemux
*****************************************************************************/
p_input->p_current_data += i_stuffing;
}
- input_DemuxPS( p_input, p_data );
+ p_input->p_demux_data->mpeg.pf_demux_ps( p_input, p_data );
}
* http.c: HTTP access plug-in
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
- * $Id: http.c,v 1.1 2002/08/04 17:23:41 sam Exp $
+ * $Id: http.c,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
*****************************************************************************/
static int HTTPConnect( input_thread_t * p_input, off_t i_tell )
{
- _input_socket_t * p_access_data = p_input->p_access_data;
+ _input_socket_t * p_access_data;
module_t * p_network;
char psz_buffer[256];
byte_t * psz_parser;
char * psz_return_alpha;
/* Find an appropriate network module */
+ p_access_data = (_input_socket_t *)p_input->p_access_data;
p_input->p_private = (void*) &p_access_data->socket_desc;
p_network = module_Need( p_input, "network", p_access_data->psz_network );
if( p_network == NULL )
char * psz_proxy;
int i_server_port = 0;
- p_access_data = p_input->p_access_data = malloc( sizeof(_input_socket_t) );
+ p_access_data = malloc( sizeof(_input_socket_t) );
+ p_input->p_access_data = (access_sys_t *)p_access_data;
if( p_access_data == NULL )
{
msg_Err( p_input, "out of memory" );
*****************************************************************************/
static void Seek( input_thread_t * p_input, off_t i_pos )
{
- _input_socket_t * p_access_data = p_input->p_access_data;
+ _input_socket_t *p_access_data = (_input_socket_t*)p_input->p_access_data;
close( p_access_data->_socket.i_handle );
msg_Dbg( p_input, "seeking to position %lld", i_pos );
HTTPConnect( p_input, i_pos );
#include <vlc/vlc.h>
#include <vlc/input.h>
+#include "../../demux/mpeg/system.h"
+
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
* udp.c: raw UDP access plug-in
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
- * $Id: udp.c,v 1.1 2002/08/04 17:23:41 sam Exp $
+ * $Id: udp.c,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
}
module_Unneed( p_input, p_network );
- p_access_data = p_input->p_access_data = malloc( sizeof(input_socket_t) );
+ p_access_data = malloc( sizeof(input_socket_t) );
+ p_input->p_access_data = (access_sys_t *)p_access_data;
+
if( p_access_data == NULL )
{
msg_Err( p_input, "out of memory" );
* vcd.c : VCD input module for vlc
*****************************************************************************
* Copyright (C) 2000 VideoLAN
- * $Id: vcd.c,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: vcd.c,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Author: Johan Bilien <jobi@via.ecp.fr>
*
#include <vlc/vlc.h>
#include <vlc/input.h>
+#include "../../demux/mpeg/system.h"
+
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
* downmix.h : A52 downmix types
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
- * $Id: downmix.h,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: downmix.h,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Renaud Dartus <reno@videolan.org>
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
+VLC_DECLARE_STRUCT(dm_par_t)
+VLC_DECLARE_STRUCT(downmix_t)
+
struct dm_par_t
{
float unit;
* imdct.h : A52 IMDCT types
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
- * $Id: imdct.h,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: imdct.h,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Renaud Dartus <reno@videolan.org>
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
+VLC_DECLARE_STRUCT(complex_t)
+VLC_DECLARE_STRUCT(imdct_t)
+
struct complex_t
{
float real;
/*****************************************************************************
- * video_decoder.h : video decoder thread
+ * decoder.h : video decoder thread
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
- * $Id: decoder.h,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: decoder.h,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
+VLC_DECLARE_STRUCT(vpar_thread_t)
+VLC_DECLARE_STRUCT(vdec_thread_t)
+VLC_DECLARE_STRUCT(vdec_pool_t)
+
/*****************************************************************************
* vdec_thread_t: video decoder thread descriptor
*****************************************************************************/
-typedef struct vdec_thread_s
+struct vdec_thread_t
{
VLC_COMMON_MEMBERS
/* IDCT iformations */
- void * p_idct_data;
+ void * p_idct_data;
/* Input properties */
- struct vdec_pool_s * p_pool;
-
-} vdec_thread_t;
+ vdec_pool_t * p_pool;
+};
/*****************************************************************************
* Prototypes
void vdec_DecodeMacroblock420( vdec_thread_t *, macroblock_t * );
void vdec_DecodeMacroblock422( vdec_thread_t *, macroblock_t * );
void vdec_DecodeMacroblock444( vdec_thread_t *, macroblock_t * );
-vdec_thread_t * vdec_CreateThread ( struct vdec_pool_s * );
+vdec_thread_t * vdec_CreateThread ( vdec_pool_t * );
void vdec_DestroyThread ( vdec_thread_t * );
/*****************************************************************************
- * video_parser.h : video parser thread
+ * parser.h : video parser thread
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
- * $Id: parser.h,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: parser.h,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Jean-Marc Dressler <polux@via.ecp.fr>
/*****************************************************************************
* Prototypes
*****************************************************************************/
-void vpar_InitScanTable( struct vpar_thread_s * p_vpar );
+void vpar_InitScanTable( vpar_thread_t * p_vpar );
-typedef void (*f_picture_data_t)( struct vpar_thread_s * p_vpar );
+typedef void (*f_picture_data_t)( vpar_thread_t * p_vpar );
#define PROTO_PICD( FUNCNAME ) \
-void FUNCNAME( struct vpar_thread_s * p_vpar );
+void FUNCNAME( vpar_thread_t * p_vpar );
PROTO_PICD( vpar_PictureDataGENERIC )
#if (VPAR_OPTIM_LEVEL > 0)
/*****************************************************************************
* Prototypes
*****************************************************************************/
-int vpar_NextSequenceHeader( struct vpar_thread_s * p_vpar );
-int vpar_ParseHeader( struct vpar_thread_s * p_vpar );
+int vpar_NextSequenceHeader( vpar_thread_t * p_vpar );
+int vpar_ParseHeader( vpar_thread_t * p_vpar );
/*
/*****************************************************************************
* Prototypes
*****************************************************************************/
-void vpar_SynchroInit ( struct vpar_thread_s * p_vpar );
-vlc_bool_t vpar_SynchroChoose ( struct vpar_thread_s * p_vpar,
- int i_coding_type, int i_structure );
-void vpar_SynchroTrash ( struct vpar_thread_s * p_vpar,
- int i_coding_type, int i_structure );
-void vpar_SynchroDecode ( struct vpar_thread_s * p_vpar,
- int i_coding_type, int i_structure );
-void vpar_SynchroEnd ( struct vpar_thread_s * p_vpar,
- int i_coding_type, int i_structure,
- int i_garbage );
-mtime_t vpar_SynchroDate ( struct vpar_thread_s * p_vpar );
-void vpar_SynchroNewPicture( struct vpar_thread_s * p_vpar, int i_coding_type,
- int i_repeat_field );
-
+void vpar_SynchroInit ( vpar_thread_t * p_vpar );
+vlc_bool_t vpar_SynchroChoose ( vpar_thread_t * p_vpar, int, int );
+void vpar_SynchroTrash ( vpar_thread_t * p_vpar, int, int );
+void vpar_SynchroDecode ( vpar_thread_t * p_vpar, int, int );
+void vpar_SynchroEnd ( vpar_thread_t * p_vpar, int, int, int );
+mtime_t vpar_SynchroDate ( vpar_thread_t * p_vpar );
+void vpar_SynchroNewPicture ( vpar_thread_t * p_vpar, int, int );
/*
* Video parser structures
/*****************************************************************************
* vpar_thread_t: video parser thread descriptor
*****************************************************************************/
-typedef struct vpar_thread_s
+struct vpar_thread_t
{
bit_stream_t bit_stream;
* pictures decoded */
count_t pc_malformed_pictures[4]; /* number of pictures trashed
* during parsing */
-} vpar_thread_t;
+};
/*****************************************************************************
* NextStartCode : Find the next start code
*****************************************************************************
* Quantizer scale factor (ISO/IEC 13818-2 7.4.2.2)
*****************************************************************************/
-static inline void LoadQuantizerScale( struct vpar_thread_s * p_vpar )
+static inline void LoadQuantizerScale( vpar_thread_t * p_vpar )
{
/* Quantization coefficient table */
static u8 pi_non_linear_quantizer_scale[32] =
/*****************************************************************************
- * vdec_ext-plugins.h : structures from the video decoder exported to plug-ins
+ * plugins.h : structures from the video decoder exported to plug-ins
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
- * $Id: plugins.h,v 1.1 2002/08/04 18:39:41 sam Exp $
+ * $Id: plugins.h,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
vlc_bool_t b_second_half;
} motion_inner_t;
-struct macroblock_t
+typedef struct macroblock_t
{
int i_mb_modes;
motion_inner_t p_motions[8];
int i_nb_motions;
yuv_data_t * pp_dest[3];
-};
+
+} macroblock_t;
/* Macroblock Modes */
#define MB_INTRA 1
* vpar_pool.h : video parser/video decoders communication
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
- * $Id: pool.h,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: pool.h,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This structure is used for the communication between the parser and the
* decoders.
*****************************************************************************/
-typedef struct vdec_pool_s vdec_pool_t;
-
-struct vdec_pool_s
+struct vdec_pool_t
{
/* Locks */
vlc_mutex_t lock; /* Structure data lock */
void (* pf_decode_mb) ( vdec_pool_t *, macroblock_t * );
/* Pointer to the decoding function - used for B&W switching */
- void (* pf_vdec_decode) ( struct vdec_thread_s *,
- macroblock_t * );
+ void (* pf_vdec_decode) ( vdec_thread_t *, macroblock_t * );
vlc_bool_t b_bw; /* Current value for B&W */
/* Access to the plug-ins needed by the video decoder thread */
void ( * ppppf_motion[2][2][4] ) ( yuv_data_t *, yuv_data_t *,
int, int );
- struct vpar_thread_s * p_vpar;
+ vpar_thread_t * p_vpar;
};
/*****************************************************************************
* Prototypes
*****************************************************************************/
-void vpar_InitPool ( struct vpar_thread_s * );
-void vpar_SpawnPool ( struct vpar_thread_s * );
-void vpar_EndPool ( struct vpar_thread_s * );
+void vpar_InitPool ( vpar_thread_t * );
+void vpar_SpawnPool ( vpar_thread_t * );
+void vpar_EndPool ( vpar_thread_t * );
/*****************************************************************************
* vpar_GetMacroblock: In a vdec thread, get the next available macroblock
* avi.c : AVI file Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: avi.c,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: avi.c,v 1.2 2002/08/07 00:29:36 sam Exp $
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
int i_number;
int i_type;
int i_totalentry = 0;
- demux_data_avi_file_t *p_avi_demux =
- (demux_data_avi_file_t*)p_input->p_demux_data ;
+ demux_sys_t *p_avi = p_input->p_demux_data;
if( RIFF_FindAndGotoDataChunk( p_input,
- p_avi_demux->p_riff,
+ p_avi->p_riff,
&p_idx1,
FOURCC_idx1)!=0 )
{
msg_Warn( p_input, "cannot find index" );
- RIFF_GoToChunk( p_input, p_avi_demux->p_hdrl );
+ RIFF_GoToChunk( p_input, p_avi->p_hdrl );
return;
}
- p_avi_demux->p_idx1 = p_idx1;
+ p_avi->p_idx1 = p_idx1;
msg_Dbg( p_input, "loading index" );
for(;;)
{
index.i_length = GetDWLE(p_peek+12);
AVI_ParseStreamHeader( index.i_id, &i_number, &i_type );
- if( ( i_number < p_avi_demux->i_streams )
- &&(p_avi_demux->pp_info[i_number]->i_cat ==
+ if( ( i_number < p_avi->i_streams )
+ &&(p_avi->pp_info[i_number]->i_cat ==
AVI_GetESTypeFromTwoCC( i_type )))
{
- __AVI_AddEntryIndex( p_avi_demux->pp_info[i_number],
+ __AVI_AddEntryIndex( p_avi->pp_info[i_number],
&index );
}
}
{
int i_stream;
int b_start = 1;/* if index pos is based on start of file or not (p_movi) */
- demux_data_avi_file_t *p_avi_demux =
- (demux_data_avi_file_t*)p_input->p_demux_data;
+ demux_sys_t *p_avi = p_input->p_demux_data;
/* FIXME some work to do :
* test in the file if it's true, if not do a RIFF_Find...
*/
-#define p_info p_avi_demux->pp_info[i_stream]
- for( i_stream = 0; i_stream < p_avi_demux->i_streams; i_stream++ )
+#define p_info p_avi->pp_info[i_stream]
+ for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
{
if( ( p_info->p_index )
- && ( p_info->p_index[0].i_pos < p_avi_demux->p_movi->i_pos + 8 ))
+ && ( p_info->p_index[0].i_pos < p_avi->p_movi->i_pos + 8 ))
{
b_start = 0;
break;
}
if( !b_start )
{
- for( i_stream = 0; i_stream < p_avi_demux->i_streams; i_stream++ )
+ for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
{
int i;
if( p_info->p_index )
{
for( i = 0; i < p_info->i_idxnb; i++ )
{
- p_info->p_index[i].i_pos += p_avi_demux->p_movi->i_pos + 8;
+ p_info->p_index[i].i_pos += p_avi->p_movi->i_pos + 8;
}
}
}
{
input_thread_t * p_input = (input_thread_t *)p_this;
int i;
- demux_data_avi_file_t *p_avi_demux;
- p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data ;
+ demux_sys_t *p_avi = p_input->p_demux_data ;
- if( p_avi_demux->p_riff )
- RIFF_DeleteChunk( p_input, p_avi_demux->p_riff );
- if( p_avi_demux->p_hdrl )
- RIFF_DeleteChunk( p_input, p_avi_demux->p_hdrl );
- if( p_avi_demux->p_movi )
- RIFF_DeleteChunk( p_input, p_avi_demux->p_movi );
- if( p_avi_demux->p_idx1 )
- RIFF_DeleteChunk( p_input, p_avi_demux->p_idx1 );
- if( p_avi_demux->pp_info )
- {
- for( i = 0; i < p_avi_demux->i_streams; i++ )
+ if( p_avi->p_riff )
+ RIFF_DeleteChunk( p_input, p_avi->p_riff );
+ if( p_avi->p_hdrl )
+ RIFF_DeleteChunk( p_input, p_avi->p_hdrl );
+ if( p_avi->p_movi )
+ RIFF_DeleteChunk( p_input, p_avi->p_movi );
+ if( p_avi->p_idx1 )
+ RIFF_DeleteChunk( p_input, p_avi->p_idx1 );
+ if( p_avi->pp_info )
+ {
+ for( i = 0; i < p_avi->i_streams; i++ )
{
- if( p_avi_demux->pp_info[i] )
+ if( p_avi->pp_info[i] )
{
- if( p_avi_demux->pp_info[i]->p_index )
+ if( p_avi->pp_info[i]->p_index )
{
- free( p_avi_demux->pp_info[i]->p_index );
+ free( p_avi->pp_info[i]->p_index );
AVI_PESBuffer_Flush( p_input->p_method_data,
- p_avi_demux->pp_info[i] );
+ p_avi->pp_info[i] );
}
- free( p_avi_demux->pp_info[i] );
+ free( p_avi->pp_info[i] );
}
}
- free( p_avi_demux->pp_info );
+ free( p_avi->pp_info );
}
}
riffchunk_t *p_riff,*p_hdrl,*p_movi;
riffchunk_t *p_avih;
riffchunk_t *p_strl,*p_strh,*p_strf;
- demux_data_avi_file_t *p_avi_demux;
+ demux_sys_t *p_avi;
es_descriptor_t *p_es = NULL; /* for not warning */
int i;
p_input->pf_demux = AVIDemux;
if( !( p_input->p_demux_data =
- p_avi_demux = malloc( sizeof(demux_data_avi_file_t) ) ) )
+ p_avi = malloc( sizeof(demux_sys_t) ) ) )
{
msg_Err( p_input, "out of memory" );
return( -1 );
}
- memset( p_avi_demux, 0, sizeof( demux_data_avi_file_t ) );
- p_avi_demux->i_rate = DEFAULT_RATE;
- p_avi_demux->b_seekable = ( ( p_input->stream.b_seekable )
+ memset( p_avi, 0, sizeof( demux_sys_t ) );
+ p_avi->i_rate = DEFAULT_RATE;
+ p_avi->b_seekable = ( ( p_input->stream.b_seekable )
&&( p_input->stream.i_method == INPUT_METHOD_FILE ) );
/* Initialize access plug-in structures. */
msg_Warn( p_input, "RIFF-AVI module discarded" );
return( -1 );
}
- p_avi_demux->p_riff = p_riff;
+ p_avi->p_riff = p_riff;
if ( RIFF_DescendChunk(p_input) != 0 )
{
msg_Err( p_input, "cannot find \"LIST-hdrl\"" );
return( -1 );
}
- p_avi_demux->p_hdrl = p_hdrl;
+ p_avi->p_hdrl = p_hdrl;
if( RIFF_DescendChunk(p_input) != 0 )
{
msg_Err( p_input, "cannot find \"avih\" chunk" );
return( -1 );
}
- AVI_Parse_avih( &p_avi_demux->avih, p_avih->p_data->p_payload_start );
+ AVI_Parse_avih( &p_avi->avih, p_avih->p_data->p_payload_start );
RIFF_DeleteChunk( p_input, p_avih );
- if( p_avi_demux->avih.i_streams == 0 )
+ if( p_avi->avih.i_streams == 0 )
/* no stream found, perhaps it would be cool to find it */
{
AVIEnd( p_input );
return( -1 );
}
p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
- p_input->stream.i_mux_rate = p_avi_demux->avih.i_maxbytespersec / 50;
+ p_input->stream.i_mux_rate = p_avi->avih.i_maxbytespersec / 50;
vlc_mutex_unlock( &p_input->stream.stream_lock );
/* now read info on each stream and create ES */
- p_avi_demux->i_streams = p_avi_demux->avih.i_streams;
+ p_avi->i_streams = p_avi->avih.i_streams;
- p_avi_demux->pp_info = calloc( p_avi_demux->i_streams,
+ p_avi->pp_info = calloc( p_avi->i_streams,
sizeof( AVIStreamInfo_t* ) );
- memset( p_avi_demux->pp_info,
+ memset( p_avi->pp_info,
0,
- sizeof( AVIStreamInfo_t* ) * p_avi_demux->i_streams );
+ sizeof( AVIStreamInfo_t* ) * p_avi->i_streams );
- for( i = 0 ; i < p_avi_demux->i_streams; i++ )
+ for( i = 0 ; i < p_avi->i_streams; i++ )
{
-#define p_info p_avi_demux->pp_info[i]
+#define p_info p_avi->pp_info[i]
p_info = malloc( sizeof(AVIStreamInfo_t ) );
memset( p_info, 0, sizeof( AVIStreamInfo_t ) );
AVIEnd( p_input );
return( -1 );
}
- p_avi_demux->p_movi = p_movi;
+ p_avi->p_movi = p_movi;
/* get index XXX need to have p_movi */
- if( p_avi_demux->b_seekable )
+ if( p_avi->b_seekable )
{
/* get index */
__AVI_GetIndex( p_input );
/* try to get i_idxoffset for each stream */
__AVI_UpdateIndexOffset( p_input );
/* to make sure to go the begining unless demux will see a seek */
- RIFF_GoToChunk( p_input, p_avi_demux->p_movi );
+ RIFF_GoToChunk( p_input, p_avi->p_movi );
}
else
/* print informations on streams */
msg_Dbg( p_input, "AVIH: %d stream, flags %s%s%s%s ",
- p_avi_demux->i_streams,
- p_avi_demux->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
- p_avi_demux->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
- p_avi_demux->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
- p_avi_demux->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" );
+ p_avi->i_streams,
+ p_avi->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
+ p_avi->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
+ p_avi->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
+ p_avi->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" );
- for( i = 0; i < p_avi_demux->i_streams; i++ )
+ for( i = 0; i < p_avi->i_streams; i++ )
{
-#define p_info p_avi_demux->pp_info[i]
+#define p_info p_avi->pp_info[i]
switch( p_info->p_es->i_cat )
{
case( VIDEO_ES ):
p_info->video_format.i_bitcount,
(float)p_info->header.i_rate /
(float)p_info->header.i_scale );
- if( (p_avi_demux->p_info_video == NULL) )
+ if( (p_avi->p_info_video == NULL) )
{
- p_avi_demux->p_info_video = p_info;
+ p_avi->p_info_video = p_info;
/* TODO add test to see if a decoder has been found */
vlc_mutex_lock( &p_input->stream.stream_lock );
input_SelectES( p_input, p_info->p_es );
p_info->audio_format.i_channels,
p_info->audio_format.i_samplespersec,
p_info->audio_format.i_bitspersample );
- if( (p_avi_demux->p_info_audio == NULL) )
+ if( (p_avi->p_info_audio == NULL) )
{
- p_avi_demux->p_info_audio = p_info;
+ p_avi->p_info_audio = p_info;
vlc_mutex_lock( &p_input->stream.stream_lock );
input_SelectES( p_input, p_info->p_es );
vlc_mutex_unlock( &p_input->stream.stream_lock );
/* we select the first audio and video ES */
vlc_mutex_lock( &p_input->stream.stream_lock );
- if( !p_avi_demux->p_info_video )
+ if( !p_avi->p_info_video )
{
msg_Warn( p_input, "no video stream found" );
}
- if( !p_avi_demux->p_info_audio )
+ if( !p_avi->p_info_audio )
{
msg_Warn( p_input, "no audio stream found!" );
}
AVIStreamInfo_t *p_info,
int b_load )
{
- demux_data_avi_file_t *p_avi_demux =
- (demux_data_avi_file_t*)p_input->p_demux_data;
+ demux_sys_t *p_avi = p_input->p_demux_data;
AVIStreamInfo_t *p_other;
int i_method;
off_t i_posmax;
int i;
-#define p_info_i p_avi_demux->pp_info[i]
+#define p_info_i p_avi->pp_info[i]
while( p_info->p_pes_first )
{
if( ( p_info->p_pes_first->i_posc == p_info->i_idxposc )
}
}
/* up to now we handle only one audio and video streams at the same time */
- p_other = (p_info == p_avi_demux->p_info_video ) ?
- p_avi_demux->p_info_audio : p_avi_demux->p_info_video ;
+ p_other = (p_info == p_avi->p_info_video ) ?
+ p_avi->p_info_audio : p_avi->p_info_video ;
i_method = __AVI_GetChunkMethod( p_input, p_info, p_other );
put in buffer p_other since it could be too far */
AVIStreamInfo_t *p_info_max = p_info;
- for( i = 0; i < p_avi_demux->i_streams; i++ )
+ for( i = 0; i < p_avi->i_streams; i++ )
{
if( p_info_i->i_idxnb )
{
}
else
{
- i_posmax = p_avi_demux->p_movi->i_pos + 12;
+ i_posmax = p_avi->p_movi->i_pos + 12;
}
}
else
}
AVI_ParseStreamHeader( p_ck->i_id, &i, &i_type );
/* littles checks but not too much if you want to read all file */
- if( i >= p_avi_demux->i_streams )
+ if( i >= p_avi->i_streams )
/* (AVI_GetESTypeFromTwoCC(i_type) != p_info_i->i_cat) perhaps add it*/
{
RIFF_DeleteChunk( p_input, p_ck );
- if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+ if( RIFF_NextChunk( p_input, p_avi->p_movi ) != 0 )
{
return( 0 );
}
}
else
{
- if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+ if( RIFF_NextChunk( p_input, p_avi->p_movi ) != 0 )
{
RIFF_DeleteChunk( p_input, p_ck );
{
/* skip it */
RIFF_DeleteChunk( p_input, p_ck );
- if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+ if( RIFF_NextChunk( p_input, p_avi->p_movi ) != 0 )
{
return( 0 );
}
int i;
off_t i_pos;
int b_after = 0;
- demux_data_avi_file_t *p_avi_demux =
- (demux_data_avi_file_t*)p_input->p_demux_data;
+ demux_sys_t *p_avi = p_input->p_demux_data;
- for( i = 0; i < p_avi_demux->i_streams; i++ )
+ for( i = 0; i < p_avi->i_streams; i++ )
{
- AVI_PESBuffer_Flush( p_input->p_method_data, p_avi_demux->pp_info[i] );
+ AVI_PESBuffer_Flush( p_input->p_method_data, p_avi->pp_info[i] );
}
/* Reinit clock
TODO use input_ClockInit instead but need to be exported
/* make difference between audio and video pts as little as possible */
static void AVI_SynchroReInit( input_thread_t *p_input )
{
- demux_data_avi_file_t *p_avi_demux =
- (demux_data_avi_file_t*)p_input->p_demux_data;
+ demux_sys_t *p_avi = p_input->p_demux_data;
-#define p_info_video p_avi_demux->p_info_video
-#define p_info_audio p_avi_demux->p_info_audio
+#define p_info_video p_avi->p_info_video
+#define p_info_audio p_avi->p_info_audio
if( ( !p_info_audio )||( !p_info_video ) )
{
return;
AVIStreamInfo_t *p_info_master,
AVIStreamInfo_t *p_info_slave )
{
- demux_data_avi_file_t *p_avi_demux =
- (demux_data_avi_file_t*)p_input->p_demux_data;
+ demux_sys_t *p_avi = p_input->p_demux_data;
pes_packet_t *p_pes_master;
pes_packet_t *p_pes_slave;
/* wait for the good time */
input_ClockManageRef( p_input,
p_input->stream.p_selected_program,
- p_avi_demux->i_pcr /*- DEFAULT_PTS_DELAY / 2 */);
+ p_avi->i_pcr /*- DEFAULT_PTS_DELAY / 2 */);
/* calculate pcr, time when we must read the next data */
/* 9/100 kludge ->need to convert to 1/1000000 clock unit to 1/90000 */
if( p_info_slave )
{
- p_avi_demux->i_pcr = __MIN( AVI_GetPTS( p_info_master ),
+ p_avi->i_pcr = __MIN( AVI_GetPTS( p_info_master ),
AVI_GetPTS( p_info_slave ) ) * 9/100;
}
else
{
- p_avi_demux->i_pcr = AVI_GetPTS( p_info_master ) * 9/100;
+ p_avi->i_pcr = AVI_GetPTS( p_info_master ) * 9/100;
}
/* get video and audio frames */
AVIStreamInfo_t *p_info_master,
AVIStreamInfo_t *p_info_slave )
{
- demux_data_avi_file_t *p_avi_demux =
- (demux_data_avi_file_t*)p_input->p_demux_data;
+ demux_sys_t *p_avi = p_input->p_demux_data;
int i_loop;
int i_stream;
int i_type;
input_AccessReinit( p_input );
*/
-#define p_info p_avi_demux->pp_info[i_stream]
+#define p_info p_avi->pp_info[i_stream]
/* The managment is very basic, we will read packets, caclulate pts
and send it to decoder, synchro made on video, and audio is very less
/* wait the good time */
input_ClockManageRef( p_input,
p_input->stream.p_selected_program,
- p_avi_demux->i_pcr /*- DEFAULT_PTS_DELAY / 2 */);
+ p_avi->i_pcr /*- DEFAULT_PTS_DELAY / 2 */);
/* TODO be smart, seeing if we can wait for min( audio, video )
or there is a too big deep */
if( !p_info_slave )
{
- p_avi_demux->i_pcr = AVI_GetPTS( p_info_master ) * 9/100;
+ p_avi->i_pcr = AVI_GetPTS( p_info_master ) * 9/100;
}
else
{
- p_avi_demux->i_pcr = __MIN( AVI_GetPTS( p_info_master ),
+ p_avi->i_pcr = __MIN( AVI_GetPTS( p_info_master ),
AVI_GetPTS( p_info_slave ) ) * 9/100;
- p_avi_demux->i_pcr = AVI_GetPTS( p_info_master ) * 9/100;
+ p_avi->i_pcr = AVI_GetPTS( p_info_master ) * 9/100;
}
for( i_loop = 0; i_loop < 10; i_loop++ )
}
//msg_Err( p_input,"Looking ck: %4.4s %d",&p_ck->i_id, p_ck->i_size );
- switch( __AVIDemux_ChunkAction( p_avi_demux->i_streams, p_ck ) )
+ switch( __AVIDemux_ChunkAction( p_avi->i_streams, p_ck ) )
{
case( 0 ): /* load it if possible */
b_load = 1;
break;
case( 1 ): /* skip it */
RIFF_DeleteChunk( p_input, p_ck );
- if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+ if( RIFF_NextChunk( p_input, p_avi->p_movi ) != 0 )
{
return( 0 );
}
else
{
- if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+ if( RIFF_NextChunk( p_input, p_avi->p_movi ) != 0 )
{
RIFF_DeleteChunk( p_input, p_ck );
return( 0 );
AVIStreamInfo_t *p_info_master;
AVIStreamInfo_t *p_info_slave;
- demux_data_avi_file_t *p_avi_demux =
- (demux_data_avi_file_t*)p_input->p_demux_data;
+ demux_sys_t *p_avi = p_input->p_demux_data;
/* search new video and audio stream selected
if current have been unselected*/
- if( ( !p_avi_demux->p_info_video )
- || ( !p_avi_demux->p_info_video->p_es->p_decoder_fifo ) )
+ if( ( !p_avi->p_info_video )
+ || ( !p_avi->p_info_video->p_es->p_decoder_fifo ) )
{
- p_avi_demux->p_info_video = NULL;
- for( i = 0; i < p_avi_demux->i_streams; i++ )
+ p_avi->p_info_video = NULL;
+ for( i = 0; i < p_avi->i_streams; i++ )
{
- if( ( p_avi_demux->pp_info[i]->i_cat == VIDEO_ES )
- &&( p_avi_demux->pp_info[i]->p_es->p_decoder_fifo ) )
+ if( ( p_avi->pp_info[i]->i_cat == VIDEO_ES )
+ &&( p_avi->pp_info[i]->p_es->p_decoder_fifo ) )
{
- p_avi_demux->p_info_video = p_avi_demux->pp_info[i];
- p_avi_demux->p_info_video->b_selected = 1;
+ p_avi->p_info_video = p_avi->pp_info[i];
+ p_avi->p_info_video->b_selected = 1;
break;
}
}
}
- if( ( !p_avi_demux->p_info_audio )
- ||( !p_avi_demux->p_info_audio->p_es->p_decoder_fifo ) )
+ if( ( !p_avi->p_info_audio )
+ ||( !p_avi->p_info_audio->p_es->p_decoder_fifo ) )
{
- p_avi_demux->p_info_audio = NULL;
- for( i = 0; i < p_avi_demux->i_streams; i++ )
+ p_avi->p_info_audio = NULL;
+ for( i = 0; i < p_avi->i_streams; i++ )
{
- if( ( p_avi_demux->pp_info[i]->i_cat == AUDIO_ES )
- &&( p_avi_demux->pp_info[i]->p_es->p_decoder_fifo ) )
+ if( ( p_avi->pp_info[i]->i_cat == AUDIO_ES )
+ &&( p_avi->pp_info[i]->p_es->p_decoder_fifo ) )
{
- p_avi_demux->p_info_audio = p_avi_demux->pp_info[i];
- p_avi_demux->p_info_audio->b_selected = 1;
+ p_avi->p_info_audio = p_avi->pp_info[i];
+ p_avi->p_info_audio->b_selected = 1;
break;
}
}
}
/* by default video is master for resync audio (after a seek .. ) */
- if( p_avi_demux->p_info_video )
+ if( p_avi->p_info_video )
{
- p_info_master = p_avi_demux->p_info_video;
- p_info_slave = p_avi_demux->p_info_audio;
+ p_info_master = p_avi->p_info_video;
+ p_info_slave = p_avi->p_info_audio;
}
else
{
- p_info_master = p_avi_demux->p_info_audio;
+ p_info_master = p_avi->p_info_audio;
p_info_slave = NULL;
}
/* manage rate, if not default: skeep audio */
vlc_mutex_lock( &p_input->stream.stream_lock );
- if( p_input->stream.control.i_rate != p_avi_demux->i_rate )
+ if( p_input->stream.control.i_rate != p_avi->i_rate )
{
- if( p_avi_demux->p_info_audio)
+ if( p_avi->p_info_audio)
{
- p_avi_demux->p_info_audio->b_selected = 1;
+ p_avi->p_info_audio->b_selected = 1;
}
- p_avi_demux->i_rate = p_input->stream.control.i_rate;
+ p_avi->i_rate = p_input->stream.control.i_rate;
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
- p_avi_demux->i_rate = DEFAULT_RATE;
- if( p_avi_demux->i_rate != DEFAULT_RATE )
+ p_avi->i_rate = DEFAULT_RATE;
+ if( p_avi->i_rate != DEFAULT_RATE )
{
p_info_slave = NULL;
}
- if( p_avi_demux->b_seekable )
+ if( p_avi->b_seekable )
{
return( AVIDemux_Seekable( p_input,
p_info_master,
* avi.h : AVI file Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: avi.h,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: avi.h,v 1.2 2002/08/07 00:29:36 sam Exp $
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
int i_pes_totalsize;
} AVIStreamInfo_t;
-typedef struct demux_data_avi_file_s
+struct demux_sys_t
{
mtime_t i_pcr;
int i_rate;
/* current audio and video es */
AVIStreamInfo_t *p_info_video;
AVIStreamInfo_t *p_info_audio;
-
-} demux_data_avi_file_t;
+};
* mp4.c : MP4 file input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: mp4.c,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: mp4.c,v 1.2 2002/08/07 00:29:36 sam Exp $
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
u8 *p_peek;
u32 i_type;
- demux_data_mp4_t *p_demux;
+ demux_sys_t *p_demux;
MP4_Box_t *p_moov;
MP4_Box_t *p_ftyp;
/* create our structure that will contains all data */
if( !( p_input->p_demux_data =
- p_demux = malloc( sizeof( demux_data_mp4_t ) ) ) )
+ p_demux = malloc( sizeof( demux_sys_t ) ) ) )
{
msg_Err( p_input, "out of memory" );
return( -1 );
}
- memset( p_demux, 0, sizeof( demux_data_mp4_t ) );
+ memset( p_demux, 0, sizeof( demux_sys_t ) );
p_input->p_demux_data = p_demux;
*****************************************************************************/
static int MP4Demux( input_thread_t *p_input )
{
- demux_data_mp4_t *p_demux = p_input->p_demux_data;
+ demux_sys_t *p_demux = p_input->p_demux_data;
int i_track;
/* first wait for the good time to read a packet */
if( p ) { free( p ); }
int i_track;
input_thread_t * p_input = (input_thread_t *)p_this;
- demux_data_mp4_t *p_demux = p_input->p_demux_data;
+ demux_sys_t *p_demux = p_input->p_demux_data;
msg_Dbg( p_input, "Freeing all memory" );
MP4_FreeBox( p_input, &p_demux->box_root );
break;
}
- p_demux_track->p_es->p_demux_data = p_init;
+ p_demux_track->p_es->p_demux_data = (es_sys_t *)p_init;
vlc_mutex_lock( &p_input->stream.stream_lock );
input_SelectES( p_input, p_demux_track->p_es );
vlc_mutex_unlock( &p_input->stream.stream_lock );
* mp4.h : MP4 file input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: mp4.h,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: mp4.h,v 1.2 2002/08/07 00:29:36 sam Exp $
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
/*****************************************************************************
*
*****************************************************************************/
-typedef struct demux_data_mp4_s
+struct demux_sys_t
{
MP4_Box_t box_root; /* container for the hole file */
track_data_mp4_t *track; /* array of track */
-} demux_data_mp4_t;
+};
static inline u64 MP4_GetTrackPos( track_data_mp4_t *p_track )
{
(mtime_t)p_track->i_timescale ) );
}
-static inline mtime_t MP4_GetMoviePTS(demux_data_mp4_t *p_demux )
+static inline mtime_t MP4_GetMoviePTS(demux_sys_t *p_demux )
{
return( (mtime_t)(
(mtime_t)1000000 *
+mpeg_system_SOURCES = system.c
es_SOURCES = es.c
ps_SOURCES = ps.c
ts_SOURCES = ts.c
* mpeg_audio.c : mpeg_audio Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: audio.c,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: audio.c,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
int i_avgbitrate; /* calculated, XXX: bits/sec not Kb */
} mpegaudio_xing_header_t;
-typedef struct demux_data_mpegaudio_s
+struct demux_sys_t
{
mtime_t i_pts;
es_descriptor_t *p_es;
mpegaudio_format_t mpeg;
mpegaudio_xing_header_t xingheader;
-
-} demux_data_mpegaudio_t;
+};
static int mpegaudio_bitrate[2][3][16] =
static int Activate( vlc_object_t * p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
- demux_data_mpegaudio_t * p_mpegaudio;
+ demux_sys_t * p_mpegaudio;
mpegaudio_format_t mpeg;
es_descriptor_t * p_es;
int i_pos;
vlc_mutex_unlock( &p_input->stream.stream_lock );
/* create p_mpegaudio and init it */
- p_input->p_demux_data =
- p_mpegaudio = malloc( sizeof( demux_data_mpegaudio_t ));
+ p_mpegaudio = p_input->p_demux_data = malloc( sizeof(demux_sys_t) );
if( !p_mpegaudio )
{
int i_toread;
pes_packet_t *p_pes;
mpegaudio_format_t mpeg;
- demux_data_mpegaudio_t *p_mpegaudio =
- (demux_data_mpegaudio_t*) p_input->p_demux_data;
+ demux_sys_t *p_mpegaudio = p_input->p_demux_data;
+
/* look for a frame */
if( !MPEGAudio_FindFrame( p_input, &i_pos, &mpeg, 4096 ) )
{
/*****************************************************************************
- * mpeg_ps.c : Program Stream input module for vlc
+ * ps.c : Program Stream input module for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
- * $Id: ps.c,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: ps.c,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
#include <sys/types.h>
+#include "system.h"
+
/*****************************************************************************
* Constants
*****************************************************************************/
#define PS_READ_ONCE 50
+/*****************************************************************************
+ * Private structure
+ *****************************************************************************/
+struct demux_sys_t
+{
+ module_t * p_module;
+ mpeg_demux_t mpeg;
+};
+
/*****************************************************************************
* Local prototypes
*****************************************************************************/
-static int Activate ( vlc_object_t * );
-static int Demux ( input_thread_t * );
+static int Activate ( vlc_object_t * );
+static void Deactivate ( vlc_object_t * );
+static int Demux ( input_thread_t * );
/*****************************************************************************
* Module descriptor
vlc_module_begin();
set_description( _("ISO 13818-1 MPEG Program Stream input") );
set_capability( "demux", 100 );
- set_callbacks( Activate, NULL );
+ set_callbacks( Activate, Deactivate );
add_shortcut( "ps" );
vlc_module_end();
/*****************************************************************************
- * Activate: initializes PS structures
+ * Activate: initialize PS structures
*****************************************************************************/
static int Activate( vlc_object_t * p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
+ demux_sys_t * p_demux;
byte_t * p_peek;
/* Set the demux function */
{
/* Stream shorter than 4 bytes... */
msg_Err( p_input, "cannot peek()" );
- return( -1 );
+ return -1;
}
if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
}
}
+ p_demux = p_input->p_demux_data = malloc( sizeof(demux_sys_t ) );
+ if( p_demux == NULL )
+ {
+ return -1;
+ }
+
+ p_input->p_private = (void*)&p_demux->mpeg;
+ p_demux->p_module = module_Need( p_input, "mpeg-system", NULL );
+ if( p_demux->p_module == NULL )
+ {
+ free( p_input->p_demux_data );
+ return -1;
+ }
+
if( input_InitStream( p_input, sizeof( stream_ps_data_t ) ) == -1 )
{
- return( -1 );
+ module_Unneed( p_input, p_demux->p_module );
+ free( p_input->p_demux_data );
+ return -1;
}
input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
ssize_t i_result;
data_packet_t * p_data;
- i_result = input_ReadPS( p_input, &p_data );
+ i_result = p_demux->mpeg.pf_read_ps( p_input, &p_data );
if( i_result == 0 )
{
break;
}
- input_ParsePS( p_input, p_data );
+ p_demux->mpeg.pf_parse_ps( p_input, p_data );
input_DeletePacket( p_input->p_method_data, p_data );
/* File too big. */
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
- return( 0 );
+ return 0;
+}
+
+/*****************************************************************************
+ * Deactivate: deinitialize PS structures
+ *****************************************************************************/
+static void Deactivate( vlc_object_t * p_this )
+{
+ input_thread_t * p_input = (input_thread_t *)p_this;
+
+ module_Unneed( p_input, p_input->p_demux_data->p_module );
+ free( p_input->p_demux_data );
}
/*****************************************************************************
*****************************************************************************/
static int Demux( input_thread_t * p_input )
{
- int i;
+ int i;
for( i = 0; i < PS_READ_ONCE; i++ )
{
data_packet_t * p_data;
ssize_t i_result;
- i_result = input_ReadPS( p_input, &p_data );
+ i_result = p_input->p_demux_data->mpeg.pf_read_ps( p_input, &p_data );
if( i_result <= 0 )
{
- return( i_result );
+ return i_result;
}
- input_DemuxPS( p_input, p_data );
+ p_input->p_demux_data->mpeg.pf_demux_ps( p_input, p_data );
}
- return( i );
+ return i;
}
--- /dev/null
+/*****************************************************************************
+ * system.c: helper module for TS, PS and PES management
+ *****************************************************************************
+ * Copyright (C) 1998-2002 VideoLAN
+ * $Id: system.c,v 1.1 2002/08/07 00:29:36 sam Exp $
+ *
+ * Authors: Christophe Massiot <massiot@via.ecp.fr>
+ * Michel Lespinasse <walken@via.ecp.fr>
+ * Benoît Steiner <benny@via.ecp.fr>
+ * Samuel Hocevar <sam@zoy.org>
+ * Henri Fallon <henri@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>
+#include <string.h> /* memcpy(), memset() */
+#include <sys/types.h> /* off_t */
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+
+#include "system.h"
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int Activate ( vlc_object_t * );
+
+static ssize_t ReadPS ( input_thread_t *, data_packet_t ** );
+static es_descriptor_t * ParsePS ( input_thread_t *, data_packet_t * );
+static void DemuxPS ( input_thread_t *, data_packet_t * );
+
+static ssize_t ReadTS ( input_thread_t *, data_packet_t ** );
+static void DemuxTS ( input_thread_t *, data_packet_t *,
+ psi_callback_t );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+ set_description( _("generic ISO 13818-1 MPEG demultiplexing") );
+ set_capability( "mpeg-system", 100 );
+ set_callbacks( Activate, NULL );
+vlc_module_end();
+
+/*****************************************************************************
+ * Activate: initializes helper functions
+ *****************************************************************************/
+static int Activate ( vlc_object_t *p_this )
+{
+ static mpeg_demux_t mpeg_demux =
+ { NULL, ReadPS, ParsePS, DemuxPS, ReadTS, DemuxTS };
+
+ memcpy( p_this->p_private, &mpeg_demux, sizeof( mpeg_demux ) );
+
+ return VLC_SUCCESS;
+}
+
+/*
+ * PES Packet management
+ */
+
+/*****************************************************************************
+ * MoveChunk
+ *****************************************************************************
+ * Small utility function used to parse discontinuous headers safely. Copies
+ * i_buf_len bytes of data to a buffer and returns the size copied.
+ * It also solves some alignment problems on non-IA-32, non-PPC processors.
+ * This is a variation on the theme of input_ext-dec.h:GetChunk().
+ *****************************************************************************/
+static inline size_t MoveChunk( byte_t * p_dest, data_packet_t ** pp_data_src,
+ byte_t ** pp_src, size_t i_buf_len )
+{
+ ptrdiff_t i_available;
+
+ if( (i_available = (*pp_data_src)->p_payload_end - *pp_src)
+ >= i_buf_len )
+ {
+ if( p_dest != NULL )
+ memcpy( p_dest, *pp_src, i_buf_len );
+ *pp_src += i_buf_len;
+ return( i_buf_len );
+ }
+ else
+ {
+ size_t i_init_len = i_buf_len;
+
+ do
+ {
+ if( p_dest != NULL )
+ memcpy( p_dest, *pp_src, i_available );
+ *pp_data_src = (*pp_data_src)->p_next;
+ i_buf_len -= i_available;
+ p_dest += i_available;
+ if( *pp_data_src == NULL )
+ {
+ *pp_src = NULL;
+ return( i_init_len - i_buf_len );
+ }
+ *pp_src = (*pp_data_src)->p_payload_start;
+ }
+ while( (i_available = (*pp_data_src)->p_payload_end - *pp_src)
+ <= i_buf_len );
+
+ if( i_buf_len )
+ {
+ if( p_dest != NULL )
+ memcpy( p_dest, *pp_src, i_buf_len );
+ *pp_src += i_buf_len;
+ }
+ return( i_init_len );
+ }
+}
+
+/*****************************************************************************
+ * ParsePES
+ *****************************************************************************
+ * Parse a finished PES packet and analyze its header.
+ *****************************************************************************/
+#define PES_HEADER_SIZE 7
+static void ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
+{
+ data_packet_t * p_data;
+ byte_t * p_byte;
+ byte_t p_header[PES_HEADER_SIZE];
+ int i_done;
+
+#define p_pes (p_es->p_pes)
+
+ /* Parse the header. The header has a variable length, but in order
+ * to improve the algorithm, we will read the 14 bytes we may be
+ * interested in */
+ p_data = p_pes->p_first;
+ p_byte = p_data->p_payload_start;
+ i_done = 0;
+
+ if( MoveChunk( p_header, &p_data, &p_byte, PES_HEADER_SIZE )
+ != PES_HEADER_SIZE )
+ {
+ msg_Warn( p_input, "PES packet too short to have a header" );
+ input_DeletePES( p_input->p_method_data, p_pes );
+ p_pes = NULL;
+ return;
+ }
+
+ /* Get the PES size if defined */
+ p_es->i_pes_real_size = U16_AT(p_header + 4);
+ if( p_es->i_pes_real_size )
+ {
+ p_es->i_pes_real_size += 6;
+ }
+
+ /* First read the 6 header bytes common to all PES packets:
+ * use them to test the PES validity */
+ if( (p_header[0] || p_header[1] || (p_header[2] != 1)) )
+ {
+ /* packet_start_code_prefix != 0x000001 */
+ msg_Err( p_input, "data loss, PES packet does not start with 000001" );
+ input_DeletePES( p_input->p_method_data, p_pes );
+ p_pes = NULL;
+ }
+ else
+ {
+ int i_pes_header_size, i_payload_size;
+
+ if ( p_es->i_pes_real_size &&
+ (p_es->i_pes_real_size != p_pes->i_pes_size) )
+ {
+ /* PES_packet_length is set and != total received payload */
+ /* Warn the decoder that the data may be corrupt. */
+ msg_Warn( p_input, "packet corrupted, PES sizes do not match" );
+ }
+
+ switch( p_es->i_stream_id )
+ {
+ case 0xBC: /* Program stream map */
+ case 0xBE: /* Padding */
+ case 0xBF: /* Private stream 2 */
+ case 0xB0: /* ECM */
+ case 0xB1: /* EMM */
+ case 0xFF: /* Program stream directory */
+ case 0xF2: /* DSMCC stream */
+ case 0xF8: /* ITU-T H.222.1 type E stream */
+ /* The payload begins immediately after the 6 bytes header, so
+ * we have finished with the parsing */
+ i_pes_header_size = 6;
+ break;
+
+ default:
+ if( (p_header[6] & 0xC0) == 0x80 )
+ {
+ /* MPEG-2 : the PES header contains at least 3 more bytes. */
+ size_t i_max_len;
+ vlc_bool_t b_has_pts, b_has_dts;
+ byte_t p_full_header[12];
+
+ p_pes->b_data_alignment = p_header[6] & 0x04;
+
+ i_max_len = MoveChunk( p_full_header, &p_data, &p_byte, 12 );
+ if( i_max_len < 2 )
+ {
+ msg_Warn( p_input,
+ "PES packet too short to have a MPEG-2 header" );
+ input_DeletePES( p_input->p_method_data,
+ p_pes );
+ p_pes = NULL;
+ return;
+ }
+
+ b_has_pts = p_full_header[0] & 0x80;
+ b_has_dts = p_full_header[0] & 0x40;
+ i_pes_header_size = p_full_header[1] + 9;
+
+ /* Now parse the optional header extensions */
+ if( b_has_pts )
+ {
+ if( i_max_len < 7 )
+ {
+ msg_Warn( p_input,
+ "PES packet too short to have a MPEG-2 header" );
+ input_DeletePES( p_input->p_method_data,
+ p_pes );
+ p_pes = NULL;
+ return;
+ }
+ p_pes->i_pts = input_ClockGetTS( p_input, p_es->p_pgrm,
+ ( ((mtime_t)(p_full_header[2] & 0x0E) << 29) |
+ ((mtime_t)(p_full_header[3]) << 22) |
+ ((mtime_t)(p_full_header[4] & 0xFE) << 14) |
+ ((mtime_t)p_full_header[5] << 7) |
+ ((mtime_t)p_full_header[6] >> 1) ) );
+
+ if( b_has_dts )
+ {
+ if( i_max_len < 12 )
+ {
+ msg_Warn( p_input,
+ "PES packet too short to have a MPEG-2 header" );
+ input_DeletePES( p_input->p_method_data,
+ p_pes );
+ p_pes = NULL;
+ return;
+ }
+ p_pes->i_dts = input_ClockGetTS( p_input, p_es->p_pgrm,
+ ( ((mtime_t)(p_full_header[7] & 0x0E) << 29) |
+ (((mtime_t)U16_AT(p_full_header + 8) << 14)
+ - (1 << 14)) |
+ ((mtime_t)U16_AT(p_full_header + 10) >> 1) ) );
+ }
+ }
+ }
+ else
+ {
+ /* Probably MPEG-1 */
+ vlc_bool_t b_has_pts, b_has_dts;
+
+ i_pes_header_size = 6;
+ p_data = p_pes->p_first;
+ p_byte = p_data->p_payload_start;
+ /* Cannot fail because the previous one succeeded. */
+ MoveChunk( NULL, &p_data, &p_byte, 6 );
+
+ while( *p_byte == 0xFF && i_pes_header_size < 23 )
+ {
+ i_pes_header_size++;
+ if( MoveChunk( NULL, &p_data, &p_byte, 1 ) != 1 )
+ {
+ msg_Warn( p_input,
+ "PES packet too short to have a MPEG-1 header" );
+ input_DeletePES( p_input->p_method_data, p_pes );
+ p_pes = NULL;
+ return;
+ }
+ }
+ if( i_pes_header_size == 23 )
+ {
+ msg_Err( p_input, "too much MPEG-1 stuffing" );
+ input_DeletePES( p_input->p_method_data, p_pes );
+ p_pes = NULL;
+ return;
+ }
+
+ if( (*p_byte & 0xC0) == 0x40 )
+ {
+ /* Don't ask why... --Meuuh */
+ /* Erm... why ? --Sam */
+ /* Well... According to the recommendation, it is for
+ * STD_buffer_scale and STD_buffer_size. --Meuuh */
+ i_pes_header_size += 2;
+ if( MoveChunk( NULL, &p_data, &p_byte, 2 ) != 2 )
+ {
+ msg_Warn( p_input,
+ "PES packet too short to have a MPEG-1 header" );
+ input_DeletePES( p_input->p_method_data, p_pes );
+ p_pes = NULL;
+ return;
+ }
+ }
+
+ i_pes_header_size++;
+
+ b_has_pts = *p_byte & 0x20;
+ b_has_dts = *p_byte & 0x10;
+
+ if( b_has_pts )
+ {
+ byte_t p_ts[5];
+
+ i_pes_header_size += 4;
+ if( MoveChunk( p_ts, &p_data, &p_byte, 5 ) != 5 )
+ {
+ msg_Warn( p_input,
+ "PES packet too short to have a MPEG-1 header" );
+ input_DeletePES( p_input->p_method_data, p_pes );
+ p_pes = NULL;
+ return;
+ }
+
+ p_pes->i_pts = input_ClockGetTS( p_input, p_es->p_pgrm,
+ ( ((mtime_t)(p_ts[0] & 0x0E) << 29) |
+ (((mtime_t)U32_AT(p_ts) & 0xFFFE00) << 6) |
+ ((mtime_t)p_ts[3] << 7) |
+ ((mtime_t)p_ts[4] >> 1) ) );
+
+ if( b_has_dts )
+ {
+ i_pes_header_size += 5;
+ if( MoveChunk( p_ts, &p_data, &p_byte, 5 ) != 5 )
+ {
+ msg_Warn( p_input,
+ "PES packet too short to have a MPEG-1 header" );
+ input_DeletePES( p_input->p_method_data, p_pes );
+ p_pes = NULL;
+ return;
+ }
+
+ p_pes->i_dts = input_ClockGetTS( p_input,
+ p_es->p_pgrm,
+ ( ((mtime_t)(p_ts[0] & 0x0E) << 29) |
+ (((mtime_t)U32_AT(p_ts) & 0xFFFE00) << 6) |
+ ((mtime_t)p_ts[3] << 7) |
+ ((mtime_t)p_ts[4] >> 1) ) );
+ }
+ }
+ }
+
+ break;
+ }
+
+ if( p_es->i_stream_id == 0xbd )
+ {
+ /* With private stream 1, the first byte of the payload
+ * is a stream_private_id, so skip it. */
+ i_pes_header_size++;
+ }
+
+ if( p_es->i_fourcc == VLC_FOURCC('a','5','2',' ') )
+ {
+ /* With A52 audio, we need to skip first 3 bytes */
+ i_pes_header_size += 3;
+ }
+
+ /* Now we've parsed the header, we just have to indicate in some
+ * specific data packets where the PES payload begins (renumber
+ * p_payload_start), so that the decoders can find the beginning
+ * of their data right out of the box. */
+ p_data = p_pes->p_first;
+ i_payload_size = p_data->p_payload_end
+ - p_data->p_payload_start;
+ while( i_pes_header_size > i_payload_size )
+ {
+ /* These packets are entirely filled by the PES header. */
+ i_pes_header_size -= i_payload_size;
+ p_data->p_payload_start = p_data->p_payload_end;
+ /* Go to the next data packet. */
+ if( (p_data = p_data->p_next) == NULL )
+ {
+ msg_Err( p_input, "PES header bigger than payload" );
+ input_DeletePES( p_input->p_method_data, p_pes );
+ p_pes = NULL;
+ return;
+ }
+ i_payload_size = p_data->p_payload_end
+ - p_data->p_payload_start;
+ }
+ /* This last packet is partly header, partly payload. */
+ if( i_payload_size < i_pes_header_size )
+ {
+ msg_Err( p_input, "PES header bigger than payload" );
+ input_DeletePES( p_input->p_method_data, p_pes );
+ p_pes = NULL;
+ return;
+ }
+ p_data->p_payload_start += i_pes_header_size;
+
+
+ /* Now we can eventually put the PES packet in the decoder's
+ * PES fifo */
+ if( p_es->p_decoder_fifo != NULL )
+ {
+ input_DecodePES( p_es->p_decoder_fifo, p_pes );
+ }
+ else
+ {
+ msg_Err( p_input, "no fifo to receive PES %p "
+ "(who wrote this damn code ?)", p_pes );
+ input_DeletePES( p_input->p_method_data, p_pes );
+ }
+ p_pes = NULL;
+ }
+#undef p_pes
+
+}
+
+/*****************************************************************************
+ * GatherPES:
+ *****************************************************************************
+ * Gather a PES packet.
+ *****************************************************************************/
+static void GatherPES( input_thread_t * p_input, data_packet_t * p_data,
+ es_descriptor_t * p_es,
+ vlc_bool_t b_unit_start, vlc_bool_t b_packet_lost )
+{
+#define p_pes (p_es->p_pes)
+
+ /* If we lost data, insert a NULL data packet (philosophy : 0 is quite
+ * often an escape sequence in decoders, so that should make them wait
+ * for the next start code). */
+ if( b_packet_lost )
+ {
+ input_NullPacket( p_input, p_es );
+ }
+
+ if( b_unit_start && p_pes != NULL )
+ {
+ /* If the data packet contains the begining of a new PES packet, and
+ * if we were reassembling a PES packet, then the PES should be
+ * complete now, so parse its header and give it to the decoders. */
+ ParsePES( p_input, p_es );
+ }
+
+ if( !b_unit_start && p_pes == NULL )
+ {
+ /* Random access... */
+ input_DeletePacket( p_input->p_method_data, p_data );
+ }
+ else
+ {
+ if( b_unit_start )
+ {
+ /* If we are at the beginning of a new PES packet, we must fetch
+ * a new PES buffer to begin with the reassembly of this PES
+ * packet. This is also here that we can synchronize with the
+ * stream if we lost packets or if the decoder has just
+ * started. */
+ if( (p_pes = input_NewPES( p_input->p_method_data ) ) == NULL )
+ {
+ msg_Err( p_input, "out of memory" );
+ p_input->b_error = 1;
+ return;
+ }
+ p_pes->i_rate = p_input->stream.control.i_rate;
+ p_pes->p_first = p_data;
+
+ /* If the PES header fits in the first data packet, we can
+ * already set p_gather->i_pes_real_size. */
+ if( p_data->p_payload_end - p_data->p_payload_start
+ >= PES_HEADER_SIZE )
+ {
+ p_es->i_pes_real_size = ((u16)p_data->p_payload_start[4] << 8)
+ + p_data->p_payload_start[5] + 6;
+ }
+ else
+ {
+ p_es->i_pes_real_size = 0;
+ }
+ }
+ else
+ {
+ /* Update the relations between the data packets */
+ p_pes->p_last->p_next = p_data;
+ }
+
+ p_pes->p_last = p_data;
+ p_pes->i_nb_data++;
+
+ /* Size of the payload carried in the data packet */
+ p_pes->i_pes_size += (p_data->p_payload_end
+ - p_data->p_payload_start);
+
+ /* We can check if the packet is finished */
+ if( p_pes->i_pes_size == p_es->i_pes_real_size )
+ {
+ /* The packet is finished, parse it */
+ ParsePES( p_input, p_es );
+ }
+ }
+#undef p_pes
+}
+
+
+/*
+ * PS Demultiplexing
+ */
+
+/*****************************************************************************
+ * GetID: Get the ID of a stream
+ *****************************************************************************/
+static u16 GetID( data_packet_t * p_data )
+{
+ u16 i_id;
+
+ i_id = p_data->p_demux_start[3]; /* stream_id */
+ if( i_id == 0xBD )
+ {
+ /* FIXME : this is not valid if the header is split in multiple
+ * packets */
+ /* stream_private_id */
+ i_id |= p_data->p_demux_start[ 9 + p_data->p_demux_start[8] ] << 8;
+ }
+ return( i_id );
+}
+
+/*****************************************************************************
+ * DecodePSM: Decode the Program Stream Map information
+ *****************************************************************************
+ * FIXME : loads are not aligned in this function
+ *****************************************************************************/
+static void DecodePSM( input_thread_t * p_input, data_packet_t * p_data )
+{
+ stream_ps_data_t * p_demux =
+ (stream_ps_data_t *)p_input->stream.p_demux_data;
+ byte_t * p_byte;
+ byte_t * p_end;
+ int i;
+ int i_new_es_number = 0;
+
+ if( p_data->p_demux_start + 10 > p_data->p_payload_end )
+ {
+ msg_Err( p_input, "PSM too short, packet corrupt" );
+ return;
+ }
+
+ if( p_demux->b_has_PSM
+ && p_demux->i_PSM_version == (p_data->p_demux_start[6] & 0x1F) )
+ {
+ /* Already got that one. */
+ return;
+ }
+
+ p_demux->b_has_PSM = 1;
+ p_demux->i_PSM_version = p_data->p_demux_start[6] & 0x1F;
+
+ /* Go to elementary_stream_map_length, jumping over
+ * program_stream_info. */
+ p_byte = p_data->p_demux_start + 10
+ + U16_AT(&p_data->p_demux_start[8]);
+ if( p_byte > p_data->p_payload_end )
+ {
+ msg_Err( p_input, "PSM too short, packet corrupt" );
+ return;
+ }
+ /* This is the full size of the elementary_stream_map.
+ * 2 == elementary_stream_map_length
+ * Please note that CRC_32 is not included in the length. */
+ p_end = p_byte + 2 + U16_AT(p_byte);
+ p_byte += 2;
+ if( p_end > p_data->p_payload_end )
+ {
+ msg_Err( p_input, "PSM too short, packet corrupt" );
+ return;
+ }
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ /* 4 == minimum useful size of a section */
+ while( p_byte + 4 <= p_end )
+ {
+ es_descriptor_t * p_es = NULL;
+ u8 i_stream_id = p_byte[1];
+ /* FIXME: there will be a problem with private streams... (same
+ * stream_id) */
+
+ /* Look for the ES in the ES table */
+ for( i = i_new_es_number;
+ i < p_input->stream.pp_programs[0]->i_es_number;
+ i++ )
+ {
+ if( p_input->stream.pp_programs[0]->pp_es[i]->i_stream_id
+ == i_stream_id )
+ {
+ p_es = p_input->stream.pp_programs[0]->pp_es[i];
+ /* FIXME: do something below */
+#if 0
+ if( p_es->i_type != p_byte[0] )
+ {
+ input_DelES( p_input, p_es );
+ p_es = NULL;
+ }
+ else
+#endif
+ {
+ /* Move the ES to the beginning. */
+ p_input->stream.pp_programs[0]->pp_es[i]
+ = p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ];
+ p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ]
+ = p_es;
+ i_new_es_number++;
+ }
+ break;
+ }
+ }
+
+ /* The goal is to have all the ES we have just read in the
+ * beginning of the pp_es table, and all the others at the end,
+ * so that we can close them more easily at the end. */
+ if( p_es == NULL )
+ {
+ p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
+ i_stream_id, 0 );
+ switch( p_byte[0] )
+ {
+ case MPEG1_VIDEO_ES:
+ case MPEG2_VIDEO_ES:
+ p_es->i_fourcc = VLC_FOURCC('m','p','g','v');
+ p_es->i_cat = VIDEO_ES;
+ break;
+ case DVD_SPU_ES:
+ p_es->i_fourcc = VLC_FOURCC('s','p','u',' ');
+ p_es->i_cat = SPU_ES;
+ break;
+ case MPEG1_AUDIO_ES:
+ case MPEG2_AUDIO_ES:
+ p_es->i_fourcc = VLC_FOURCC('m','p','g','a');
+ p_es->i_cat = AUDIO_ES;
+ break;
+ case A52_AUDIO_ES:
+ p_es->i_fourcc = VLC_FOURCC('a','5','2',' ');
+ p_es->i_cat = AUDIO_ES;
+ break;
+ case LPCM_AUDIO_ES:
+ p_es->i_fourcc = VLC_FOURCC('l','p','c','m');
+ p_es->i_cat = AUDIO_ES;
+ break;
+ default:
+ p_es->i_fourcc = 0;
+ break;
+ }
+
+ /* input_AddES has inserted the new element at the end. */
+ p_input->stream.pp_programs[0]->pp_es[
+ p_input->stream.pp_programs[0]->i_es_number ]
+ = p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ];
+ p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ] = p_es;
+ i_new_es_number++;
+ }
+ p_byte += 4 + U16_AT(&p_byte[2]);
+ }
+
+ /* Un-select the streams that are no longer parts of the program. */
+ while( i_new_es_number < p_input->stream.pp_programs[0]->i_es_number )
+ {
+ /* We remove pp_es[i_new_es_member] and not pp_es[i] because the
+ * list will be emptied starting from the end */
+ input_DelES( p_input,
+ p_input->stream.pp_programs[0]->pp_es[i_new_es_number] );
+ }
+
+ msg_Dbg( p_input, "the stream map after the PSM is now:" );
+ input_DumpStream( p_input );
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+}
+
+/*****************************************************************************
+ * ReadPS: store a PS packet into a data_buffer_t
+ *****************************************************************************/
+#define PEEK( SIZE ) \
+ i_error = input_Peek( p_input, &p_peek, SIZE ); \
+ if( i_error == -1 ) \
+ { \
+ return( -1 ); \
+ } \
+ else if( i_error < SIZE ) \
+ { \
+ /* EOF */ \
+ return( 0 ); \
+ }
+
+static ssize_t ReadPS( input_thread_t * p_input, data_packet_t ** pp_data )
+{
+ byte_t * p_peek;
+ size_t i_packet_size;
+ ssize_t i_error, i_read;
+
+ /* Read what we believe to be a packet header. */
+ PEEK( 4 );
+
+ if( p_peek[0] || p_peek[1] || p_peek[2] != 1 || p_peek[3] < 0xB9 )
+ {
+ if( p_peek[0] || p_peek[1] || p_peek[2] )
+ {
+ /* It is common for MPEG-1 streams to pad with zeros
+ * (although it is forbidden by the recommendation), so
+ * don't bother everybody in this case. */
+ msg_Warn( p_input, "garbage (0x%.2x%.2x%.2x%.2x)",
+ p_peek[0], p_peek[1], p_peek[2], p_peek[3] );
+ }
+
+ /* This is not the startcode of a packet. Read the stream
+ * until we find one. */
+ while( p_peek[0] || p_peek[1] || p_peek[2] != 1 || p_peek[3] < 0xB9 )
+ {
+ p_input->p_current_data++;
+ PEEK( 4 );
+ if( p_input->b_die ) return( -1 );
+ }
+ /* Packet found. */
+ }
+
+ /* 0x1B9 == SYSTEM_END_CODE, it is only 4 bytes long. */
+ if( p_peek[3] != 0xB9 )
+ {
+ /* The packet is at least 6 bytes long. */
+ PEEK( 6 );
+
+ if( p_peek[3] != 0xBA )
+ {
+ /* That's the case for all packets, except pack header. */
+ i_packet_size = (p_peek[4] << 8) | p_peek[5];
+ }
+ else
+ {
+ /* Pack header. */
+ if( (p_peek[4] & 0xC0) == 0x40 )
+ {
+ /* MPEG-2 */
+ i_packet_size = 8;
+ }
+ else if( (p_peek[4] & 0xF0) == 0x20 )
+ {
+ /* MPEG-1 */
+ i_packet_size = 6;
+ }
+ else
+ {
+ msg_Err( p_input, "unable to determine stream type" );
+ return( -1 );
+ }
+ }
+ }
+ else
+ {
+ /* System End Code */
+ i_packet_size = -2;
+ }
+
+ /* Fetch a packet of the appropriate size. */
+ i_read = input_SplitBuffer( p_input, pp_data, i_packet_size + 6 );
+ if( i_read <= 0 )
+ {
+ return( i_read );
+ }
+
+ /* In MPEG-2 pack headers we still have to read stuffing bytes. */
+ if( ((*pp_data)->p_demux_start[3] == 0xBA) && (i_packet_size == 8) )
+ {
+ size_t i_stuffing = ((*pp_data)->p_demux_start[13] & 0x7);
+ /* Force refill of the input buffer - though we don't care
+ * about p_peek. Please note that this is unoptimized. */
+ PEEK( i_stuffing );
+ p_input->p_current_data += i_stuffing;
+ }
+
+ return( 1 );
+}
+
+#undef PEEK
+
+/*****************************************************************************
+ * ParsePS: read the PS header
+ *****************************************************************************/
+static es_descriptor_t * ParsePS( input_thread_t * p_input,
+ data_packet_t * p_data )
+{
+ u32 i_code;
+ es_descriptor_t * p_es = NULL;
+
+ i_code = p_data->p_demux_start[3];
+
+ if( i_code > 0xBC ) /* ES start code */
+ {
+ u16 i_id;
+ int i_dummy;
+
+ /* This is a PES packet. Find out if we want it or not. */
+ i_id = GetID( p_data );
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ if( p_input->stream.pp_programs[0]->b_is_ok )
+ {
+ /* Look only at the selected ES. */
+ for( i_dummy = 0; i_dummy < p_input->stream.i_selected_es_number;
+ i_dummy++ )
+ {
+ if( p_input->stream.pp_selected_es[i_dummy] != NULL
+ && p_input->stream.pp_selected_es[i_dummy]->i_id == i_id )
+ {
+ p_es = p_input->stream.pp_selected_es[i_dummy];
+ break;
+ }
+ }
+ }
+ else
+ {
+ stream_ps_data_t * p_demux =
+ (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
+
+ /* Search all ES ; if not found -> AddES */
+ p_es = input_FindES( p_input, i_id );
+
+ if( p_es == NULL && !p_demux->b_has_PSM )
+ {
+ p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
+ i_id, 0 );
+ if( p_es != NULL )
+ {
+ p_es->i_stream_id = p_data->p_demux_start[3];
+
+ /* Set stream type and auto-spawn. */
+ if( (i_id & 0xF0) == 0xE0 )
+ {
+ /* MPEG video */
+ p_es->i_fourcc = VLC_FOURCC('m','p','g','v');
+ p_es->i_cat = VIDEO_ES;
+#ifdef AUTO_SPAWN
+ if( !p_input->stream.b_seekable )
+ input_SelectES( p_input, p_es );
+#endif
+ }
+ else if( (i_id & 0xE0) == 0xC0 )
+ {
+ /* MPEG audio */
+ p_es->i_fourcc = VLC_FOURCC('m','p','g','a');
+ p_es->i_cat = AUDIO_ES;
+#ifdef AUTO_SPAWN
+ if( !p_input->stream.b_seekable )
+ if( config_GetInt( p_input, "audio-channel" )
+ == (p_es->i_id & 0x1F) ||
+ ( config_GetInt( p_input, "audio-channel" ) < 0
+ && !(p_es->i_id & 0x1F) ) )
+ switch( config_GetInt( p_input, "audio-type" ) )
+ {
+ case -1:
+ case REQUESTED_MPEG:
+ input_SelectES( p_input, p_es );
+ }
+#endif
+ }
+ else if( (i_id & 0xF0FF) == 0x80BD )
+ {
+ /* A52 audio (0x80->0x8F) */
+ p_es->i_fourcc = VLC_FOURCC('a','5','2',' ');
+ p_es->i_cat = AUDIO_ES;
+#ifdef AUTO_SPAWN
+ if( !p_input->stream.b_seekable )
+ if( config_GetInt( p_input, "audio-channel" )
+ == ((p_es->i_id & 0xF00) >> 8) ||
+ ( config_GetInt( p_input, "audio-channel" ) < 0
+ && !((p_es->i_id & 0xF00) >> 8)) )
+ switch( config_GetInt( p_input, "audio-type" ) )
+ {
+ case -1:
+ case REQUESTED_A52:
+ input_SelectES( p_input, p_es );
+ }
+#endif
+ }
+ else if( (i_id & 0xE0FF) == 0x20BD )
+ {
+ /* Subtitles video (0x20->0x3F) */
+ p_es->i_fourcc = VLC_FOURCC('s','p','u',' ');
+ p_es->i_cat = SPU_ES;
+#ifdef AUTO_SPAWN
+ if( config_GetInt( p_input, "spu-channel" )
+ == ((p_es->i_id & 0x1F00) >> 8) )
+ {
+ if( !p_input->stream.b_seekable )
+ input_SelectES( p_input, p_es );
+ }
+#endif
+ }
+ else if( (i_id & 0xF0FF) == 0xA0BD )
+ {
+ /* LPCM audio (0xA0->0xAF) */
+ p_es->i_fourcc = VLC_FOURCC('l','p','c','m');
+ p_es->i_cat = AUDIO_ES;
+ }
+ else
+ {
+ p_es->i_fourcc = 0;
+ }
+ }
+
+ /* Tell the interface the stream has changed */
+ p_input->stream.b_changed = 1;
+ }
+ } /* stream.b_is_ok */
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ } /* i_code > 0xBC */
+
+ return( p_es );
+}
+
+/*****************************************************************************
+ * DemuxPS: first step of demultiplexing: the PS header
+ *****************************************************************************/
+static void DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
+{
+ u32 i_code;
+ vlc_bool_t b_trash = 0;
+ es_descriptor_t * p_es = NULL;
+
+ i_code = ((u32)p_data->p_demux_start[0] << 24)
+ | ((u32)p_data->p_demux_start[1] << 16)
+ | ((u32)p_data->p_demux_start[2] << 8)
+ | p_data->p_demux_start[3];
+ if( i_code <= 0x1BC )
+ {
+ switch( i_code )
+ {
+ case 0x1BA: /* PACK_START_CODE */
+ {
+ /* Read the SCR. */
+ mtime_t scr_time;
+ u32 i_mux_rate;
+
+ if( (p_data->p_demux_start[4] & 0xC0) == 0x40 )
+ {
+ /* MPEG-2 */
+ byte_t p_header[14];
+ byte_t * p_byte;
+ p_byte = p_data->p_demux_start;
+
+ if( MoveChunk( p_header, &p_data, &p_byte, 14 ) != 14 )
+ {
+ msg_Warn( p_input,
+ "packet too short to have a header" );
+ b_trash = 1;
+ break;
+ }
+ scr_time =
+ ((mtime_t)(p_header[4] & 0x38) << 27) |
+ ((mtime_t)(U32_AT(p_header + 4) & 0x03FFF800)
+ << 4) |
+ ((( ((mtime_t)U16_AT(p_header + 6) << 16)
+ | (mtime_t)U16_AT(p_header + 8) ) & 0x03FFF800)
+ >> 11);
+
+ /* mux_rate */
+ i_mux_rate = ((u32)U16_AT(p_header + 10) << 6)
+ | (p_header[12] >> 2);
+ /* FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
+ * This is the biggest kludge ever !
+ * I don't know what's wrong with mux_rate calculation
+ * but this heuristic works well : */
+ i_mux_rate <<= 1;
+ i_mux_rate /= 3;
+ }
+ else
+ {
+ /* MPEG-1 SCR is like PTS. */
+ byte_t p_header[12];
+ byte_t * p_byte;
+ p_byte = p_data->p_demux_start;
+
+ if( MoveChunk( p_header, &p_data, &p_byte, 12 ) != 12 )
+ {
+ msg_Warn( p_input,
+ "packet too short to have a header" );
+ b_trash = 1;
+ break;
+ }
+ scr_time =
+ ((mtime_t)(p_header[4] & 0x0E) << 29) |
+ (((mtime_t)U32_AT(p_header + 4) & 0xFFFE00) << 6) |
+ ((mtime_t)p_header[7] << 7) |
+ ((mtime_t)p_header[8] >> 1);
+
+ /* mux_rate */
+ i_mux_rate = (U32_AT(p_header + 8) & 0x7FFFFE) >> 1;
+ }
+ /* Call the pace control. */
+ input_ClockManageRef( p_input,
+ p_input->stream.p_selected_program,
+ scr_time );
+
+ if( i_mux_rate != p_input->stream.i_mux_rate
+ && p_input->stream.i_mux_rate )
+ {
+ msg_Warn( p_input,
+ "mux_rate changed, expect cosmetic errors" );
+ }
+ p_input->stream.i_mux_rate = i_mux_rate;
+
+ b_trash = 1;
+ }
+ break;
+
+ case 0x1BB: /* SYSTEM_START_CODE */
+ b_trash = 1; /* Nothing interesting */
+ break;
+
+ case 0x1BC: /* PROGRAM_STREAM_MAP_CODE */
+ DecodePSM( p_input, p_data );
+ b_trash = 1;
+ break;
+
+ case 0x1B9: /* PROGRAM_END_CODE */
+ b_trash = 1;
+ break;
+
+ default:
+ /* This should not happen */
+ b_trash = 1;
+ msg_Warn( p_input, "unwanted packet received "
+ "with startcode 0x%.8x", i_code );
+ }
+ }
+ else
+ {
+ p_es = ParsePS( p_input, p_data );
+
+ vlc_mutex_lock( &p_input->stream.control.control_lock );
+ if( p_es != NULL && p_es->p_decoder_fifo != NULL
+ && (p_es->i_cat != AUDIO_ES || !p_input->stream.control.b_mute) )
+ {
+ vlc_mutex_unlock( &p_input->stream.control.control_lock );
+ p_es->c_packets++;
+ GatherPES( p_input, p_data, p_es, 1, 0 );
+ }
+ else
+ {
+ vlc_mutex_unlock( &p_input->stream.control.control_lock );
+ b_trash = 1;
+ }
+ }
+
+ /* Trash the packet if it has no payload or if it isn't selected */
+ if( b_trash )
+ {
+ input_DeletePacket( p_input->p_method_data, p_data );
+ p_input->stream.c_packets_trashed++;
+ }
+}
+
+
+/*
+ * TS Demultiplexing
+ */
+
+/*****************************************************************************
+ * ReadTS: store a TS packet into a data_buffer_t
+ *****************************************************************************/
+#define PEEK( SIZE ) \
+ i_error = input_Peek( p_input, &p_peek, SIZE ); \
+ if( i_error == -1 ) \
+ { \
+ return( -1 ); \
+ } \
+ else if( i_error < SIZE ) \
+ { \
+ /* EOF */ \
+ return( 0 ); \
+ }
+
+static ssize_t ReadTS( input_thread_t * p_input, data_packet_t ** pp_data )
+{
+ byte_t * p_peek;
+ ssize_t i_error, i_read;
+
+ PEEK( 1 );
+
+ if( *p_peek != TS_SYNC_CODE )
+ {
+ msg_Warn( p_input, "garbage at input (%x)", *p_peek );
+
+ if( p_input->i_mtu )
+ {
+ while( *p_peek != TS_SYNC_CODE )
+ {
+ /* Try to resync on next packet. */
+ PEEK( TS_PACKET_SIZE );
+ p_input->p_current_data += TS_PACKET_SIZE;
+ PEEK( 1 );
+ }
+ }
+ else
+ {
+ /* Move forward until we find 0x47 (and hope it's the good
+ * one... FIXME) */
+ while( *p_peek != TS_SYNC_CODE )
+ {
+ p_input->p_current_data++;
+ PEEK( 1 );
+ }
+ }
+ }
+
+ i_read = input_SplitBuffer( p_input, pp_data, TS_PACKET_SIZE );
+ if( i_read <= 0 )
+ {
+ return( i_read );
+ }
+
+ return( 1 );
+}
+
+/*****************************************************************************
+ * DemuxTS: first step of demultiplexing: the TS header
+ *****************************************************************************/
+static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
+ psi_callback_t pf_psi_callback )
+{
+ u16 i_pid;
+ int i_dummy;
+ vlc_bool_t b_adaptation; /* Adaptation field is present */
+ vlc_bool_t b_payload; /* Packet carries payload */
+ vlc_bool_t b_unit_start; /* A PSI or a PES start in the packet */
+ vlc_bool_t b_trash = 0; /* Is the packet unuseful ? */
+ vlc_bool_t b_lost = 0; /* Was there a packet loss ? */
+ vlc_bool_t b_psi = 0; /* Is this a PSI ? */
+ vlc_bool_t b_pcr = 0; /* Does it have a PCR ? */
+ es_descriptor_t * p_es = NULL;
+ es_ts_data_t * p_es_demux = NULL;
+ pgrm_ts_data_t * p_pgrm_demux = NULL;
+
+#define p (p_data->p_demux_start)
+ /* Extract flags values from TS common header. */
+ i_pid = ((p[1] & 0x1F) << 8) | p[2];
+ b_unit_start = (p[1] & 0x40);
+ b_adaptation = (p[3] & 0x20);
+ b_payload = (p[3] & 0x10);
+
+ /* Find out the elementary stream. */
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ for( i_dummy = 0; i_dummy < p_input->stream.i_pgrm_number; i_dummy ++ )
+ {
+ if( (( pgrm_ts_data_t * ) p_input->stream.pp_programs[i_dummy]->
+ p_demux_data)->i_pcr_pid == i_pid )
+ {
+ b_pcr = 1;
+ break;
+ }
+ }
+
+ p_es= input_FindES( p_input, i_pid );
+
+ if( (p_es != NULL) && (p_es->p_demux_data != NULL) )
+ {
+ p_es_demux = (es_ts_data_t *)p_es->p_demux_data;
+
+ if( p_es_demux->b_psi )
+ {
+ b_psi = 1;
+ }
+ else
+ {
+ p_pgrm_demux = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data;
+ }
+ }
+
+ vlc_mutex_lock( &p_input->stream.control.control_lock );
+ if( ( p_es == NULL ) || (p_es->i_cat == AUDIO_ES
+ && p_input->stream.control.b_mute) )
+ {
+ /* Not selected. Just read the adaptation field for a PCR. */
+ b_trash = 1;
+ }
+ else if( p_es->p_decoder_fifo == NULL && !b_psi )
+ {
+ b_trash = 1;
+ }
+
+ vlc_mutex_unlock( &p_input->stream.control.control_lock );
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+
+ /* Don't change the order of the tests : if b_psi then p_pgrm_demux
+ * may still be null. Who said it was ugly ?
+ * I have written worse. --Meuuh */
+ if( ( p_es ) &&
+ ((p_es->p_decoder_fifo != NULL) || b_psi || b_pcr ) )
+ {
+ p_es->c_packets++;
+
+ /* Extract adaptation field information if any */
+
+ if( !b_adaptation )
+ {
+ /* We don't have any adaptation_field, so payload starts
+ * immediately after the 4 byte TS header */
+ p_data->p_payload_start += 4;
+ }
+ else
+ {
+ /* p[4] is adaptation_field_length minus one */
+ p_data->p_payload_start += 5 + p[4];
+
+ /* The adaptation field can be limited to the
+ * adaptation_field_length byte, so that there is nothing to do:
+ * skip this possibility */
+ if( p[4] )
+ {
+ /* If the packet has both adaptation_field and payload,
+ * adaptation_field cannot be more than 182 bytes long; if
+ * there is only an adaptation_field, it must fill the next
+ * 183 bytes. */
+ if( b_payload ? (p[4] > 182) : (p[4] != 183) )
+ {
+ msg_Warn( p_input, "invalid TS adaptation field (%p)",
+ p_data );
+ p_data->b_discard_payload = 1;
+ p_es->c_invalid_packets++;
+ }
+
+ /* Now we are sure that the byte containing flags is present:
+ * read it */
+ else
+ {
+ /* discontinuity_indicator */
+ if( p[5] & 0x80 )
+ {
+ msg_Warn( p_input,
+ "discontinuity_indicator encountered by TS demux "
+ "(position read: %d, saved: %d)",
+ p[5] & 0x80, p_es_demux->i_continuity_counter );
+
+ /* If the PID carries the PCR, there will be a system
+ * time-based discontinuity. We let the PCR decoder
+ * handle that. */
+ p_es->p_pgrm->i_synchro_state = SYNCHRO_REINIT;
+
+ /* There also may be a continuity_counter
+ * discontinuity: resynchronize our counter with
+ * the one of the stream. */
+ p_es_demux->i_continuity_counter = (p[3] & 0x0f) - 1;
+ }
+
+ } /* valid TS adaptation field ? */
+ } /* length > 0 */
+ } /* has adaptation field */
+ /* Check the continuity of the stream. */
+ i_dummy = ((p[3] & 0x0f) - p_es_demux->i_continuity_counter) & 0x0f;
+ if( i_dummy == 1 )
+ {
+ /* Everything is ok, just increase our counter */
+ (p_es_demux->i_continuity_counter)++;
+ }
+ else
+ {
+ if( !b_payload && i_dummy == 0 )
+ {
+ /* This is a packet without payload, this is allowed by the
+ * draft. As there is nothing interesting in this packet
+ * (except PCR that have already been handled), we can trash
+ * the packet. */
+ b_trash = 1;
+ }
+ else if( i_dummy <= 0 )
+ {
+ /* Duplicate packet: mark it as being to be trashed. */
+ msg_Warn( p_input,
+ "duplicate packet received by TS demux" );
+ b_trash = 1;
+ }
+ else if( p_es_demux->i_continuity_counter == 0xFF )
+ {
+ /* This means that the packet is the first one we receive for
+ * this ES since the continuity counter ranges between 0 and
+ * 0x0F excepts when it has been initialized by the input:
+ * init the counter to the correct value. */
+ msg_Warn( p_input, "first packet for PID %d received "
+ "by TS demux", p_es->i_id );
+ p_es_demux->i_continuity_counter = (p[3] & 0x0f);
+ }
+ else
+ {
+ /* This can indicate that we missed a packet or that the
+ * continuity_counter wrapped and we received a dup packet:
+ * as we don't know, do as if we missed a packet to be sure
+ * to recover from this situation */
+ msg_Warn( p_input,
+ "packet lost by TS demux: current %d, packet %d",
+ p_es_demux->i_continuity_counter & 0x0f,
+ p[3] & 0x0f );
+ b_lost = 1;
+ p_es_demux->i_continuity_counter = p[3] & 0x0f;
+ } /* not continuous */
+ } /* continuity */
+ } /* if selected or PCR */
+
+ /* Handle PCR */
+ if( b_pcr && b_adaptation && (p[5] & 0x10) && p[4]>=7 )
+ {
+ /* Read the PCR. */
+ mtime_t pcr_time;
+ pcr_time = ( (mtime_t)p[6] << 25 ) |
+ ( (mtime_t)p[7] << 17 ) |
+ ( (mtime_t)p[8] << 9 ) |
+ ( (mtime_t)p[9] << 1 ) |
+ ( (mtime_t)p[10] >> 7 );
+ /* Call the pace control. */
+ for( i_dummy = 0; i_dummy < p_input->stream.i_pgrm_number;
+ i_dummy ++ )
+ {
+ if( ( ( pgrm_ts_data_t * ) p_input->stream.pp_programs[i_dummy]->
+ p_demux_data )->i_pcr_pid == i_pid )
+ {
+ input_ClockManageRef( p_input,
+ p_input->stream.pp_programs[i_dummy], pcr_time );
+ }
+ }
+
+ }
+
+ /* Trash the packet if it has no payload or if it isn't selected */
+ if( b_trash )
+ {
+ input_DeletePacket( p_input->p_method_data, p_data );
+ p_input->stream.c_packets_trashed++;
+ }
+ else
+ {
+ if( b_psi )
+ {
+ /* The payload contains PSI tables */
+ (* pf_psi_callback) ( p_input, p_data, p_es, b_unit_start );
+ }
+ else
+ {
+ /* The payload carries a PES stream */
+ GatherPES( p_input, p_data, p_es, b_unit_start, b_lost );
+ }
+
+ }
+
+#undef p
+
+}
+
--- /dev/null
+/*****************************************************************************
+ * system.h: MPEG demultiplexing.
+ *****************************************************************************
+ * Copyright (C) 1999-2002 VideoLAN
+ * $Id: system.h,v 1.1 2002/08/07 00:29:36 sam Exp $
+ *
+ * Authors: Christophe Massiot <massiot@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+/*
+ * Optional MPEG demultiplexing
+ */
+
+/*****************************************************************************
+ * Constants
+ *****************************************************************************/
+#define TS_PACKET_SIZE 188 /* Size of a TS packet */
+#define TS_SYNC_CODE 0x47 /* First byte of a TS packet */
+#define PSI_SECTION_SIZE 4096 /* Maximum size of a PSI section */
+
+#define PAT_UNINITIALIZED (1 << 6)
+#define PMT_UNINITIALIZED (1 << 6)
+
+#define PSI_IS_PAT 0x00
+#define PSI_IS_PMT 0x01
+#define UNKNOWN_PSI 0xff
+
+/****************************************************************************
+ * psi_callback_t
+ ****************************************************************************
+ * Used by TS demux to handle a PSI, either with the builtin decoder, either
+ * with a library such as libdvbpsi
+ ****************************************************************************/
+typedef void( * psi_callback_t )(
+ input_thread_t * p_input,
+ data_packet_t * p_data,
+ es_descriptor_t * p_es,
+ vlc_bool_t b_unit_start );
+
+
+/****************************************************************************
+ * mpeg_demux_t
+ ****************************************************************************
+ * Demux callbacks exported by the helper plugin
+ ****************************************************************************/
+typedef struct mpeg_demux_t
+{
+ module_t * p_module;
+
+ ssize_t (*pf_read_ps) ( input_thread_t *, data_packet_t ** );
+ es_descriptor_t * (*pf_parse_ps) ( input_thread_t *, data_packet_t * );
+ void (*pf_demux_ps) ( input_thread_t *, data_packet_t * );
+
+ ssize_t (*pf_read_ts) ( input_thread_t *, data_packet_t ** );
+ void (*pf_demux_ts) ( input_thread_t *, data_packet_t *,
+ psi_callback_t );
+} mpeg_demux_t;
+
+/*****************************************************************************
+ * psi_section_t
+ *****************************************************************************
+ * Describes a PSI section. Beware, it doesn't contain pointers to the TS
+ * packets that contain it as for a PES, but the data themselves
+ *****************************************************************************/
+typedef struct psi_section_t
+{
+ byte_t buffer[PSI_SECTION_SIZE];
+
+ u8 i_section_number;
+ u8 i_last_section_number;
+ u8 i_version_number;
+ u16 i_section_length;
+ u16 i_read_in_section;
+
+ /* the PSI is complete */
+ vlc_bool_t b_is_complete;
+
+ /* packet missed up ? */
+ vlc_bool_t b_trash;
+
+ /*about sections */
+ vlc_bool_t b_section_complete;
+
+ /* where are we currently ? */
+ byte_t * p_current;
+
+} psi_section_t;
+
+/*****************************************************************************
+ * es_ts_data_t: extension of es_descriptor_t
+ *****************************************************************************/
+typedef struct es_ts_data_t
+{
+ vlc_bool_t b_psi; /* Does the stream have to be handled by
+ * the PSI decoder ? */
+
+ int i_psi_type; /* There are different types of PSI */
+
+ psi_section_t * p_psi_section; /* PSI packets */
+
+ /* Markers */
+ int i_continuity_counter;
+} es_ts_data_t;
+
+/*****************************************************************************
+ * pgrm_ts_data_t: extension of pgrm_descriptor_t
+ *****************************************************************************/
+typedef struct pgrm_ts_data_t
+{
+ u16 i_pcr_pid; /* PCR ES, for TS streams */
+ int i_pmt_version;
+ /* libdvbpsi pmt decoder handle */
+ void * p_pmt_handle;
+} pgrm_ts_data_t;
+
+/*****************************************************************************
+ * stream_ts_data_t: extension of stream_descriptor_t
+ *****************************************************************************/
+typedef struct stream_ts_data_t
+{
+ int i_pat_version; /* Current version of the PAT */
+ /* libdvbpsi pmt decoder handle */
+ void * p_pat_handle;
+} stream_ts_data_t;
+
+/*****************************************************************************
+ * stream_ps_data_t: extension of stream_descriptor_t
+ *****************************************************************************/
+typedef struct stream_ps_data_t
+{
+ vlc_bool_t b_has_PSM; /* very rare, in fact */
+
+ u8 i_PSM_version;
+} stream_ps_data_t;
+
+/* PSM version is 5 bits, so -1 is not a valid value */
+#define EMPTY_PSM_VERSION -1
+
* mpeg_ts.c : Transport Stream input module for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
- * $Id: ts.c,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: ts.c,v 1.2 2002/08/07 00:29:36 sam Exp $
*
* Authors: Henri Fallon <henri@via.ecp.fr>
* Johan Bilien <jobi@via.ecp.fr>
# endif
#endif
+#include "system.h"
+
/*****************************************************************************
* Constants
*****************************************************************************/
#define TS_READ_ONCE 200
+/*****************************************************************************
+ * Private structure
+ *****************************************************************************/
+struct demux_sys_t
+{
+ module_t * p_module;
+ mpeg_demux_t mpeg;
+};
+
/*****************************************************************************
* Local prototypes
*****************************************************************************/
-static int Activate ( vlc_object_t * );
-static int Demux ( input_thread_t * );
+static int Activate ( vlc_object_t * );
+static void Deactivate ( vlc_object_t * );
+static int Demux ( input_thread_t * );
#if defined MODULE_NAME_IS_ts
static void TSDemuxPSI ( input_thread_t *, data_packet_t *,
set_capability( "demux", 170 );
add_shortcut( "ts_dvbpsi" );
#endif
- set_callbacks( Activate, NULL );
+ set_callbacks( Activate, Deactivate );
vlc_module_end();
/*****************************************************************************
- * Activate: initializes TS structures
+ * Activate: initialize TS structures
*****************************************************************************/
static int Activate( vlc_object_t * p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
- es_descriptor_t * p_pat_es;
- es_ts_data_t * p_demux_data;
- stream_ts_data_t * p_stream_data;
- byte_t * p_peek;
+ demux_sys_t * p_demux;
+ es_descriptor_t * p_pat_es;
+ es_ts_data_t * p_demux_data;
+ stream_ts_data_t * p_stream_data;
+ byte_t * p_peek;
/* Set the demux function */
p_input->pf_demux = Demux;
if( input_Peek( p_input, &p_peek, 1 ) < 1 )
{
msg_Err( p_input, "cannot peek()" );
- return( -1 );
+ return -1;
}
if( *p_peek != TS_SYNC_CODE )
else
{
msg_Warn( p_input, "TS module discarded (no sync)" );
- return( -1 );
+ return -1;
}
}
p_input->i_bufsize = (p_input->i_mtu / TS_PACKET_SIZE) * TS_PACKET_SIZE;
}
+ p_demux = p_input->p_demux_data = malloc( sizeof(demux_sys_t ) );
+ if( p_demux == NULL )
+ {
+ return -1;
+ }
+
+ p_input->p_private = (void*)&p_demux->mpeg;
+ p_demux->p_module = module_Need( p_input, "mpeg-system", NULL );
+ if( p_demux->p_module == NULL )
+ {
+ free( p_input->p_demux_data );
+ return -1;
+ }
+
vlc_mutex_lock( &p_input->stream.stream_lock );
if( input_InitStream( p_input, sizeof( stream_ts_data_t ) ) == -1 )
{
- return( -1 );
+ module_Unneed( p_input, p_demux->p_module );
+ free( p_input->p_demux_data );
+ return -1;
}
-
+
p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
p_stream_data->i_pat_version = PAT_UNINITIALIZED ;
if( p_stream_data->p_pat_handle == NULL )
{
msg_Err( p_input, "could not create PAT decoder" );
- return( -1 );
+ module_Unneed( p_input, p_demux->p_module );
+ free( p_input->p_demux_data );
+ return -1;
}
#endif
vlc_mutex_unlock( &p_input->stream.stream_lock );
- return( 0 );
+ return 0;
+}
+
+/*****************************************************************************
+ * Deactivate: deinitialize TS structures
+ *****************************************************************************/
+static void Deactivate( vlc_object_t * p_this )
+{
+ input_thread_t * p_input = (input_thread_t *)p_this;
+
+ module_Unneed( p_input, p_input->p_demux_data->p_module );
+ free( p_input->p_demux_data );
}
/*****************************************************************************
*****************************************************************************/
static int Demux( input_thread_t * p_input )
{
+ demux_sys_t * p_demux = p_input->p_demux_data;
int i_read_once = (p_input->i_mtu ?
p_input->i_bufsize / TS_PACKET_SIZE :
TS_READ_ONCE);
data_packet_t * p_data;
ssize_t i_result;
- i_result = input_ReadTS( p_input, &p_data );
+ i_result = p_demux->mpeg.pf_read_ts( p_input, &p_data );
if( i_result <= 0 )
{
- return( i_result );
+ return i_result;
}
- input_DemuxTS( p_input, p_data, (psi_callback_t) &PSI_CALLBACK );
+ p_demux->mpeg.pf_demux_ts( p_input, p_data,
+ (psi_callback_t) &PSI_CALLBACK );
}
- return( i_read_once );
+ return i_read_once;
}
+++ /dev/null
-/*****************************************************************************
- * mpeg_system.c: TS, PS and PES management
- *****************************************************************************
- * Copyright (C) 1998-2001 VideoLAN
- * $Id: mpeg_system.c,v 1.101 2002/08/04 17:23:44 sam Exp $
- *
- * Authors: Christophe Massiot <massiot@via.ecp.fr>
- * Michel Lespinasse <walken@via.ecp.fr>
- * Benoît Steiner <benny@via.ecp.fr>
- * Samuel Hocevar <sam@via.ecp.fr>
- * Henri Fallon <henri@via.ecp.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#include <stdlib.h>
-#include <string.h> /* memcpy(), memset() */
-#include <sys/types.h> /* off_t */
-
-#include <vlc/vlc.h>
-
-#include "stream_control.h"
-#include "input_ext-intf.h"
-#include "input_ext-dec.h"
-#include "input_ext-plugins.h"
-
-/*
- * PES Packet management
- */
-
-/*****************************************************************************
- * MoveChunk
- *****************************************************************************
- * Small utility function used to parse discontinuous headers safely. Copies
- * i_buf_len bytes of data to a buffer and returns the size copied.
- * It also solves some alignment problems on non-IA-32, non-PPC processors.
- * This is a variation on the theme of input_ext-dec.h:GetChunk().
- *****************************************************************************/
-static inline size_t MoveChunk( byte_t * p_dest, data_packet_t ** pp_data_src,
- byte_t ** pp_src, size_t i_buf_len )
-{
- ptrdiff_t i_available;
-
- if( (i_available = (*pp_data_src)->p_payload_end - *pp_src)
- >= i_buf_len )
- {
- if( p_dest != NULL )
- memcpy( p_dest, *pp_src, i_buf_len );
- *pp_src += i_buf_len;
- return( i_buf_len );
- }
- else
- {
- size_t i_init_len = i_buf_len;
-
- do
- {
- if( p_dest != NULL )
- memcpy( p_dest, *pp_src, i_available );
- *pp_data_src = (*pp_data_src)->p_next;
- i_buf_len -= i_available;
- p_dest += i_available;
- if( *pp_data_src == NULL )
- {
- *pp_src = NULL;
- return( i_init_len - i_buf_len );
- }
- *pp_src = (*pp_data_src)->p_payload_start;
- }
- while( (i_available = (*pp_data_src)->p_payload_end - *pp_src)
- <= i_buf_len );
-
- if( i_buf_len )
- {
- if( p_dest != NULL )
- memcpy( p_dest, *pp_src, i_buf_len );
- *pp_src += i_buf_len;
- }
- return( i_init_len );
- }
-}
-
-/*****************************************************************************
- * input_ParsePES
- *****************************************************************************
- * Parse a finished PES packet and analyze its header.
- *****************************************************************************/
-#define PES_HEADER_SIZE 7
-void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
-{
- data_packet_t * p_data;
- byte_t * p_byte;
- byte_t p_header[PES_HEADER_SIZE];
- int i_done;
-
-#define p_pes (p_es->p_pes)
-
- /* Parse the header. The header has a variable length, but in order
- * to improve the algorithm, we will read the 14 bytes we may be
- * interested in */
- p_data = p_pes->p_first;
- p_byte = p_data->p_payload_start;
- i_done = 0;
-
- if( MoveChunk( p_header, &p_data, &p_byte, PES_HEADER_SIZE )
- != PES_HEADER_SIZE )
- {
- msg_Warn( p_input, "PES packet too short to have a header" );
- input_DeletePES( p_input->p_method_data, p_pes );
- p_pes = NULL;
- return;
- }
-
- /* Get the PES size if defined */
- p_es->i_pes_real_size = U16_AT(p_header + 4);
- if( p_es->i_pes_real_size )
- {
- p_es->i_pes_real_size += 6;
- }
-
- /* First read the 6 header bytes common to all PES packets:
- * use them to test the PES validity */
- if( (p_header[0] || p_header[1] || (p_header[2] != 1)) )
- {
- /* packet_start_code_prefix != 0x000001 */
- msg_Err( p_input, "data loss, PES packet does not start with 000001" );
- input_DeletePES( p_input->p_method_data, p_pes );
- p_pes = NULL;
- }
- else
- {
- int i_pes_header_size, i_payload_size;
-
- if ( p_es->i_pes_real_size &&
- (p_es->i_pes_real_size != p_pes->i_pes_size) )
- {
- /* PES_packet_length is set and != total received payload */
- /* Warn the decoder that the data may be corrupt. */
- msg_Warn( p_input, "packet corrupted, PES sizes do not match" );
- }
-
- switch( p_es->i_stream_id )
- {
- case 0xBC: /* Program stream map */
- case 0xBE: /* Padding */
- case 0xBF: /* Private stream 2 */
- case 0xB0: /* ECM */
- case 0xB1: /* EMM */
- case 0xFF: /* Program stream directory */
- case 0xF2: /* DSMCC stream */
- case 0xF8: /* ITU-T H.222.1 type E stream */
- /* The payload begins immediately after the 6 bytes header, so
- * we have finished with the parsing */
- i_pes_header_size = 6;
- break;
-
- default:
- if( (p_header[6] & 0xC0) == 0x80 )
- {
- /* MPEG-2 : the PES header contains at least 3 more bytes. */
- size_t i_max_len;
- vlc_bool_t b_has_pts, b_has_dts;
- byte_t p_full_header[12];
-
- p_pes->b_data_alignment = p_header[6] & 0x04;
-
- i_max_len = MoveChunk( p_full_header, &p_data, &p_byte, 12 );
- if( i_max_len < 2 )
- {
- msg_Warn( p_input,
- "PES packet too short to have a MPEG-2 header" );
- input_DeletePES( p_input->p_method_data,
- p_pes );
- p_pes = NULL;
- return;
- }
-
- b_has_pts = p_full_header[0] & 0x80;
- b_has_dts = p_full_header[0] & 0x40;
- i_pes_header_size = p_full_header[1] + 9;
-
- /* Now parse the optional header extensions */
- if( b_has_pts )
- {
- if( i_max_len < 7 )
- {
- msg_Warn( p_input,
- "PES packet too short to have a MPEG-2 header" );
- input_DeletePES( p_input->p_method_data,
- p_pes );
- p_pes = NULL;
- return;
- }
- p_pes->i_pts = input_ClockGetTS( p_input, p_es->p_pgrm,
- ( ((mtime_t)(p_full_header[2] & 0x0E) << 29) |
- ((mtime_t)(p_full_header[3]) << 22) |
- ((mtime_t)(p_full_header[4] & 0xFE) << 14) |
- ((mtime_t)p_full_header[5] << 7) |
- ((mtime_t)p_full_header[6] >> 1) ) );
-
- if( b_has_dts )
- {
- if( i_max_len < 12 )
- {
- msg_Warn( p_input,
- "PES packet too short to have a MPEG-2 header" );
- input_DeletePES( p_input->p_method_data,
- p_pes );
- p_pes = NULL;
- return;
- }
- p_pes->i_dts = input_ClockGetTS( p_input, p_es->p_pgrm,
- ( ((mtime_t)(p_full_header[7] & 0x0E) << 29) |
- (((mtime_t)U16_AT(p_full_header + 8) << 14)
- - (1 << 14)) |
- ((mtime_t)U16_AT(p_full_header + 10) >> 1) ) );
- }
- }
- }
- else
- {
- /* Probably MPEG-1 */
- vlc_bool_t b_has_pts, b_has_dts;
-
- i_pes_header_size = 6;
- p_data = p_pes->p_first;
- p_byte = p_data->p_payload_start;
- /* Cannot fail because the previous one succeeded. */
- MoveChunk( NULL, &p_data, &p_byte, 6 );
-
- while( *p_byte == 0xFF && i_pes_header_size < 23 )
- {
- i_pes_header_size++;
- if( MoveChunk( NULL, &p_data, &p_byte, 1 ) != 1 )
- {
- msg_Warn( p_input,
- "PES packet too short to have a MPEG-1 header" );
- input_DeletePES( p_input->p_method_data, p_pes );
- p_pes = NULL;
- return;
- }
- }
- if( i_pes_header_size == 23 )
- {
- msg_Err( p_input, "too much MPEG-1 stuffing" );
- input_DeletePES( p_input->p_method_data, p_pes );
- p_pes = NULL;
- return;
- }
-
- if( (*p_byte & 0xC0) == 0x40 )
- {
- /* Don't ask why... --Meuuh */
- /* Erm... why ? --Sam */
- /* Well... According to the recommendation, it is for
- * STD_buffer_scale and STD_buffer_size. --Meuuh */
- i_pes_header_size += 2;
- if( MoveChunk( NULL, &p_data, &p_byte, 2 ) != 2 )
- {
- msg_Warn( p_input,
- "PES packet too short to have a MPEG-1 header" );
- input_DeletePES( p_input->p_method_data, p_pes );
- p_pes = NULL;
- return;
- }
- }
-
- i_pes_header_size++;
-
- b_has_pts = *p_byte & 0x20;
- b_has_dts = *p_byte & 0x10;
-
- if( b_has_pts )
- {
- byte_t p_ts[5];
-
- i_pes_header_size += 4;
- if( MoveChunk( p_ts, &p_data, &p_byte, 5 ) != 5 )
- {
- msg_Warn( p_input,
- "PES packet too short to have a MPEG-1 header" );
- input_DeletePES( p_input->p_method_data, p_pes );
- p_pes = NULL;
- return;
- }
-
- p_pes->i_pts = input_ClockGetTS( p_input, p_es->p_pgrm,
- ( ((mtime_t)(p_ts[0] & 0x0E) << 29) |
- (((mtime_t)U32_AT(p_ts) & 0xFFFE00) << 6) |
- ((mtime_t)p_ts[3] << 7) |
- ((mtime_t)p_ts[4] >> 1) ) );
-
- if( b_has_dts )
- {
- i_pes_header_size += 5;
- if( MoveChunk( p_ts, &p_data, &p_byte, 5 ) != 5 )
- {
- msg_Warn( p_input,
- "PES packet too short to have a MPEG-1 header" );
- input_DeletePES( p_input->p_method_data, p_pes );
- p_pes = NULL;
- return;
- }
-
- p_pes->i_dts = input_ClockGetTS( p_input,
- p_es->p_pgrm,
- ( ((mtime_t)(p_ts[0] & 0x0E) << 29) |
- (((mtime_t)U32_AT(p_ts) & 0xFFFE00) << 6) |
- ((mtime_t)p_ts[3] << 7) |
- ((mtime_t)p_ts[4] >> 1) ) );
- }
- }
- }
-
- break;
- }
-
- if( p_es->i_stream_id == 0xbd )
- {
- /* With private stream 1, the first byte of the payload
- * is a stream_private_id, so skip it. */
- i_pes_header_size++;
- }
-
- if( p_es->i_fourcc == VLC_FOURCC('a','5','2',' ') )
- {
- /* With A52 audio, we need to skip first 3 bytes */
- i_pes_header_size += 3;
- }
-
- /* Now we've parsed the header, we just have to indicate in some
- * specific data packets where the PES payload begins (renumber
- * p_payload_start), so that the decoders can find the beginning
- * of their data right out of the box. */
- p_data = p_pes->p_first;
- i_payload_size = p_data->p_payload_end
- - p_data->p_payload_start;
- while( i_pes_header_size > i_payload_size )
- {
- /* These packets are entirely filled by the PES header. */
- i_pes_header_size -= i_payload_size;
- p_data->p_payload_start = p_data->p_payload_end;
- /* Go to the next data packet. */
- if( (p_data = p_data->p_next) == NULL )
- {
- msg_Err( p_input, "PES header bigger than payload" );
- input_DeletePES( p_input->p_method_data, p_pes );
- p_pes = NULL;
- return;
- }
- i_payload_size = p_data->p_payload_end
- - p_data->p_payload_start;
- }
- /* This last packet is partly header, partly payload. */
- if( i_payload_size < i_pes_header_size )
- {
- msg_Err( p_input, "PES header bigger than payload" );
- input_DeletePES( p_input->p_method_data, p_pes );
- p_pes = NULL;
- return;
- }
- p_data->p_payload_start += i_pes_header_size;
-
-
- /* Now we can eventually put the PES packet in the decoder's
- * PES fifo */
- if( p_es->p_decoder_fifo != NULL )
- {
- input_DecodePES( p_es->p_decoder_fifo, p_pes );
- }
- else
- {
- msg_Err( p_input, "no fifo to receive PES %p "
- "(who wrote this damn code ?)", p_pes );
- input_DeletePES( p_input->p_method_data, p_pes );
- }
- p_pes = NULL;
- }
-#undef p_pes
-
-}
-
-/*****************************************************************************
- * input_GatherPES:
- *****************************************************************************
- * Gather a PES packet.
- *****************************************************************************/
-void input_GatherPES( input_thread_t * p_input, data_packet_t * p_data,
- es_descriptor_t * p_es,
- vlc_bool_t b_unit_start, vlc_bool_t b_packet_lost )
-{
-#define p_pes (p_es->p_pes)
-
- /* If we lost data, insert a NULL data packet (philosophy : 0 is quite
- * often an escape sequence in decoders, so that should make them wait
- * for the next start code). */
- if( b_packet_lost )
- {
- input_NullPacket( p_input, p_es );
- }
-
- if( b_unit_start && p_pes != NULL )
- {
- /* If the data packet contains the begining of a new PES packet, and
- * if we were reassembling a PES packet, then the PES should be
- * complete now, so parse its header and give it to the decoders. */
- input_ParsePES( p_input, p_es );
- }
-
- if( !b_unit_start && p_pes == NULL )
- {
- /* Random access... */
- input_DeletePacket( p_input->p_method_data, p_data );
- }
- else
- {
- if( b_unit_start )
- {
- /* If we are at the beginning of a new PES packet, we must fetch
- * a new PES buffer to begin with the reassembly of this PES
- * packet. This is also here that we can synchronize with the
- * stream if we lost packets or if the decoder has just
- * started. */
- if( (p_pes = input_NewPES( p_input->p_method_data ) ) == NULL )
- {
- msg_Err( p_input, "out of memory" );
- p_input->b_error = 1;
- return;
- }
- p_pes->i_rate = p_input->stream.control.i_rate;
- p_pes->p_first = p_data;
-
- /* If the PES header fits in the first data packet, we can
- * already set p_gather->i_pes_real_size. */
- if( p_data->p_payload_end - p_data->p_payload_start
- >= PES_HEADER_SIZE )
- {
- p_es->i_pes_real_size = ((u16)p_data->p_payload_start[4] << 8)
- + p_data->p_payload_start[5] + 6;
- }
- else
- {
- p_es->i_pes_real_size = 0;
- }
- }
- else
- {
- /* Update the relations between the data packets */
- p_pes->p_last->p_next = p_data;
- }
-
- p_pes->p_last = p_data;
- p_pes->i_nb_data++;
-
- /* Size of the payload carried in the data packet */
- p_pes->i_pes_size += (p_data->p_payload_end
- - p_data->p_payload_start);
-
- /* We can check if the packet is finished */
- if( p_pes->i_pes_size == p_es->i_pes_real_size )
- {
- /* The packet is finished, parse it */
- input_ParsePES( p_input, p_es );
- }
- }
-#undef p_pes
-}
-
-
-/*
- * PS Demultiplexing
- */
-
-/*****************************************************************************
- * GetID: Get the ID of a stream
- *****************************************************************************/
-static u16 GetID( data_packet_t * p_data )
-{
- u16 i_id;
-
- i_id = p_data->p_demux_start[3]; /* stream_id */
- if( i_id == 0xBD )
- {
- /* FIXME : this is not valid if the header is split in multiple
- * packets */
- /* stream_private_id */
- i_id |= p_data->p_demux_start[ 9 + p_data->p_demux_start[8] ] << 8;
- }
- return( i_id );
-}
-
-/*****************************************************************************
- * DecodePSM: Decode the Program Stream Map information
- *****************************************************************************
- * FIXME : loads are not aligned in this function
- *****************************************************************************/
-static void DecodePSM( input_thread_t * p_input, data_packet_t * p_data )
-{
- stream_ps_data_t * p_demux =
- (stream_ps_data_t *)p_input->stream.p_demux_data;
- byte_t * p_byte;
- byte_t * p_end;
- int i;
- int i_new_es_number = 0;
-
- if( p_data->p_demux_start + 10 > p_data->p_payload_end )
- {
- msg_Err( p_input, "PSM too short, packet corrupt" );
- return;
- }
-
- if( p_demux->b_has_PSM
- && p_demux->i_PSM_version == (p_data->p_demux_start[6] & 0x1F) )
- {
- /* Already got that one. */
- return;
- }
-
- p_demux->b_has_PSM = 1;
- p_demux->i_PSM_version = p_data->p_demux_start[6] & 0x1F;
-
- /* Go to elementary_stream_map_length, jumping over
- * program_stream_info. */
- p_byte = p_data->p_demux_start + 10
- + U16_AT(&p_data->p_demux_start[8]);
- if( p_byte > p_data->p_payload_end )
- {
- msg_Err( p_input, "PSM too short, packet corrupt" );
- return;
- }
- /* This is the full size of the elementary_stream_map.
- * 2 == elementary_stream_map_length
- * Please note that CRC_32 is not included in the length. */
- p_end = p_byte + 2 + U16_AT(p_byte);
- p_byte += 2;
- if( p_end > p_data->p_payload_end )
- {
- msg_Err( p_input, "PSM too short, packet corrupt" );
- return;
- }
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- /* 4 == minimum useful size of a section */
- while( p_byte + 4 <= p_end )
- {
- es_descriptor_t * p_es = NULL;
- u8 i_stream_id = p_byte[1];
- /* FIXME: there will be a problem with private streams... (same
- * stream_id) */
-
- /* Look for the ES in the ES table */
- for( i = i_new_es_number;
- i < p_input->stream.pp_programs[0]->i_es_number;
- i++ )
- {
- if( p_input->stream.pp_programs[0]->pp_es[i]->i_stream_id
- == i_stream_id )
- {
- p_es = p_input->stream.pp_programs[0]->pp_es[i];
- /* FIXME: do something below */
-#if 0
- if( p_es->i_type != p_byte[0] )
- {
- input_DelES( p_input, p_es );
- p_es = NULL;
- }
- else
-#endif
- {
- /* Move the ES to the beginning. */
- p_input->stream.pp_programs[0]->pp_es[i]
- = p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ];
- p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ]
- = p_es;
- i_new_es_number++;
- }
- break;
- }
- }
-
- /* The goal is to have all the ES we have just read in the
- * beginning of the pp_es table, and all the others at the end,
- * so that we can close them more easily at the end. */
- if( p_es == NULL )
- {
- p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
- i_stream_id, 0 );
- switch( p_byte[0] )
- {
- case MPEG1_VIDEO_ES:
- case MPEG2_VIDEO_ES:
- p_es->i_fourcc = VLC_FOURCC('m','p','g','v');
- p_es->i_cat = VIDEO_ES;
- break;
- case DVD_SPU_ES:
- p_es->i_fourcc = VLC_FOURCC('s','p','u',' ');
- p_es->i_cat = SPU_ES;
- break;
- case MPEG1_AUDIO_ES:
- case MPEG2_AUDIO_ES:
- p_es->i_fourcc = VLC_FOURCC('m','p','g','a');
- p_es->i_cat = AUDIO_ES;
- break;
- case A52_AUDIO_ES:
- p_es->i_fourcc = VLC_FOURCC('a','5','2',' ');
- p_es->i_cat = AUDIO_ES;
- break;
- case LPCM_AUDIO_ES:
- p_es->i_fourcc = VLC_FOURCC('l','p','c','m');
- p_es->i_cat = AUDIO_ES;
- break;
- default:
- p_es->i_fourcc = 0;
- break;
- }
-
- /* input_AddES has inserted the new element at the end. */
- p_input->stream.pp_programs[0]->pp_es[
- p_input->stream.pp_programs[0]->i_es_number ]
- = p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ];
- p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ] = p_es;
- i_new_es_number++;
- }
- p_byte += 4 + U16_AT(&p_byte[2]);
- }
-
- /* Un-select the streams that are no longer parts of the program. */
- while( i_new_es_number < p_input->stream.pp_programs[0]->i_es_number )
- {
- /* We remove pp_es[i_new_es_member] and not pp_es[i] because the
- * list will be emptied starting from the end */
- input_DelES( p_input,
- p_input->stream.pp_programs[0]->pp_es[i_new_es_number] );
- }
-
- msg_Dbg( p_input, "the stream map after the PSM is now:" );
- input_DumpStream( p_input );
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-}
-
-/*****************************************************************************
- * input_ReadPS: store a PS packet into a data_buffer_t
- *****************************************************************************/
-#define PEEK( SIZE ) \
- i_error = input_Peek( p_input, &p_peek, SIZE ); \
- if( i_error == -1 ) \
- { \
- return( -1 ); \
- } \
- else if( i_error < SIZE ) \
- { \
- /* EOF */ \
- return( 0 ); \
- }
-
-ssize_t input_ReadPS( input_thread_t * p_input, data_packet_t ** pp_data )
-{
- byte_t * p_peek;
- size_t i_packet_size;
- ssize_t i_error, i_read;
-
- /* Read what we believe to be a packet header. */
- PEEK( 4 );
-
- if( p_peek[0] || p_peek[1] || p_peek[2] != 1 || p_peek[3] < 0xB9 )
- {
- if( p_peek[0] || p_peek[1] || p_peek[2] )
- {
- /* It is common for MPEG-1 streams to pad with zeros
- * (although it is forbidden by the recommendation), so
- * don't bother everybody in this case. */
- msg_Warn( p_input, "garbage (0x%.2x%.2x%.2x%.2x)",
- p_peek[0], p_peek[1], p_peek[2], p_peek[3] );
- }
-
- /* This is not the startcode of a packet. Read the stream
- * until we find one. */
- while( p_peek[0] || p_peek[1] || p_peek[2] != 1 || p_peek[3] < 0xB9 )
- {
- p_input->p_current_data++;
- PEEK( 4 );
- if( p_input->b_die ) return( -1 );
- }
- /* Packet found. */
- }
-
- /* 0x1B9 == SYSTEM_END_CODE, it is only 4 bytes long. */
- if( p_peek[3] != 0xB9 )
- {
- /* The packet is at least 6 bytes long. */
- PEEK( 6 );
-
- if( p_peek[3] != 0xBA )
- {
- /* That's the case for all packets, except pack header. */
- i_packet_size = (p_peek[4] << 8) | p_peek[5];
- }
- else
- {
- /* Pack header. */
- if( (p_peek[4] & 0xC0) == 0x40 )
- {
- /* MPEG-2 */
- i_packet_size = 8;
- }
- else if( (p_peek[4] & 0xF0) == 0x20 )
- {
- /* MPEG-1 */
- i_packet_size = 6;
- }
- else
- {
- msg_Err( p_input, "unable to determine stream type" );
- return( -1 );
- }
- }
- }
- else
- {
- /* System End Code */
- i_packet_size = -2;
- }
-
- /* Fetch a packet of the appropriate size. */
- i_read = input_SplitBuffer( p_input, pp_data, i_packet_size + 6 );
- if( i_read <= 0 )
- {
- return( i_read );
- }
-
- /* In MPEG-2 pack headers we still have to read stuffing bytes. */
- if( ((*pp_data)->p_demux_start[3] == 0xBA) && (i_packet_size == 8) )
- {
- size_t i_stuffing = ((*pp_data)->p_demux_start[13] & 0x7);
- /* Force refill of the input buffer - though we don't care
- * about p_peek. Please note that this is unoptimized. */
- PEEK( i_stuffing );
- p_input->p_current_data += i_stuffing;
- }
-
- return( 1 );
-}
-
-#undef PEEK
-
-/*****************************************************************************
- * input_ParsePS: read the PS header
- *****************************************************************************/
-es_descriptor_t * input_ParsePS( input_thread_t * p_input,
- data_packet_t * p_data )
-{
- u32 i_code;
- es_descriptor_t * p_es = NULL;
-
- i_code = p_data->p_demux_start[3];
-
- if( i_code > 0xBC ) /* ES start code */
- {
- u16 i_id;
- int i_dummy;
-
- /* This is a PES packet. Find out if we want it or not. */
- i_id = GetID( p_data );
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
- if( p_input->stream.pp_programs[0]->b_is_ok )
- {
- /* Look only at the selected ES. */
- for( i_dummy = 0; i_dummy < p_input->stream.i_selected_es_number;
- i_dummy++ )
- {
- if( p_input->stream.pp_selected_es[i_dummy] != NULL
- && p_input->stream.pp_selected_es[i_dummy]->i_id == i_id )
- {
- p_es = p_input->stream.pp_selected_es[i_dummy];
- break;
- }
- }
- }
- else
- {
- stream_ps_data_t * p_demux =
- (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
-
- /* Search all ES ; if not found -> AddES */
- p_es = input_FindES( p_input, i_id );
-
- if( p_es == NULL && !p_demux->b_has_PSM )
- {
- p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
- i_id, 0 );
- if( p_es != NULL )
- {
- p_es->i_stream_id = p_data->p_demux_start[3];
-
- /* Set stream type and auto-spawn. */
- if( (i_id & 0xF0) == 0xE0 )
- {
- /* MPEG video */
- p_es->i_fourcc = VLC_FOURCC('m','p','g','v');
- p_es->i_cat = VIDEO_ES;
-#ifdef AUTO_SPAWN
- if( !p_input->stream.b_seekable )
- input_SelectES( p_input, p_es );
-#endif
- }
- else if( (i_id & 0xE0) == 0xC0 )
- {
- /* MPEG audio */
- p_es->i_fourcc = VLC_FOURCC('m','p','g','a');
- p_es->i_cat = AUDIO_ES;
-#ifdef AUTO_SPAWN
- if( !p_input->stream.b_seekable )
- if( config_GetInt( p_input, "audio-channel" )
- == (p_es->i_id & 0x1F) ||
- ( config_GetInt( p_input, "audio-channel" ) < 0
- && !(p_es->i_id & 0x1F) ) )
- switch( config_GetInt( p_input, "audio-type" ) )
- {
- case -1:
- case REQUESTED_MPEG:
- input_SelectES( p_input, p_es );
- }
-#endif
- }
- else if( (i_id & 0xF0FF) == 0x80BD )
- {
- /* A52 audio (0x80->0x8F) */
- p_es->i_fourcc = VLC_FOURCC('a','5','2',' ');
- p_es->i_cat = AUDIO_ES;
-#ifdef AUTO_SPAWN
- if( !p_input->stream.b_seekable )
- if( config_GetInt( p_input, "audio-channel" )
- == ((p_es->i_id & 0xF00) >> 8) ||
- ( config_GetInt( p_input, "audio-channel" ) < 0
- && !((p_es->i_id & 0xF00) >> 8)) )
- switch( config_GetInt( p_input, "audio-type" ) )
- {
- case -1:
- case REQUESTED_A52:
- input_SelectES( p_input, p_es );
- }
-#endif
- }
- else if( (i_id & 0xE0FF) == 0x20BD )
- {
- /* Subtitles video (0x20->0x3F) */
- p_es->i_fourcc = VLC_FOURCC('s','p','u',' ');
- p_es->i_cat = SPU_ES;
-#ifdef AUTO_SPAWN
- if( config_GetInt( p_input, "spu-channel" )
- == ((p_es->i_id & 0x1F00) >> 8) )
- {
- if( !p_input->stream.b_seekable )
- input_SelectES( p_input, p_es );
- }
-#endif
- }
- else if( (i_id & 0xF0FF) == 0xA0BD )
- {
- /* LPCM audio (0xA0->0xAF) */
- p_es->i_fourcc = VLC_FOURCC('l','p','c','m');
- p_es->i_cat = AUDIO_ES;
- }
- else
- {
- p_es->i_fourcc = 0;
- }
- }
-
- /* Tell the interface the stream has changed */
- p_input->stream.b_changed = 1;
- }
- } /* stream.b_is_ok */
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- } /* i_code > 0xBC */
-
- return( p_es );
-}
-
-/*****************************************************************************
- * input_DemuxPS: first step of demultiplexing: the PS header
- *****************************************************************************/
-void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
-{
- u32 i_code;
- vlc_bool_t b_trash = 0;
- es_descriptor_t * p_es = NULL;
-
- i_code = ((u32)p_data->p_demux_start[0] << 24)
- | ((u32)p_data->p_demux_start[1] << 16)
- | ((u32)p_data->p_demux_start[2] << 8)
- | p_data->p_demux_start[3];
- if( i_code <= 0x1BC )
- {
- switch( i_code )
- {
- case 0x1BA: /* PACK_START_CODE */
- {
- /* Read the SCR. */
- mtime_t scr_time;
- u32 i_mux_rate;
-
- if( (p_data->p_demux_start[4] & 0xC0) == 0x40 )
- {
- /* MPEG-2 */
- byte_t p_header[14];
- byte_t * p_byte;
- p_byte = p_data->p_demux_start;
-
- if( MoveChunk( p_header, &p_data, &p_byte, 14 ) != 14 )
- {
- msg_Warn( p_input,
- "packet too short to have a header" );
- b_trash = 1;
- break;
- }
- scr_time =
- ((mtime_t)(p_header[4] & 0x38) << 27) |
- ((mtime_t)(U32_AT(p_header + 4) & 0x03FFF800)
- << 4) |
- ((( ((mtime_t)U16_AT(p_header + 6) << 16)
- | (mtime_t)U16_AT(p_header + 8) ) & 0x03FFF800)
- >> 11);
-
- /* mux_rate */
- i_mux_rate = ((u32)U16_AT(p_header + 10) << 6)
- | (p_header[12] >> 2);
- /* FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
- * This is the biggest kludge ever !
- * I don't know what's wrong with mux_rate calculation
- * but this heuristic works well : */
- i_mux_rate <<= 1;
- i_mux_rate /= 3;
- }
- else
- {
- /* MPEG-1 SCR is like PTS. */
- byte_t p_header[12];
- byte_t * p_byte;
- p_byte = p_data->p_demux_start;
-
- if( MoveChunk( p_header, &p_data, &p_byte, 12 ) != 12 )
- {
- msg_Warn( p_input,
- "packet too short to have a header" );
- b_trash = 1;
- break;
- }
- scr_time =
- ((mtime_t)(p_header[4] & 0x0E) << 29) |
- (((mtime_t)U32_AT(p_header + 4) & 0xFFFE00) << 6) |
- ((mtime_t)p_header[7] << 7) |
- ((mtime_t)p_header[8] >> 1);
-
- /* mux_rate */
- i_mux_rate = (U32_AT(p_header + 8) & 0x7FFFFE) >> 1;
- }
- /* Call the pace control. */
- input_ClockManageRef( p_input,
- p_input->stream.p_selected_program,
- scr_time );
-
- if( i_mux_rate != p_input->stream.i_mux_rate
- && p_input->stream.i_mux_rate )
- {
- msg_Warn( p_input,
- "mux_rate changed, expect cosmetic errors" );
- }
- p_input->stream.i_mux_rate = i_mux_rate;
-
- b_trash = 1;
- }
- break;
-
- case 0x1BB: /* SYSTEM_START_CODE */
- b_trash = 1; /* Nothing interesting */
- break;
-
- case 0x1BC: /* PROGRAM_STREAM_MAP_CODE */
- DecodePSM( p_input, p_data );
- b_trash = 1;
- break;
-
- case 0x1B9: /* PROGRAM_END_CODE */
- b_trash = 1;
- break;
-
- default:
- /* This should not happen */
- b_trash = 1;
- msg_Warn( p_input, "unwanted packet received "
- "with startcode 0x%.8x", i_code );
- }
- }
- else
- {
- p_es = input_ParsePS( p_input, p_data );
-
- vlc_mutex_lock( &p_input->stream.control.control_lock );
- if( p_es != NULL && p_es->p_decoder_fifo != NULL
- && (p_es->i_cat != AUDIO_ES || !p_input->stream.control.b_mute) )
- {
- vlc_mutex_unlock( &p_input->stream.control.control_lock );
- p_es->c_packets++;
- input_GatherPES( p_input, p_data, p_es, 1, 0 );
- }
- else
- {
- vlc_mutex_unlock( &p_input->stream.control.control_lock );
- b_trash = 1;
- }
- }
-
- /* Trash the packet if it has no payload or if it isn't selected */
- if( b_trash )
- {
- input_DeletePacket( p_input->p_method_data, p_data );
- p_input->stream.c_packets_trashed++;
- }
-}
-
-
-/*
- * TS Demultiplexing
- */
-
-/*****************************************************************************
- * input_ReadTS: store a TS packet into a data_buffer_t
- *****************************************************************************/
-#define PEEK( SIZE ) \
- i_error = input_Peek( p_input, &p_peek, SIZE ); \
- if( i_error == -1 ) \
- { \
- return( -1 ); \
- } \
- else if( i_error < SIZE ) \
- { \
- /* EOF */ \
- return( 0 ); \
- }
-
-ssize_t input_ReadTS( input_thread_t * p_input, data_packet_t ** pp_data )
-{
- byte_t * p_peek;
- ssize_t i_error, i_read;
-
- PEEK( 1 );
-
- if( *p_peek != TS_SYNC_CODE )
- {
- msg_Warn( p_input, "garbage at input (%x)", *p_peek );
-
- if( p_input->i_mtu )
- {
- while( *p_peek != TS_SYNC_CODE )
- {
- /* Try to resync on next packet. */
- PEEK( TS_PACKET_SIZE );
- p_input->p_current_data += TS_PACKET_SIZE;
- PEEK( 1 );
- }
- }
- else
- {
- /* Move forward until we find 0x47 (and hope it's the good
- * one... FIXME) */
- while( *p_peek != TS_SYNC_CODE )
- {
- p_input->p_current_data++;
- PEEK( 1 );
- }
- }
- }
-
- i_read = input_SplitBuffer( p_input, pp_data, TS_PACKET_SIZE );
- if( i_read <= 0 )
- {
- return( i_read );
- }
-
- return( 1 );
-}
-
-/*****************************************************************************
- * input_DemuxTS: first step of demultiplexing: the TS header
- *****************************************************************************/
-void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
- psi_callback_t pf_psi_callback )
-{
- u16 i_pid;
- int i_dummy;
- vlc_bool_t b_adaptation; /* Adaptation field is present */
- vlc_bool_t b_payload; /* Packet carries payload */
- vlc_bool_t b_unit_start; /* A PSI or a PES start in the packet */
- vlc_bool_t b_trash = 0; /* Is the packet unuseful ? */
- vlc_bool_t b_lost = 0; /* Was there a packet loss ? */
- vlc_bool_t b_psi = 0; /* Is this a PSI ? */
- vlc_bool_t b_pcr = 0; /* Does it have a PCR ? */
- es_descriptor_t * p_es = NULL;
- es_ts_data_t * p_es_demux = NULL;
- pgrm_ts_data_t * p_pgrm_demux = NULL;
-
-#define p (p_data->p_demux_start)
- /* Extract flags values from TS common header. */
- i_pid = ((p[1] & 0x1F) << 8) | p[2];
- b_unit_start = (p[1] & 0x40);
- b_adaptation = (p[3] & 0x20);
- b_payload = (p[3] & 0x10);
-
- /* Find out the elementary stream. */
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- for( i_dummy = 0; i_dummy < p_input->stream.i_pgrm_number; i_dummy ++ )
- {
- if( (( pgrm_ts_data_t * ) p_input->stream.pp_programs[i_dummy]->
- p_demux_data)->i_pcr_pid == i_pid )
- {
- b_pcr = 1;
- break;
- }
- }
-
- p_es= input_FindES( p_input, i_pid );
-
- if( (p_es != NULL) && (p_es->p_demux_data != NULL) )
- {
- p_es_demux = (es_ts_data_t *)p_es->p_demux_data;
-
- if( p_es_demux->b_psi )
- {
- b_psi = 1;
- }
- else
- {
- p_pgrm_demux = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data;
- }
- }
-
- vlc_mutex_lock( &p_input->stream.control.control_lock );
- if( ( p_es == NULL ) || (p_es->i_cat == AUDIO_ES
- && p_input->stream.control.b_mute) )
- {
- /* Not selected. Just read the adaptation field for a PCR. */
- b_trash = 1;
- }
- else if( p_es->p_decoder_fifo == NULL && !b_psi )
- {
- b_trash = 1;
- }
-
- vlc_mutex_unlock( &p_input->stream.control.control_lock );
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-
- /* Don't change the order of the tests : if b_psi then p_pgrm_demux
- * may still be null. Who said it was ugly ?
- * I have written worse. --Meuuh */
- if( ( p_es ) &&
- ((p_es->p_decoder_fifo != NULL) || b_psi || b_pcr ) )
- {
- p_es->c_packets++;
-
- /* Extract adaptation field information if any */
-
- if( !b_adaptation )
- {
- /* We don't have any adaptation_field, so payload starts
- * immediately after the 4 byte TS header */
- p_data->p_payload_start += 4;
- }
- else
- {
- /* p[4] is adaptation_field_length minus one */
- p_data->p_payload_start += 5 + p[4];
-
- /* The adaptation field can be limited to the
- * adaptation_field_length byte, so that there is nothing to do:
- * skip this possibility */
- if( p[4] )
- {
- /* If the packet has both adaptation_field and payload,
- * adaptation_field cannot be more than 182 bytes long; if
- * there is only an adaptation_field, it must fill the next
- * 183 bytes. */
- if( b_payload ? (p[4] > 182) : (p[4] != 183) )
- {
- msg_Warn( p_input, "invalid TS adaptation field (%p)",
- p_data );
- p_data->b_discard_payload = 1;
- p_es->c_invalid_packets++;
- }
-
- /* Now we are sure that the byte containing flags is present:
- * read it */
- else
- {
- /* discontinuity_indicator */
- if( p[5] & 0x80 )
- {
- msg_Warn( p_input,
- "discontinuity_indicator encountered by TS demux "
- "(position read: %d, saved: %d)",
- p[5] & 0x80, p_es_demux->i_continuity_counter );
-
- /* If the PID carries the PCR, there will be a system
- * time-based discontinuity. We let the PCR decoder
- * handle that. */
- p_es->p_pgrm->i_synchro_state = SYNCHRO_REINIT;
-
- /* There also may be a continuity_counter
- * discontinuity: resynchronize our counter with
- * the one of the stream. */
- p_es_demux->i_continuity_counter = (p[3] & 0x0f) - 1;
- }
-
- } /* valid TS adaptation field ? */
- } /* length > 0 */
- } /* has adaptation field */
- /* Check the continuity of the stream. */
- i_dummy = ((p[3] & 0x0f) - p_es_demux->i_continuity_counter) & 0x0f;
- if( i_dummy == 1 )
- {
- /* Everything is ok, just increase our counter */
- (p_es_demux->i_continuity_counter)++;
- }
- else
- {
- if( !b_payload && i_dummy == 0 )
- {
- /* This is a packet without payload, this is allowed by the
- * draft. As there is nothing interesting in this packet
- * (except PCR that have already been handled), we can trash
- * the packet. */
- b_trash = 1;
- }
- else if( i_dummy <= 0 )
- {
- /* Duplicate packet: mark it as being to be trashed. */
- msg_Warn( p_input,
- "duplicate packet received by TS demux" );
- b_trash = 1;
- }
- else if( p_es_demux->i_continuity_counter == 0xFF )
- {
- /* This means that the packet is the first one we receive for
- * this ES since the continuity counter ranges between 0 and
- * 0x0F excepts when it has been initialized by the input:
- * init the counter to the correct value. */
- msg_Warn( p_input, "first packet for PID %d received "
- "by TS demux", p_es->i_id );
- p_es_demux->i_continuity_counter = (p[3] & 0x0f);
- }
- else
- {
- /* This can indicate that we missed a packet or that the
- * continuity_counter wrapped and we received a dup packet:
- * as we don't know, do as if we missed a packet to be sure
- * to recover from this situation */
- msg_Warn( p_input,
- "packet lost by TS demux: current %d, packet %d",
- p_es_demux->i_continuity_counter & 0x0f,
- p[3] & 0x0f );
- b_lost = 1;
- p_es_demux->i_continuity_counter = p[3] & 0x0f;
- } /* not continuous */
- } /* continuity */
- } /* if selected or PCR */
-
- /* Handle PCR */
- if( b_pcr && b_adaptation && (p[5] & 0x10) && p[4]>=7 )
- {
- /* Read the PCR. */
- mtime_t pcr_time;
- pcr_time = ( (mtime_t)p[6] << 25 ) |
- ( (mtime_t)p[7] << 17 ) |
- ( (mtime_t)p[8] << 9 ) |
- ( (mtime_t)p[9] << 1 ) |
- ( (mtime_t)p[10] >> 7 );
- /* Call the pace control. */
- for( i_dummy = 0; i_dummy < p_input->stream.i_pgrm_number;
- i_dummy ++ )
- {
- if( ( ( pgrm_ts_data_t * ) p_input->stream.pp_programs[i_dummy]->
- p_demux_data )->i_pcr_pid == i_pid )
- {
- input_ClockManageRef( p_input,
- p_input->stream.pp_programs[i_dummy], pcr_time );
- }
- }
-
- }
-
- /* Trash the packet if it has no payload or if it isn't selected */
- if( b_trash )
- {
- input_DeletePacket( p_input->p_method_data, p_data );
- p_input->stream.c_packets_trashed++;
- }
- else
- {
- if( b_psi )
- {
- /* The payload contains PSI tables */
- (* pf_psi_callback) ( p_input, p_data, p_es, b_unit_start );
- }
- else
- {
- /* The payload carries a PES stream */
- input_GatherPES( p_input, p_data, p_es, b_unit_start, b_lost );
- }
-
- }
-
-#undef p
-
-}
* configuration.c management of the modules configuration
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: configuration.c,v 1.33 2002/07/31 20:56:53 sam Exp $
+ * $Id: configuration.c,v 1.34 2002/08/07 00:29:37 sam Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
!memcmp( &line[1], p_module->psz_object_name,
strlen(p_module->psz_object_name) ) )
{
- msg_Dbg( p_this, "loading config for module \"%s\"",
- p_module->psz_object_name );
+ //msg_Dbg( p_this, "loading config for module \"%s\"",
+ // p_module->psz_object_name );
break;
}
if( !*psz_option_value )
break; /* ignore empty option */
p_item->i_value = atoi( psz_option_value);
- msg_Dbg( p_this, "option \"%s\", value %i",
- p_item->psz_name, p_item->i_value );
+ //msg_Dbg( p_this, "option \"%s\", value %i",
+ // p_item->psz_name, p_item->i_value );
break;
case CONFIG_ITEM_FLOAT:
if( !*psz_option_value )
break; /* ignore empty option */
p_item->f_value = (float)atof( psz_option_value);
- msg_Dbg( p_this, "option \"%s\", value %f",
- p_item->psz_name, (double)p_item->f_value );
+ //msg_Dbg( p_this, "option \"%s\", value %f",
+ // p_item->psz_name, (double)p_item->f_value );
break;
default:
vlc_mutex_unlock( p_item->p_lock );
- msg_Dbg( p_this, "option \"%s\", value \"%s\"",
- p_item->psz_name,
- p_item->psz_value ? p_item->psz_value : "" );
+ //msg_Dbg( p_this, "option \"%s\", value \"%s\"",
+ // p_item->psz_name,
+ // p_item->psz_value ? p_item->psz_value : "" );
break;
}
}
* modules.c : Builtin and plugin modules management functions
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: modules.c,v 1.80 2002/08/06 00:26:48 sam Exp $
+ * $Id: modules.c,v 1.81 2002/08/07 00:29:37 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Ethan C. Baldridge <BaldridgeE@cadmus.com>
*****************************************************************************/
#ifdef HAVE_DYNAMIC_PLUGINS
static void AllocateAllPlugins ( vlc_object_t * );
-static void AllocatePluginDir ( vlc_object_t *, const char * );
+static void AllocatePluginDir ( vlc_object_t *, const char *, int );
static int AllocatePluginFile ( vlc_object_t *, char * );
#endif
static int AllocateBuiltinModule( vlc_object_t *, int ( * ) ( module_t * ) );
msg_Dbg( p_this, "recursively browsing `%s'", psz_fullpath );
- AllocatePluginDir( p_this, psz_fullpath );
+ /* Don't go deeper than 5 subdirectories */
+ AllocatePluginDir( p_this, psz_fullpath, 5 );
#if defined( SYS_BEOS ) || defined( SYS_DARWIN )
if( b_notinroot )
/*****************************************************************************
* AllocatePluginDir: recursively parse a directory to look for plugins
*****************************************************************************/
-static void AllocatePluginDir( vlc_object_t *p_this, const char *psz_dir )
+static void AllocatePluginDir( vlc_object_t *p_this, const char *psz_dir,
+ int i_maxdepth )
{
#define PLUGIN_EXT ".so"
int i_dirlen;
struct dirent * file;
+ if( i_maxdepth < 0 )
+ {
+ return;
+ }
+
dir = opendir( psz_dir );
if( !dir )
if( !stat( psz_file, &statbuf ) && statbuf.st_mode & S_IFDIR )
{
- AllocatePluginDir( p_this, psz_file );
+ AllocatePluginDir( p_this, psz_file, i_maxdepth - 1 );
}
else if( i_len > strlen( PLUGIN_EXT )
/* We only load files ending with ".so" */
p_this->p_vlc->p_module_bank->first = p_module;
p_this->p_vlc->p_module_bank->i_count++;
- msg_Dbg( p_this, "plugin \"%s\", %s",
- p_module->psz_object_name, p_module->psz_longname );
+ //msg_Dbg( p_this, "plugin \"%s\", %s",
+ // p_module->psz_object_name, p_module->psz_longname );
vlc_object_attach( p_module, p_this->p_vlc->p_module_bank );
p_this->p_vlc->p_module_bank->first = p_module;
p_this->p_vlc->p_module_bank->i_count++;
- msg_Dbg( p_this, "builtin \"%s\", %s",
- p_module->psz_object_name, p_module->psz_longname );
+ //msg_Dbg( p_this, "builtin \"%s\", %s",
+ // p_module->psz_object_name, p_module->psz_longname );
vlc_object_attach( p_module, p_this->p_vlc->p_module_bank );
(p_symbols)->input_AccessInit_inner = input_AccessInit; \
(p_symbols)->input_AccessReinit_inner = input_AccessReinit; \
(p_symbols)->input_AccessEnd_inner = input_AccessEnd; \
- (p_symbols)->input_ParsePES_inner = input_ParsePES; \
- (p_symbols)->input_GatherPES_inner = input_GatherPES; \
- (p_symbols)->input_ReadPS_inner = input_ReadPS; \
- (p_symbols)->input_ParsePS_inner = input_ParsePS; \
- (p_symbols)->input_ReadTS_inner = input_ReadTS; \
- (p_symbols)->input_DemuxPS_inner = input_DemuxPS; \
- (p_symbols)->input_DemuxTS_inner = input_DemuxTS; \
(p_symbols)->__input_FDClose_inner = __input_FDClose; \
(p_symbols)->__input_FDNetworkClose_inner = __input_FDNetworkClose; \
(p_symbols)->input_FDRead_inner = input_FDRead; \