CFLAGS += -O6
CFLAGS += -ffast-math -funroll-loops -fargument-noalias-global
CFLAGS += -funroll-all-loops -fstrict-aliasing
-CFLAGS += -fomit-frame-pointer
+#CFLAGS += -fomit-frame-pointer
# Optimizations for x86 familiy
ifneq (,$(findstring 86,$(ARCH)))
interface/intf_ctrl.o \
interface/intf_console.o
-input_obj = input/input_vlan.o \
- input/input_file.o \
- input/input_netlist.o \
- input/input_network.o \
- input/input_ctrl.o \
- input/input_pcr.o \
- input/input_psi.o \
+input_obj = input/input_ps.o \
+ input/mpeg_system.o \
+ input/input_ext-dec.o \
input/input.o
audio_output_obj = audio_output/audio_output.o
misc/rsc_files.o \
misc/netutils.o \
misc/playlist.o \
- misc/plugins.o \
- misc/decoder_fifo.o
+ misc/plugins.o
C_OBJ = $(interface_obj) \
/* Duration between the time we receive the TS packet, and the time we will
* mark it to be presented */
-#define INPUT_PTS_DELAY (.5*CLOCK_FREQ)
+#define DEFAULT_PTS_DELAY (.5*CLOCK_FREQ)
#define INPUT_DVD_AUDIO_VAR "vlc_dvd_audio"
#define INPUT_DVD_CHANNEL_VAR "vlc_dvd_channel"
+++ /dev/null
-/*****************************************************************************
- * decoder_fifo.h: interface for decoders PES fifo
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * Authors: Michel Kaempf <maxx@via.ecp.fr>
- * Christophe Massiot <massiot@via.ecp.fr>
- * Michel Lespinasse <walken@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.
- *****************************************************************************/
-
-/*****************************************************************************
- * Required headers:
- * - "config.h"
- * - "common.h"
- * - "threads.h"
- * - "input.h"
- *****************************************************************************/
-
-#define WORD_TYPE u32
-#define WORD_BYTE_LENGTH 4
-#define WORD_LENGTH 32
-
-/*****************************************************************************
- * Macros
- *****************************************************************************/
-
-/* FIXME: move to inline functions ??*/
-#define DECODER_FIFO_ISEMPTY( fifo ) ( (fifo).i_start == (fifo).i_end )
-#define DECODER_FIFO_ISFULL( fifo ) ( ( ((fifo).i_end + 1 - (fifo).i_start)\
- & FIFO_SIZE ) == 0 )
-#define DECODER_FIFO_START( fifo ) ( (fifo).buffer[ (fifo).i_start ] )
-#define DECODER_FIFO_INCSTART( fifo ) ( (fifo).i_start = ((fifo).i_start + 1)\
- & FIFO_SIZE )
-#define DECODER_FIFO_END( fifo ) ( (fifo).buffer[ (fifo).i_end ] )
-#define DECODER_FIFO_INCEND( fifo ) ( (fifo).i_end = ((fifo).i_end + 1) \
- & FIFO_SIZE )
-
-/*****************************************************************************
- * decoder_fifo_t
- *****************************************************************************
- * This rotative FIFO contains PES packets that are to be decoded...
- *****************************************************************************/
-typedef struct
-{
- vlc_mutex_t data_lock; /* fifo data lock */
- vlc_cond_t data_wait; /* fifo data conditional variable */
-
- /* buffer is an array of PES packets pointers */
- pes_packet_t * buffer[FIFO_SIZE + 1];
- int i_start;
- int i_end;
-
-} decoder_fifo_t;
-
-/*****************************************************************************
- * bit_fifo_t : bit fifo descriptor
- *****************************************************************************
- * This type describes a bit fifo used to store bits while working with the
- * input stream at the bit level.
- *****************************************************************************/
-typedef struct bit_fifo_s
-{
- /* This unsigned integer allows us to work at the bit level. This buffer
- * can contain 32 bits, and the used space can be found on the MSb's side
- * and the available space on the LSb's side. */
- WORD_TYPE buffer;
-
- /* Number of bits available in the bit buffer */
- int i_available;
-
-} bit_fifo_t;
-
-/*****************************************************************************
- * bit_stream_t : bit stream descriptor
- *****************************************************************************
- * This type, based on a PES stream, includes all the structures needed to
- * handle the input stream like a bit stream.
- *****************************************************************************/
-typedef struct bit_stream_s
-{
- /*
- * Input structures
- */
- /* The input thread feeds the stream with fresh PES packets */
- input_thread_t * p_input;
- /* The decoder fifo contains the data of the PES stream */
- decoder_fifo_t * p_decoder_fifo;
-
- /*
- * Byte structures
- */
- /* Current TS packet (in the current PES packet of the PES stream) */
- ts_packet_t * p_ts;
- /* Pointer to the next byte that is to be read (in the current TS packet) */
- byte_t * p_byte;
- /* Pointer to the last byte that is to be read (in the current TS packet */
- byte_t * p_end;
-
- /*
- * Bit structures
- */
- bit_fifo_t fifo;
-
-} bit_stream_t;
-
-
-void decoder_fifo_next( bit_stream_t * p_bit_stream );
-/*****************************************************************************
- * GetByte : reads the next byte in the input stream
- *****************************************************************************/
-static __inline__ byte_t GetByte( bit_stream_t * p_bit_stream )
-{
- /* Are there some bytes left in the current TS packet ? */
- /* could change this test to have a if (! (bytes--)) instead */
- if ( p_bit_stream->p_byte >= p_bit_stream->p_end )
- {
- /* no, switch to next TS packet */
- decoder_fifo_next( p_bit_stream );
- }
-
- return( *(p_bit_stream->p_byte++));
-}
-
-/*****************************************************************************
- * NeedBits : reads i_bits new bits in the bit stream and stores them in the
- * bit buffer
- *****************************************************************************
- * - i_bits must be less or equal 32 !
- * - There is something important to notice with that function : if the number
- * of bits available in the bit buffer when calling NeedBits() is greater than
- * 24 (i_available > 24) but less than the number of needed bits
- * (i_available < i_bits), the byte returned by GetByte() will be shifted with
- * a negative value and the number of bits available in the bit buffer will be
- * set to more than 32 !
- *****************************************************************************/
-static __inline__ void NeedBits( bit_stream_t * p_bit_stream, int i_bits )
-{
- while ( p_bit_stream->fifo.i_available < i_bits )
- {
- p_bit_stream->fifo.buffer |= ((u32)GetByte( p_bit_stream )) << (24 - p_bit_stream->fifo.i_available);
- p_bit_stream->fifo.i_available += 8;
- }
-}
-
-/*****************************************************************************
- * DumpBits : removes i_bits bits from the bit buffer
- *****************************************************************************
- * - i_bits <= i_available
- * - i_bits < 32 (because (u32 << 32) <=> (u32 = u32))
- *****************************************************************************/
-static __inline__ void DumpBits( bit_stream_t * p_bit_stream, int i_bits )
-{
- p_bit_stream->fifo.buffer <<= i_bits;
- p_bit_stream->fifo.i_available -= i_bits;
-}
-
-/*****************************************************************************
- * DumpBits32 : removes 32 bits from the bit buffer
- *****************************************************************************
- * This function actually believes that you have already put 32 bits in the
- * bit buffer, so you can't use it anytime.
- *****************************************************************************/
-static __inline__ void DumpBits32( bit_stream_t * p_bit_stream )
-{
- p_bit_stream->fifo.buffer = 0;
- p_bit_stream->fifo.i_available = 0;
-}
-
-/*
- * For the following functions, please read VERY CAREFULLY the warning in
- * NeedBits(). If i_bits > 24, the stream parser must be already aligned
- * on an 8-bit boundary, or you will get curious results (that is, you
- * need to call RealignBits() before).
- */
-
-void PeekNextPacket( bit_stream_t * p_bit_stream );
-
-//(stolen from the kernel)
-// XXX: The macro swab32 for little endian machine does
-// not seem to work correctly
-
-#if defined(SYS_BEOS)
-# define swab32(x) B_BENDIAN_TO_HOST_INT32(x)
-#else
-# if __BYTE_ORDER == __BIG_ENDIAN
-# define swab32(x) (x)
-# else
-# if defined (__i386__)
-# define swab32(x) __i386_swab32(x)
-static inline const u32 __i386_swab32(u32 x)
-{
- __asm__("bswap %0" : "=r" (x) : "0" (x));
- return x;
-}
-# else
-# define swab32(x)\
- ( ( (u32)(((u8*)&x)[0]) << 24 ) | ( (u32)(((u8*)&x)[1]) << 16 ) | \
- ( (u32)(((u8*)&x)[2]) << 8 ) | ( (u32)(((u8*)&x)[3])) )
-# endif
-# endif
-#endif
-
-
-static __inline__ WORD_TYPE GetWord( bit_stream_t * p_bit_stream )
-{
- if( p_bit_stream->p_byte <= p_bit_stream->p_end - WORD_BYTE_LENGTH )
- {
- return( swab32( *(((WORD_TYPE *)p_bit_stream->p_byte)++) ) );
- }
- else
- {
- PeekNextPacket( p_bit_stream );
- return( swab32( *(((WORD_TYPE *)p_bit_stream->p_byte)++) ) );
- }
-}
-
-/*****************************************************************************
- * RemoveBits : removes i_bits bits from the bit buffer
- *****************************************************************************/
-static __inline__ void RemoveBits( bit_stream_t * p_bit_stream, int i_bits )
-{
- p_bit_stream->fifo.i_available -= i_bits;
-
- if( p_bit_stream->fifo.i_available >= 0 )
- {
- p_bit_stream->fifo.buffer <<= i_bits;
- return;
- }
- p_bit_stream->fifo.buffer = GetWord( p_bit_stream )
- << ( -p_bit_stream->fifo.i_available );
- p_bit_stream->fifo.i_available += WORD_LENGTH;
-}
-
-/*****************************************************************************
- * RemoveBits32 : removes 32 bits from the bit buffer (and as a side effect,
- * refill it)
- *****************************************************************************/
-static __inline__ void RemoveBits32( bit_stream_t * p_bit_stream )
-{
- p_bit_stream->fifo.buffer = GetWord( p_bit_stream )
- << (32 - p_bit_stream->fifo.i_available);
-}
-
-/*****************************************************************************
- * ShowBits : return i_bits bits from the bit stream
- *****************************************************************************/
-static __inline__ WORD_TYPE ShowWord( bit_stream_t * p_bit_stream )
-{
- if( p_bit_stream->p_byte <= p_bit_stream->p_end - WORD_BYTE_LENGTH )
- {
- return( swab32( *((WORD_TYPE *)p_bit_stream->p_byte) ) );
- }
-
- PeekNextPacket( p_bit_stream );
- return( swab32( *((WORD_TYPE *)p_bit_stream->p_byte) ) );
-}
-
-static __inline__ u32 ShowBits( bit_stream_t * p_bit_stream, int i_bits )
-{
- if( p_bit_stream->fifo.i_available >= i_bits )
- {
- return( p_bit_stream->fifo.buffer >> (32 - i_bits) );
- }
-
- return( (p_bit_stream->fifo.buffer |
- (ShowWord( p_bit_stream ) >> p_bit_stream->fifo.i_available))
- >> (32 - i_bits) );
-}
-
-/*****************************************************************************
- * GetBits : returns i_bits bits from the bit stream and removes them
- *****************************************************************************/
-static __inline__ u32 GetBits( bit_stream_t * p_bit_stream, int i_bits )
-{
- u32 i_result;
-
- p_bit_stream->fifo.i_available -= i_bits;
- if( p_bit_stream->fifo.i_available >= 0 )
- {
- i_result = p_bit_stream->fifo.buffer >> (32 - i_bits);
- p_bit_stream->fifo.buffer <<= i_bits;
- return( i_result );
- }
-
- i_result = p_bit_stream->fifo.buffer >> (32 - i_bits);
- p_bit_stream->fifo.buffer = GetWord( p_bit_stream );
- i_result |= p_bit_stream->fifo.buffer
- >> (32 + p_bit_stream->fifo.i_available);
- p_bit_stream->fifo.buffer <<= ( -p_bit_stream->fifo.i_available );
- p_bit_stream->fifo.i_available += WORD_LENGTH;
-
- return( i_result );
-}
-
-/*****************************************************************************
- * GetBits32 : returns 32 bits from the bit stream and removes them
- *****************************************************************************/
-static __inline__ u32 GetBits32( bit_stream_t * p_bit_stream )
-{
- u32 i_result;
-
- i_result = p_bit_stream->fifo.buffer;
- p_bit_stream->fifo.buffer = GetWord( p_bit_stream );
- i_result |= p_bit_stream->fifo.buffer
- >> (p_bit_stream->fifo.i_available);
- p_bit_stream->fifo.buffer <<= (32 - p_bit_stream->fifo.i_available);
-
- return( i_result );
-}
-
-/*****************************************************************************
- * RealignBits : realigns the bit buffer on an 8-bit boundary
- *****************************************************************************/
-static __inline__ void RealignBits( bit_stream_t * p_bit_stream )
-{
- p_bit_stream->fifo.buffer <<= (p_bit_stream->fifo.i_available & 0x7);
- p_bit_stream->fifo.i_available &= ~0x7;
-}
-
+++ /dev/null
-/*****************************************************************************
- * input.h: input thread interface
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * Authors: Christophe Massiot <massiot@via.ecp.fr>
- * Vincent Seguin <seguin@via.ecp.fr>
- * Benoît Steiner <benny@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.
- *****************************************************************************/
-
-/*****************************************************************************
- * Constants related to input
- *****************************************************************************/
-#define TS_PACKET_SIZE 188 /* size of a TS packet */
-#define PES_HEADER_SIZE 14 /* size of the first part of a PES header */
-#define PSI_SECTION_SIZE 4096 /* Maximum size of a PSI section */
-
-/*****************************************************************************
- * ts_packet_t
- *****************************************************************************
- * Describe a TS packet.
- *****************************************************************************/
-typedef struct ts_packet_s
-{
- /* Nothing before this line, the code relies on that */
- byte_t buffer[TS_PACKET_SIZE]; /* raw TS data packet */
-
- /* Decoders information */
- unsigned int i_payload_start;
- /* start of the PES payload in this packet */
- unsigned int i_payload_end; /* guess ? :-) */
-
- /* Used to chain the TS packets that carry data for a same PES or PSI */
- struct ts_packet_s * p_prev_ts;
- struct ts_packet_s * p_next_ts;
-} ts_packet_t;
-
-/*****************************************************************************
- * pes_packet_t
- *****************************************************************************
- * Describes an PES packet, with its properties, and pointers to the TS packets
- * containing it.
- *****************************************************************************/
-typedef struct pes_packet_s
-{
- /* PES properties */
- boolean_t b_data_loss; /* The previous (at least) PES packet
- * has been lost. The decoders will have to find a way to recover. */
- boolean_t b_data_alignment; /* used to find the beginning of
- * a video or audio unit */
- boolean_t b_has_pts; /* is the following field set ? */
- mtime_t i_pts; /* the PTS for this packet (if set above) */
- boolean_t b_random_access;
- /* if TRUE, in the payload of this packet, there is the first byte
- * of a video sequence header, or the first byte of an audio frame.
- */
- u8 i_stream_id; /* payload type and id */
- int i_pes_size; /* size of the current PES packet */
- int i_pes_real_size; /* real size of the current
- * PES packet, ie. the one
- * announced in the header */
- int i_ts_packets;/* number of TS packets in this PES */
-
- /* Demultiplexer environment */
- boolean_t b_discard_payload; /* is the packet messed up ? */
- byte_t * p_pes_header; /* pointer to the PES header */
- byte_t * p_pes_header_save; /* temporary buffer */
-
- /* Pointers to TS packets (TS packets are then linked by the p_prev_ts and
- p_next_ts fields of the ts_packet_t struct) */
- ts_packet_t * p_first_ts; /* The first TS packet containing this
- * PES (used by decoders). */
- ts_packet_t * p_last_ts; /* The last TS packet gathered at present
- * (used by the demultiplexer). */
-} pes_packet_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_s
-{
- byte_t buffer[PSI_SECTION_SIZE];
-
- boolean_t b_running_section; /* Is there a section being decoded ? */
-
- u16 i_length;
- u16 i_current_position;
-} psi_section_t;
-
-
-/*****************************************************************************
- * es_descriptor_t: elementary stream descriptor
- *****************************************************************************
- * Describes an elementary stream, and includes fields required to handle and
- * demultiplex this elementary stream.
- *****************************************************************************/
-typedef struct es_descriptor_t
-{
- u16 i_id; /* stream ID, PID for TS streams */
- u8 i_type; /* stream type */
-
- boolean_t b_pcr; /* does the stream include a PCR ? */
- /* XXX?? b_pcr will be replaced by something else: since a PCR can't be shared
- * between several ES, we will probably store the PCR fields directly here,
- * and one of those fields will probably (again) be used as a test of the
- * PCR presence */
- boolean_t b_psi; /* does the stream have to be handled by the
- PSI decoder ? */
- /* Markers */
- int i_continuity_counter;
- boolean_t b_discontinuity;
- boolean_t b_random;
-
- /* PES packets */
- pes_packet_t * p_pes_packet;
- /* current PES packet we are gathering */
-
- /* PSI packets */
- psi_section_t * p_psi_section; /* idem for a PSI stream */
-
- /* Decoder informations */
- void * p_dec; /* p_dec is void *, since we don't know a
- * priori whether it is adec_thread_t or
- * vdec_thread_t. We will use explicit
- * casts. */
-
- /* XXX?? video stream descriptor ? */
- /* XXX?? audio stream descriptor ? */
- /* XXX?? hierarchy descriptor ? */
- /* XXX?? target background grid descriptor ? */
- /* XXX?? video window descriptor ? */
- /* XXX?? ISO 639 language descriptor ? */
-
-#ifdef STATS
- /* Stats */
- count_t c_bytes; /* total bytes read */
- count_t c_payload_bytes;/* total of payload useful bytes */
- count_t c_packets; /* total packets read */
- count_t c_invalid_packets; /* invalid packets read */
- /* XXX?? ... other stats */
-#endif
-} es_descriptor_t;
-
-/* Special PID values - note that the PID is only on 13 bits, and that values
- * greater than 0x1fff have no meaning in a stream */
-#define PROGRAM_ASSOCIATION_TABLE_PID 0x0000
-#define CONDITIONNAL_ACCESS_TABLE_PID 0x0001 /* not used */
-#define EMPTY_PID 0xffff /* empty record in a table */
-
-/* ES streams types - see ISO/IEC 13818-1 table 2-29 numbers */
-#define MPEG1_VIDEO_ES 0x01
-#define MPEG2_VIDEO_ES 0x02
-#define MPEG1_AUDIO_ES 0x03
-#define MPEG2_AUDIO_ES 0x04
-#define AC3_AUDIO_ES 0x81
-#define DVD_SPU_ES 0x82 /* 0x82 might violate the norm */
-#define LPCM_AUDIO_ES 0x83
-/*****************************************************************************
- * program_descriptor_t
- *****************************************************************************
- * Describes a program and list associated elementary streams. It is build by
- * the PSI decoder upon the informations carried in program map sections
- *****************************************************************************/
-typedef struct
-{
- /* Program characteristics */
- u16 i_number; /* program number */
- u8 i_version; /* version number */
- boolean_t b_is_ok; /* Is the description up to date ?*/
- u16 i_pcr_pid; /* PCR ES */
-
- int i_es_number;
- es_descriptor_t ** ap_es; /* array of pointers to ES */
-
-#ifdef DVB_EXTENSIONS
- /* Service Descriptor (program name) */
- u8 i_srv_type;
- char* psz_srv_name;
-#endif
-
- /* XXX?? target background grid descriptor ? */
- /* XXX?? video window descriptor ? */
- /* XXX?? ISO 639 language descriptor ? */
-
-#ifdef STATS
- /* Stats */
- /* XXX?? ...stats */
-#endif
-} pgrm_descriptor_t;
-
-/*****************************************************************************
- * pcr_descriptor_t
- *****************************************************************************
- * Contains informations used to synchronise the decoder with the server
- *****************************************************************************/
-
-typedef struct pcr_descriptor_struct
-{
- /* system_date = PTS_date + delta_pcr + delta_absolute */
- mtime_t delta_pcr;
- mtime_t delta_absolute;
-
- mtime_t last_pcr;
-
- u32 i_synchro_state;
- count_t c_average_count;
- /* counter used to compute dynamic average values */
-} pcr_descriptor_t;
-
-/*****************************************************************************
- * stream_descriptor_t
- *****************************************************************************
- * Describes a transport stream and list its associated programs. Build upon
- * the informations carried in program association sections
- *****************************************************************************/
-typedef struct
-{
- u16 i_stream_id; /* stream id */
-
- /* Program Association Table status */
- u8 i_PAT_version; /* version number */
- boolean_t b_is_PAT_complete; /* Is the PAT complete ?*/
- u8 i_known_PAT_sections;
- /* Number of section we received so far */
- byte_t a_known_PAT_sections[32];
- /* Already received sections */
-
- /* Program Map Table status */
- boolean_t b_is_PMT_complete; /* Is the PMT complete ?*/
- u8 i_known_PMT_sections;
- /* Number of section we received so far */
- byte_t a_known_PMT_sections[32];
- /* Already received sections */
-
- /* Service Description Table status */
- u8 i_SDT_version; /* version number */
- boolean_t b_is_SDT_complete; /* Is the SDT complete ?*/
- u8 i_known_SDT_sections;
- /* Number of section we received so far */
- byte_t a_known_SDT_sections[32];
- /* Already received sections */
-
- /* Programs description */
- int i_pgrm_number; /* Number of program number we have */
- pgrm_descriptor_t ** ap_programs; /* Array of pointers to pgrm */
-
-#ifdef STATS
- /* Stats */
- /* XXX?? ...stats */
-#endif
-} stream_descriptor_t;
-
-/*****************************************************************************
- * input_netlist_t
- *****************************************************************************/
-typedef struct
-{
- vlc_mutex_t lock; /* netlist modification lock */
- struct iovec p_ts_free[INPUT_MAX_TS + INPUT_TS_READ_ONCE];
- /* FIFO or LIFO of free TS packets */
- ts_packet_t * p_ts_packets;
- /* pointer to the first TS packet we allocated */
-
- pes_packet_t * p_pes_free[INPUT_MAX_PES + 1];
- /* FIFO or LIFO of free PES packets */
- pes_packet_t * p_pes_packets;
- /* pointer to the first PES packet we allocated */
-
- /* To use the efficiency of the scatter/gather IO operations. We implemented
- * it in 2 ways, as we don't know yet which one is better : as a FIFO (code
- * simplier) or as a LIFO stack (when we doesn't care of the ordering, this
- * allow to drastically improve the cache performance) */
-#ifdef INPUT_LIFO_TS_NETLIST
- int i_ts_index;
-#else
- int i_ts_start, i_ts_end;
-#endif
-#ifdef INPUT_LIFO_PES_NETLIST
- int i_pes_index;
-#else
- int i_pes_start, i_pes_end;
-#endif
-} input_netlist_t;
-
-
-
-/*****************************************************************************
- * input_thread_t
- *****************************************************************************
- * This structure includes all the local static variables of an input thread,
- * including the netlist and the ES descriptors
- * Note that p_es must be defined as a static table, otherwise we would have to
- * update all reference to it each time the table would be reallocated
- *****************************************************************************/
-
-/* Function pointers used in structure */
-typedef int (input_open_t) ( p_input_thread_t p_input );
-typedef int (input_read_t) ( p_input_thread_t p_input, const struct iovec *p_vector,
- size_t i_count );
-typedef void (input_close_t) ( p_input_thread_t p_input );
-
-/* Structure */
-typedef struct input_thread_s
-{
- /* Thread properties and locks */
- boolean_t b_die; /* 'die' flag */
- boolean_t b_error; /* deadlock */
- vlc_thread_t thread_id; /* id for thread functions */
- vlc_mutex_t programs_lock; /* programs modification lock */
- vlc_mutex_t es_lock; /* es modification lock */
- int * pi_status; /* temporary status flag */
-
- /* Input method description */
- int i_method; /* input method */
- int i_handle; /* file/socket descriptor */
- char * p_source; /* source */
- int i_port; /* port number */
- int i_vlan; /* id for vlan method */
- input_open_t * p_Open; /* opener of the method */
- input_read_t * p_Read; /* reading function */
- input_close_t * p_Close; /* destroying function */
-
- /* General stream description */
- stream_descriptor_t * p_stream; /* PAT tables */
- es_descriptor_t p_es[INPUT_MAX_ES];/* carried elementary streams */
- pcr_descriptor_t * p_pcr; /* PCR struct used for synchronisation */
-
- /* List of streams to demux */
- es_descriptor_t * pp_selected_es[INPUT_MAX_SELECTED_ES];
-
- /* Netlists */
- input_netlist_t netlist; /* see above */
-
- /* Default settings for spawned decoders */
- p_aout_thread_t p_aout; /* audio output thread structure */
- p_vout_thread_t p_vout; /* video output thread */
-
-#ifdef STATS
- /* Statistics */
- count_t c_loops; /* number of loops */
- count_t c_bytes; /* bytes read */
- count_t c_payload_bytes; /* payload useful bytes */
- count_t c_packets_read; /* packets read */
- count_t c_packets_trashed; /* trashed packets */
-#endif
-} input_thread_t;
-
-/* Input methods */
-#define INPUT_METHOD_NONE 0 /* input thread is inactive */
-#define INPUT_METHOD_TS_FILE 10 /* TS stream is read from a file */
-#define INPUT_METHOD_TS_UCAST 20 /* TS UDP unicast */
-#define INPUT_METHOD_TS_MCAST 21 /* TS UDP multicast */
-#define INPUT_METHOD_TS_BCAST 22 /* TS UDP broadcast */
-#define INPUT_METHOD_TS_VLAN_BCAST 32 /* TS UDP broadcast with VLANs */
-
-/*****************************************************************************
- * Prototypes
- *****************************************************************************/
-input_thread_t *input_CreateThread ( int i_method, void *p_source, int i_port,
- int i_vlan, p_vout_thread_t p_vout,
- p_aout_thread_t p_aout, int *pi_status );
-void input_DestroyThread ( input_thread_t *p_input, int *pi_status );
-
-
-int input_OpenAudioStream ( input_thread_t *p_input, int i_pid );
-void input_CloseAudioStream ( input_thread_t *p_input, int i_pid );
-int input_OpenVideoStream ( input_thread_t *p_input, int i_pid );
-void input_CloseVideoStream ( input_thread_t *p_input, int i_pid );
--- /dev/null
+/* Structures exported to the decoders */
+
+/*****************************************************************************
+ * data_packet_t
+ *****************************************************************************
+ * Describe a data packet.
+ *****************************************************************************/
+typedef struct data_packet_s
+{
+ /* Nothing before this line, the code relies on that */
+ byte_t * p_buffer; /* raw data packet */
+
+ /* Decoders information */
+ byte_t * p_payload_start;
+ /* start of the PES payload in this packet */
+ byte_t * p_payload_end; /* guess ? :-) */
+ boolean_t b_discard_payload; /* is the packet messed up ? */
+
+ /* Used to chain the TS packets that carry data for a same PES or PSI */
+ struct data_packet_s * p_next;
+} data_packet_t;
+
+/*****************************************************************************
+ * pes_packet_t
+ *****************************************************************************
+ * Describes an PES packet, with its properties, and pointers to the TS packets
+ * containing it.
+ *****************************************************************************/
+typedef struct pes_packet_s
+{
+ /* PES properties */
+ boolean_t b_messed_up; /* At least one of the data packets
+ * has a questionable content */
+ boolean_t b_data_alignment; /* used to find the beginning of
+ * a video or audio unit */
+ boolean_t b_discontinuity; /* This packet doesn't follow the
+ * previous one */
+
+ boolean_t b_has_pts; /* is the following field set ? */
+ mtime_t i_pts; /* the PTS for this packet (if set above) */
+
+ int i_pes_size; /* size of the current PES packet */
+
+ /* Pointers to packets (packets are then linked by the p_prev and
+ p_next fields of the data_packet_t struct) */
+ data_packet_t * p_first; /* The first packet containing this
+ * PES (used by decoders). */
+} pes_packet_t;
+
+/*****************************************************************************
+ * decoder_fifo_t
+ *****************************************************************************
+ * This rotative FIFO contains PES packets that are to be decoded.
+ *****************************************************************************/
+typedef struct decoder_fifo_s
+{
+ /* Thread structures */
+ vlc_mutex_t data_lock; /* fifo data lock */
+ vlc_cond_t data_wait; /* fifo data conditional variable */
+
+ /* Data */
+ pes_packet_t * buffer[FIFO_SIZE + 1];
+ int i_start;
+ int i_end;
+
+ /* Communication interface between input and decoders */
+ boolean_t b_die; /* the decoder should return now */
+ void * p_packets_mgt; /* packets management services
+ * data (netlist...) */
+ void (* pf_delete_pes)( void *, pes_packet_t * );
+ /* function to use when releasing a PES */
+} decoder_fifo_t;
+
+/* Macros to manage a decoder_fifo_t structure. Please remember to take
+ * data_lock before using them. */
+#define DECODER_FIFO_ISEMPTY( fifo ) ( (fifo).i_start == (fifo).i_end )
+#define DECODER_FIFO_ISFULL( fifo ) ( ( ((fifo).i_end + 1 - (fifo).i_start)\
+ & FIFO_SIZE ) == 0 )
+#define DECODER_FIFO_START( fifo ) ( (fifo).buffer[ (fifo).i_start ] )
+#define DECODER_FIFO_INCSTART( fifo ) ( (fifo).i_start = ((fifo).i_start + 1)\
+ & FIFO_SIZE )
+#define DECODER_FIFO_END( fifo ) ( (fifo).buffer[ (fifo).i_end ] )
+#define DECODER_FIFO_INCEND( fifo ) ( (fifo).i_end = ((fifo).i_end + 1) \
+ & FIFO_SIZE )
+
+/*****************************************************************************
+ * bit_fifo_t : bit fifo descriptor
+ *****************************************************************************
+ * This type describes a bit fifo used to store bits while working with the
+ * input stream at the bit level.
+ *****************************************************************************/
+typedef u32 WORD_TYPE; /* only u32 is supported at the moment */
+
+typedef struct bit_fifo_s
+{
+ /* This unsigned integer allows us to work at the bit level. This buffer
+ * can contain 32 bits, and the used space can be found on the MSb's side
+ * and the available space on the LSb's side. */
+ WORD_TYPE buffer;
+
+ /* Number of bits available in the bit buffer */
+ int i_available;
+
+} bit_fifo_t;
+
+/*****************************************************************************
+ * bit_stream_t : bit stream descriptor
+ *****************************************************************************
+ * This type, based on a PES stream, includes all the structures needed to
+ * handle the input stream like a bit stream.
+ *****************************************************************************/
+typedef struct bit_stream_s
+{
+ /*
+ * Input structures
+ */
+ /* The decoder fifo contains the data of the PES stream */
+ decoder_fifo_t * p_decoder_fifo;
+
+ /* Function to jump to the next data packet */
+ void (* pf_next_data_packet)( struct bit_stream_s * );
+
+ /*
+ * Byte structures
+ */
+ /* Current data packet (in the current PES packet of the PES stream) */
+ data_packet_t * p_data;
+ /* Pointer to the next byte that is to be read (in the current TS packet) */
+ byte_t * p_byte;
+ /* Pointer to the last byte that is to be read (in the current TS packet */
+ byte_t * p_end;
+
+ /*
+ * Bit structures
+ */
+ bit_fifo_t fifo;
+} bit_stream_t;
+
+/*****************************************************************************
+ * Inline functions used by the decoders to read bit_stream_t
+ *****************************************************************************/
+
+/*
+ * Philosophy of the first implementation : the bit buffer is first filled by
+ * NeedBits, then the buffer can be read via p_bit_stream->fifo.buffer, and
+ * unnecessary bits are dumped with a DumpBits() call.
+ */
+
+/*****************************************************************************
+ * GetByte : reads the next byte in the input stream
+ *****************************************************************************/
+static __inline__ byte_t GetByte( bit_stream_t * p_bit_stream )
+{
+ /* Are there some bytes left in the current data packet ? */
+ /* could change this test to have a if (! (bytes--)) instead */
+ if ( p_bit_stream->p_byte >= p_bit_stream->p_end )
+ {
+ /* no, switch to next data packet */
+ p_bit_stream->pf_next_data_packet( p_bit_stream );
+ }
+
+ return( *(p_bit_stream->p_byte++) );
+}
+
+/*****************************************************************************
+ * NeedBits : reads i_bits new bits in the bit stream and stores them in the
+ * bit buffer
+ *****************************************************************************
+ * - i_bits must be less or equal 32 !
+ * - There is something important to notice with that function : if the number
+ * of bits available in the bit buffer when calling NeedBits() is greater than
+ * 24 (i_available > 24) but less than the number of needed bits
+ * (i_available < i_bits), the byte returned by GetByte() will be shifted with
+ * a negative value and the number of bits available in the bit buffer will be
+ * set to more than 32 !
+ *****************************************************************************/
+static __inline__ void NeedBits( bit_stream_t * p_bit_stream, int i_bits )
+{
+ while ( p_bit_stream->fifo.i_available < i_bits )
+ {
+ p_bit_stream->fifo.buffer |= ((WORD_TYPE)GetByte( p_bit_stream ))
+ << (sizeof(WORD_TYPE) - 8
+ - p_bit_stream->fifo.i_available);
+ p_bit_stream->fifo.i_available += 8;
+ }
+}
+
+/*****************************************************************************
+ * DumpBits : removes i_bits bits from the bit buffer
+ *****************************************************************************
+ * - i_bits <= i_available
+ * - i_bits < 32 (because (u32 << 32) <=> (u32 = u32))
+ *****************************************************************************/
+static __inline__ void DumpBits( bit_stream_t * p_bit_stream, int i_bits )
+{
+ p_bit_stream->fifo.buffer <<= i_bits;
+ p_bit_stream->fifo.i_available -= i_bits;
+}
+
+
+/*
+ * Philosophy of the second implementation : WORD_LENGTH (usually 32) bits
+ * are read at the same time, thus minimizing the number of p_byte changes.
+ * Bits are read via GetBits() or ShowBits. This is slightly faster. Be
+ * aware that if, in the forthcoming functions, i_bits > 24, the data have to
+ * be already aligned on an 8-bit boundary, or wrong results will be
+ * returned.
+ */
+
+#if (WORD_TYPE != u32)
+# error Not supported word
+#endif
+
+/*
+ * This is stolen from the livid source who stole it from the kernel
+ * FIXME: The macro swab32 for little endian machines does
+ * not seem to work correctly
+ */
+
+#if defined(SYS_BEOS)
+# define swab32(x) B_BENDIAN_TO_HOST_INT32(x)
+#else
+# if __BYTE_ORDER == __BIG_ENDIAN
+# define swab32(x) (x)
+# else
+# if defined (__i386__)
+static __inline__ const u32 __i386_swab32( u32 x )
+{
+ __asm__("bswap %0" : "=r" (x) : "0" (x));
+ return x;
+}
+# define swab32(x) __i386_swab32(x)
+# else
+# define swab32(x) \
+ ( ( (u32)(((u8*)&x)[0]) << 24 ) | ( (u32)(((u8*)&x)[1]) << 16 ) |\
+ ( (u32)(((u8*)&x)[2]) << 8 ) | ( (u32)(((u8*)&x)[3])) )
+# endif
+# endif
+#endif
+
+/*****************************************************************************
+ * ShowBits : return i_bits bits from the bit stream
+ *****************************************************************************/
+static __inline__ WORD_TYPE ShowWord( bit_stream_t * p_bit_stream )
+{
+ if( p_bit_stream->p_byte <= p_bit_stream->p_end - sizeof(WORD_TYPE) )
+ {
+ return( swab32( *((WORD_TYPE *)p_bit_stream->p_byte) ) );
+ }
+
+ p_bit_stream->pf_next_data_packet( p_bit_stream );
+ return( swab32( *((WORD_TYPE *)p_bit_stream->p_byte) ) );
+}
+
+static __inline__ WORD_TYPE ShowBits( bit_stream_t * p_bit_stream, int i_bits )
+{
+ if( p_bit_stream->fifo.i_available >= i_bits )
+ {
+ return( p_bit_stream->fifo.buffer >> (8 * sizeof(WORD_TYPE) - i_bits) );
+ }
+
+ return( (p_bit_stream->fifo.buffer |
+ (ShowWord( p_bit_stream ) >> p_bit_stream->fifo.i_available))
+ >> (8 * sizeof(WORD_TYPE) - i_bits) );
+}
+
+/*****************************************************************************
+ * GetWord : returns the next word to be read
+ *****************************************************************************/
+static __inline__ WORD_TYPE GetWord( bit_stream_t * p_bit_stream )
+{
+ if( p_bit_stream->p_byte <= p_bit_stream->p_end - sizeof(WORD_TYPE) )
+ {
+ return( swab32( *(((WORD_TYPE *)p_bit_stream->p_byte)++) ) );
+ }
+ else
+ {
+ p_bit_stream->pf_next_data_packet( p_bit_stream );
+ return( swab32( *(((WORD_TYPE *)p_bit_stream->p_byte)++) ) );
+ }
+}
+
+/*****************************************************************************
+ * RemoveBits : removes i_bits bits from the bit buffer
+ *****************************************************************************/
+static __inline__ void RemoveBits( bit_stream_t * p_bit_stream, int i_bits )
+{
+ p_bit_stream->fifo.i_available -= i_bits;
+
+ if( p_bit_stream->fifo.i_available >= 0 )
+ {
+ p_bit_stream->fifo.buffer <<= i_bits;
+ return;
+ }
+ p_bit_stream->fifo.buffer = GetWord( p_bit_stream )
+ << ( -p_bit_stream->fifo.i_available );
+ p_bit_stream->fifo.i_available += sizeof(WORD_TYPE) * 8;
+}
+
+/*****************************************************************************
+ * RemoveBits32 : removes 32 bits from the bit buffer (and as a side effect,
+ * refill it). This should be faster than RemoveBits, though
+ * RemoveBits will work, too.
+ *****************************************************************************/
+static __inline__ void RemoveBits32( bit_stream_t * p_bit_stream )
+{
+ p_bit_stream->fifo.buffer = GetWord( p_bit_stream )
+ << (32 - p_bit_stream->fifo.i_available);
+}
+
+/*****************************************************************************
+ * GetBits : returns i_bits bits from the bit stream and removes them
+ *****************************************************************************/
+static __inline__ WORD_TYPE GetBits( bit_stream_t * p_bit_stream, int i_bits )
+{
+ u32 i_result;
+
+ p_bit_stream->fifo.i_available -= i_bits;
+ if( p_bit_stream->fifo.i_available >= 0 )
+ {
+ i_result = p_bit_stream->fifo.buffer >> (8 * sizeof(WORD_TYPE) - i_bits);
+ p_bit_stream->fifo.buffer <<= i_bits;
+ return( i_result );
+ }
+
+ i_result = p_bit_stream->fifo.buffer >> (8 * sizeof(WORD_TYPE) - i_bits);
+ p_bit_stream->fifo.buffer = GetWord( p_bit_stream );
+ i_result |= p_bit_stream->fifo.buffer
+ >> (8 * sizeof(WORD_TYPE)
+ + p_bit_stream->fifo.i_available);
+ p_bit_stream->fifo.buffer <<= ( -p_bit_stream->fifo.i_available );
+ p_bit_stream->fifo.i_available += sizeof(WORD_TYPE) * 8;
+
+ return( i_result );
+}
+
+/*****************************************************************************
+ * GetBits32 : returns 32 bits from the bit stream and removes them
+ *****************************************************************************/
+static __inline__ WORD_TYPE GetBits32( bit_stream_t * p_bit_stream )
+{
+ WORD_TYPE i_result;
+
+ i_result = p_bit_stream->fifo.buffer;
+ p_bit_stream->fifo.buffer = GetWord( p_bit_stream );
+ i_result |= p_bit_stream->fifo.buffer
+ >> (p_bit_stream->fifo.i_available);
+ p_bit_stream->fifo.buffer <<= (8 * sizeof(WORD_TYPE)
+ - p_bit_stream->fifo.i_available);
+
+ return( i_result );
+}
+
+/*****************************************************************************
+ * RealignBits : realigns the bit buffer on an 8-bit boundary
+ *****************************************************************************/
+static __inline__ void RealignBits( bit_stream_t * p_bit_stream )
+{
+ p_bit_stream->fifo.buffer <<= (p_bit_stream->fifo.i_available & 0x7);
+ p_bit_stream->fifo.i_available &= ~0x7;
+}
+
+
+/*
+ * Communication interface between input and decoders
+ */
+
+/*****************************************************************************
+ * decoder_config_t
+ *****************************************************************************
+ * Standard pointers given to the decoders as a toolbox.
+ *****************************************************************************/
+typedef struct decoder_config_s
+{
+ u16 i_stream_id;
+ u8 i_type; /* type of the elementary stream */
+
+ struct stream_ctrl_s * p_stream_ctrl;
+ struct decoder_fifo_s * p_decoder_fifo;
+ void (* pf_init_bit_stream)( struct bit_stream_s *,
+ struct decoder_fifo_s * );
+} decoder_config_t;
+
+/*****************************************************************************
+ * vdec_config_t
+ *****************************************************************************
+ * Pointers given to video decoders threads.
+ *****************************************************************************/
+struct vout_thread_s;
+
+typedef struct vdec_config_s
+{
+ struct vout_thread_s * p_vout;
+
+ struct picture_s * (* pf_create_picture)( struct vout_thread_s *,
+ int i_type, int i_width,
+ int i_height );
+ void (* pf_destroy_picture)( struct vout_thread_s *,
+ struct picture_s * );
+ void (* pf_display_picture)( struct vout_thread_s *,
+ struct picture_s * );
+ void (* pf_date_picture)( struct vout_thread_s *,
+ struct picture_s *, mtime_t date );
+ void (* pf_link_picture)( struct vout_thread_s *,
+ struct picture_s *, mtime_t date );
+ void (* pf_unlink_picture)( struct vout_thread_s *,
+ struct picture_s *, mtime_t date );
+ struct subpicture_s *(* pf_create_subpicture)( struct vout_thread_s *,
+ int i_type, int i_size );
+ void (* pf_destroy_subpicture)( struct vout_thread_s *,
+ struct subpicture_s * );
+ void (* pf_display_subpicture)( struct vout_thread_s *,
+ struct subpicture_s * );
+
+ decoder_config_t decoder_config;
+} vdec_config_t;
+
+/*****************************************************************************
+ * adec_config_t
+ *****************************************************************************
+ * Pointers given to audio decoders threads.
+ *****************************************************************************/
+struct aout_thread_s;
+
+typedef struct adec_config_s
+{
+ struct aout_thread_s * p_aout;
+
+ struct aout_fifo_s * (* pf_create_fifo)( struct aout_thread_s *,
+ struct aout_fifo_s * );
+ void (* pf_destroy_fifo)( struct aout_thread_s *);
+
+ decoder_config_t decoder_config;
+} adec_config_t;
+
+
+/*
+ * Communication interface between decoders and input
+ */
+
+/*****************************************************************************
+ * decoder_capabilities_t
+ *****************************************************************************
+ * Structure returned by a call to GetCapabilities() of the decoder.
+ *****************************************************************************/
+typedef struct decoder_capabilities_s
+{
+ int i_dec_type;
+ u8 i_stream_type; /* == i_type in es_descriptor_t */
+ int i_weight; /* for a given stream type, the decoder
+ * with higher weight will be spawned */
+
+ vlc_thread_t (* pf_create_thread)( struct decoder_config_s * );
+} decoder_capabilities_t;
+
+/* Decoder types */
+#define NONE_D 0
+#define VIDEO_D 1
+#define AUDIO_D 2
--- /dev/null
+/* Structures exported to the interface */
+
+/*
+ * Communication input -> interface
+ */
+#define INPUT_MAX_PLUGINS 1
+
+/*****************************************************************************
+ * es_descriptor_t: elementary stream descriptor
+ *****************************************************************************
+ * Describes an elementary stream, and includes fields required to handle and
+ * demultiplex this elementary stream.
+ *****************************************************************************/
+struct decoder_fifo_s; /* defined in input_ext-dec.h */
+struct pgrm_descriptor_s;
+
+typedef struct es_descriptor_s
+{
+ u16 i_id; /* stream ID for PS, PID for TS */
+ u8 i_stream_id; /* stream ID defined in the PES */
+ u8 i_type; /* stream type */
+
+ /* Demultiplexer information */
+ void * p_demux_data;
+ struct pgrm_descriptor_s *
+ p_pgrm; /* very convenient in the demultiplexer */
+ boolean_t b_discontinuity;
+
+ /* PES parser information */
+ struct pes_packet_s * p_pes; /* Current PES */
+ struct data_packet_s * p_last; /* The last packet gathered at present */
+ int i_pes_real_size; /* as indicated by the header */
+
+ /* Decoder information */
+ struct decoder_fifo_s * p_decoder_fifo;
+ vlc_thread_t thread_id; /* ID of the decoder */
+
+#ifdef STATS
+ count_t c_payload_bytes;/* total of payload useful bytes */
+ count_t c_packets; /* total packets read */
+ count_t c_invalid_packets; /* invalid packets read */
+#endif
+} es_descriptor_t;
+
+/* Special PID values - note that the PID is only on 13 bits, and that values
+ * greater than 0x1fff have no meaning in a stream */
+#define PROGRAM_ASSOCIATION_TABLE_PID 0x0000
+#define CONDITIONNAL_ACCESS_TABLE_PID 0x0001 /* not used */
+#define EMPTY_ID 0xffff /* empty record in a table */
+
+/* ES streams types - see ISO/IEC 13818-1 table 2-29 numbers */
+#define MPEG1_VIDEO_ES 0x01
+#define MPEG2_VIDEO_ES 0x02
+#define MPEG1_AUDIO_ES 0x03
+#define MPEG2_AUDIO_ES 0x04
+#define AC3_AUDIO_ES 0x81
+#define DVD_SPU_ES 0x82 /* 0x82 might violate the norm */
+#define LPCM_AUDIO_ES 0x83
+
+/*****************************************************************************
+ * pgrm_descriptor_t
+ *****************************************************************************
+ * Describes a program and list associated elementary streams. It is build by
+ * the PSI decoder upon the informations carried in program map sections
+ *****************************************************************************/
+typedef struct pgrm_descriptor_s
+{
+ /* Program characteristics */
+ u16 i_number; /* program number */
+ u8 i_version; /* version number */
+ boolean_t b_is_ok; /* Is the description up to date ? */
+
+ /* Service Descriptor (program name) - DVB extension */
+ u8 i_srv_type;
+ char * psz_srv_name;
+
+ /* Synchronization information */
+ /* system_date = PTS_date + delta_cr + delta_absolute */
+ mtime_t delta_cr;
+ mtime_t delta_absolute;
+ mtime_t last_cr;
+ count_t c_average_count;
+ /* counter used to compute dynamic average values */
+ int i_synchro_state;
+
+ /* Demultiplexer data */
+ void * p_demux_data;
+
+ /* Decoders control */
+ struct vout_thread_s * p_vout;
+ struct aout_thread_s * p_aout;
+
+ int i_es_number; /* size of the following array */
+ es_descriptor_t ** pp_es; /* array of pointers to ES */
+} pgrm_descriptor_t;
+
+/* Synchro states */
+#define SYNCHRO_OK 0
+#define SYNCHRO_NOT_STARTED 1
+#define SYNCHRO_START 2
+#define SYNCHRO_REINIT 3
+
+/*****************************************************************************
+ * stream_descriptor_t
+ *****************************************************************************
+ * Describes a stream and list its associated programs. Build upon
+ * the information carried in program association sections (for instance)
+ *****************************************************************************/
+typedef struct stream_descriptor_s
+{
+ u16 i_stream_id; /* stream id */
+ vlc_mutex_t stream_lock; /* to be taken every time you read
+ * or modify stream, pgrm or es */
+
+ /* Input method data */
+ boolean_t b_pace_control; /* can we read when we want ? */
+ boolean_t b_seekable; /* can we do lseek() ? */
+ /* if (b_seekable) : */
+ off_t i_size; /* total size of the file (in bytes) */
+ off_t i_tell;/* actual location in the file (in bytes) */
+
+ /* Demultiplexer data */
+ void * p_demux_data;
+
+ /* Programs description */
+ int i_pgrm_number; /* size of the following array */
+ pgrm_descriptor_t ** pp_programs; /* array of pointers to pgrm */
+
+ /* Stream control */
+ stream_ctrl_t control;
+} stream_descriptor_t;
+
+/*****************************************************************************
+ * i_p_config_t
+ *****************************************************************************
+ * This structure gives plugins pointers to the useful functions of input
+ *****************************************************************************/
+struct input_thread_s;
+struct data_packet_s;
+struct es_descriptor_s;
+
+typedef struct i_p_config_s
+{
+ int (* pf_peek_stream)( struct input_thread_s *,
+ byte_t * buffer, size_t );
+ void (* pf_demux_pes)( struct input_thread_s *,
+ struct data_packet_s *,
+ struct es_descriptor_s *,
+ boolean_t b_unit_start,
+ boolean_t b_packet_lost );
+} i_p_config_t;
+
+/*****************************************************************************
+ * input_thread_t
+ *****************************************************************************
+ * This structure includes all the local static variables of an input thread
+ *****************************************************************************/
+struct aout_thread_s;
+struct vout_thread_s;
+
+typedef struct input_thread_s
+{
+ /* Thread properties and locks */
+ boolean_t b_die; /* 'die' flag */
+ boolean_t b_error;
+ vlc_thread_t thread_id; /* id for thread functions */
+ int * pi_status; /* temporary status flag */
+
+ struct input_config_s * p_config;
+
+ struct input_capabilities_s *
+ pp_plugins[INPUT_MAX_PLUGINS];/* list of plugins */
+ struct input_capabilities_s *
+ p_plugin; /* selected plugin */
+ i_p_config_t i_p_config; /* plugin configuration */
+
+ int i_handle; /* socket or file descriptor */
+ void * p_method_data;
+
+ /* General stream description */
+ stream_descriptor_t stream; /* PAT tables */
+ es_descriptor_t p_es[INPUT_MAX_ES];
+ /* carried elementary streams */
+
+ /* List of streams to demux */
+ es_descriptor_t * pp_selected_es[INPUT_MAX_SELECTED_ES];
+
+ /* For auto-launch of decoders */
+ struct aout_thread_s * p_default_aout;
+ struct vout_thread_s * p_default_vout;
+
+#ifdef STATS
+ count_t c_loops;
+ count_t c_bytes; /* bytes read */
+ count_t c_payload_bytes; /* payload useful bytes */
+ count_t c_packets_read; /* packets read */
+ count_t c_packets_trashed; /* trashed packets */
+#endif
+} input_thread_t;
+
+
+/*
+ * Communication interface -> input
+ */
+
+/*****************************************************************************
+ * input_config_t
+ *****************************************************************************
+ * This structure is given by the interface to an input thread
+ *****************************************************************************/
+typedef struct input_config_s
+{
+ /* Input method description */
+ int i_method; /* input method */
+ char * p_source; /* source */
+
+ /* For auto-launch of decoders */
+ struct aout_thread_s * p_default_aout;
+ struct vout_thread_s * p_default_vout;
+} input_config_t;
+
+/* Input methods */
+#define INPUT_METHOD_NONE 0 /* input thread is inactive */
+#define INPUT_METHOD_FILE 10 /* stream is read from file p_source */
+#define INPUT_METHOD_UCAST 20 /* UDP unicast */
+#define INPUT_METHOD_MCAST 21 /* UDP multicast */
+#define INPUT_METHOD_BCAST 22 /* UDP broadcast */
+#define INPUT_METHOD_VLAN_BCAST 32 /* UDP broadcast with VLANs */
+
+/*****************************************************************************
+ * Prototypes
+ *****************************************************************************/
+struct input_thread_s * input_CreateThread( struct input_config_s *,
+ int *pi_status );
+void input_DestroyThread( struct input_thread_s *,
+ int *pi_status );
+void input_PauseProgram( struct input_thread_s *,
+ struct pgrm_descriptor_s * );
+void input_PlayProgram( struct input_thread_s *,
+ struct pgrm_descriptor_s * );
+void input_FFProgram( struct input_thread_s *,
+ struct pgrm_descriptor_s * );
+void input_SMProgram( struct input_thread_s *,
+ struct pgrm_descriptor_s * );
+void input_RewindProgram( struct input_thread_s *,
+ struct pgrm_descriptor_s * );
+++ /dev/null
-/*****************************************************************************
- * input_netlist.h: netlist interface
- * The netlists are an essential part of the input structure. We maintain a
- * list of free TS packets and free PES packets to avoid continuous malloc
- * and free.
- *****************************************************************************
- * Copyright (C) 1998, 1999, 2000 VideoLAN
- *
- * 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.
- *****************************************************************************/
-
-#include "intf_msg.h"
-
-/*****************************************************************************
- * Prototypes
- *****************************************************************************/
-int input_NetlistInit ( input_thread_t *p_input );
-void input_NetlistEnd ( input_thread_t *p_input );
-
-static __inline__ void input_NetlistFreePES( input_thread_t *p_input, pes_packet_t *p_pes_packet );
-static __inline__ void input_NetlistFreeTS( input_thread_t *p_input, ts_packet_t *p_ts_packet );
-static __inline__ pes_packet_t* input_NetlistGetPES( input_thread_t *p_input );
-
-/*****************************************************************************
- * input_NetlistFreePES: add a PES packet to the netlist
- *****************************************************************************
- * Add a PES packet to the PES netlist, so that the packet can immediately be
- * reused by the demultiplexer. We put this function directly in the .h file,
- * because it is very frequently called.
- *****************************************************************************/
-static __inline__ void input_NetlistFreePES( input_thread_t *p_input,
- pes_packet_t *p_pes_packet )
-{
- int i_dummy;
- ts_packet_t * p_ts_packet;
-
- ASSERT(p_pes_packet);
-
- /* We will be playing with indexes, so we take a lock. */
- vlc_mutex_lock( &p_input->netlist.lock );
-
- /* Free all TS packets in this PES structure. */
- p_ts_packet = p_pes_packet->p_first_ts;
- for( i_dummy = 0; i_dummy < p_pes_packet->i_ts_packets; i_dummy++ )
- {
- ASSERT(p_ts_packet);
-
-#ifdef INPUT_LIFO_TS_NETLIST
- p_input->netlist.i_ts_index--;
- p_input->netlist.p_ts_free[p_input->netlist.i_ts_index].iov_base
- = (void *)p_ts_packet;
-#else /* FIFO */
- p_input->netlist.p_ts_free[p_input->netlist.i_ts_end].iov_base
- = (void *)p_ts_packet;
- p_input->netlist.i_ts_end++;
- p_input->netlist.i_ts_end &= INPUT_MAX_TS; /* loop */
-#endif
- p_ts_packet = p_ts_packet->p_next_ts;
- }
-
- /* Free the PES structure. */
-#ifdef INPUT_LIFO_PES_NETLIST
- p_input->netlist.i_pes_index--;
- p_input->netlist.p_pes_free[p_input->netlist.i_pes_index] = p_pes_packet;
-#else /* FIFO */
- p_input->netlist.p_pes_free[p_input->netlist.i_pes_end] = p_pes_packet;
- p_input->netlist.i_pes_end++;
- p_input->netlist.i_pes_end &= INPUT_MAX_PES; /* loop */
-#endif
-
- vlc_mutex_unlock( &p_input->netlist.lock );
-}
-
-/*****************************************************************************
- * input_NetlistFreeTS: add a TS packet to the netlist
- *****************************************************************************
- * Add a TS packet to the TS netlist, so that the packet can immediately be
- * reused by the demultiplexer. Shouldn't be called by other threads (they
- * should only use input_FreePES.
- *****************************************************************************/
-static __inline__ void input_NetlistFreeTS( input_thread_t *p_input,
- ts_packet_t *p_ts_packet )
-{
- ASSERT(p_ts_packet);
-
- /* We will be playing with indexes, so we take a lock. */
- vlc_mutex_lock( &p_input->netlist.lock );
-
- /* Free the TS structure. */
-#ifdef INPUT_LIFO_TS_NETLIST
- p_input->netlist.i_ts_index--;
- p_input->netlist.p_ts_free[p_input->netlist.i_ts_index].iov_base
- = (void *)p_ts_packet;
-#else /* FIFO */
- p_input->netlist.p_ts_free[p_input->netlist.i_ts_end].iov_base
- = (void *)p_ts_packet;
- p_input->netlist.i_ts_end++;
- p_input->netlist.i_ts_end &= INPUT_MAX_TS; /* loop */
-#endif
-
- vlc_mutex_unlock( &p_input->netlist.lock );
-}
-
-/*****************************************************************************
- * input_NetlistGetPES: remove a PES packet from the netlist
- *****************************************************************************
- * Add a TS packet to the TS netlist, so that the packet can immediately be
- * reused by the demultiplexer. Shouldn't be called by other threads (they
- * should only use input_FreePES.
- *****************************************************************************/
-static __inline__ pes_packet_t* input_NetlistGetPES( input_thread_t *p_input )
-{
- pes_packet_t * p_pes_packet;
-
-#ifdef INPUT_LIFO_PES_NETLIST
- /* i_pes_index might be accessed by a decoder thread to give back a
- * packet. */
- vlc_mutex_lock( &p_input->netlist.lock );
-
- /* Verify that we still have PES packet in the netlist */
- if( (INPUT_MAX_PES - p_input->netlist.i_pes_index ) <= 1 )
- {
- intf_ErrMsg("input error: PES netlist is empty !\n");
- return( NULL );
- }
-
- /* Fetch a new PES packet */
- p_pes_packet = p_input->netlist.p_pes_free[p_input->netlist.i_pes_index];
- p_input->netlist.i_pes_index++;
- vlc_mutex_unlock( &p_input->netlist.lock );
-
-#else /* FIFO */
- /* No need to lock, since we are the only ones accessing i_pes_start. */
-
- /* Verify that we still have PES packet in the netlist */
- if( ((p_input->netlist.i_pes_end -1 - p_input->netlist.i_pes_start) & INPUT_MAX_PES) <= 1 )
- {
- intf_ErrMsg("input error: PES netlist is empty !\n");
- return( NULL );
- }
-
- p_pes_packet = p_input->netlist.p_pes_free[p_input->netlist.i_pes_start];
- p_input->netlist.i_pes_start++;
- p_input->netlist.i_pes_start &= INPUT_MAX_PES; /* loop */
-#endif /* netlist type */
-
- /* Initialize PES flags. */
- p_pes_packet->b_data_loss = 0;
- p_pes_packet->b_data_alignment = 0;
- p_pes_packet->b_has_pts = 0;
- p_pes_packet->b_random_access = 0;
- p_pes_packet->b_discard_payload = 0;
- p_pes_packet->i_pes_size = 0;
- p_pes_packet->i_pes_real_size = 0;
- p_pes_packet->i_ts_packets = 0;
- p_pes_packet->p_first_ts = NULL;
- p_pes_packet->p_last_ts = NULL;
-
- return( p_pes_packet );
-}
+++ /dev/null
-/*****************************************************************************
- * input_file.h: file input method
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
- * Samuel Hocevar <sam@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.
- *****************************************************************************/
-
-/*****************************************************************************
- * Prototypes
- *****************************************************************************/
-
-#define REQUESTED_AC3 0
-#define REQUESTED_MPEG 1
-#define REQUESTED_LPCM 2
-#define REQUESTED_NOAUDIO 255
-
--- /dev/null
+/* Structures exported to interface, input and decoders */
+
+/*****************************************************************************
+ * stream_ctrl_t
+ *****************************************************************************
+ * Describe the state of a program stream.
+ *****************************************************************************/
+typedef struct stream_ctrl_s
+{
+ vlc_mutex_t control_lock;
+
+ int i_status;
+ /* if i_status == FORWARD_S or BACKWARD_S */
+ int i_rate;
+ s64 i_ref_sysdate;
+ s64 i_ref_clock;
+
+ boolean_t b_mute;
+ boolean_t b_bw; /* black & white */
+} stream_ctrl_t;
+
+/* Possible status : */
+#define PLAYING_S 0
+#define PAUSE_S 1
+#define FORWARD_S 2
+#define BACKWARD_S 3
+
+#define DEFAULT_RATE 1000
/* Input properties */
- decoder_fifo_t fifo; /* PES input fifo */
-
- /* The bit stream structure handles the PES stream at the bit level */
+ decoder_fifo_t * p_fifo; /* PES input fifo */
bit_stream_t bit_stream;
+ vdec_config_t * p_config;
+
/* Output properties */
vout_thread_t * p_vout; /* video output thread */
*****************************************************************************/
/* Thread management functions */
-vpar_thread_t * vpar_CreateThread ( /* video_cfg_t *p_cfg, */ input_thread_t *p_input /*,
- vout_thread_t *p_vout, int *pi_status */ );
-void vpar_DestroyThread ( vpar_thread_t *p_vpar /*, int *pi_status */ );
-
-/* Time management functions */
-/* XXX?? */
-
-/* Dynamic thread settings */
-/* XXX?? */
-
+vlc_thread_t vpar_CreateThread ( vdec_config_t * );
/*****************************************************************************
* NextStartCode : Find the next start code
*****************************************************************************/
-static __inline__ void NextStartCode( vpar_thread_t * p_vpar )
+static __inline__ void NextStartCode( bit_stream_t * p_bit_stream )
{
/* Re-align the buffer on an 8-bit boundary */
- RealignBits( &p_vpar->bit_stream );
+ RealignBits( p_bit_stream );
- while( ShowBits( &p_vpar->bit_stream, 24 ) != 0x01L && !p_vpar->b_die )
+ while( ShowBits( p_bit_stream, 24 ) != 0x01L
+ && !p_bit_stream->p_decoder_fifo->b_die )
{
- RemoveBits( &p_vpar->bit_stream, 8 );
+ RemoveBits( p_bit_stream, 8 );
}
}
#include "defs.h"
#include <stdlib.h> /* malloc(), free() */
-#include <sys/types.h> /* on BSD, uio.h needs types.h */
-#include <sys/uio.h> /* "input.h" */
#include "config.h"
#include "common.h"
#include "mtime.h"
#include "plugins.h"
-#include "input.h"
+#include "stream_control.h"
+#include "input_ext-intf.h"
+
#include "video.h"
#include "video_output.h"
#include "mtime.h"
#include "plugins.h"
-#include "input.h"
+#include "stream_control.h"
+#include "input_ext-intf.h"
+
#include "video.h"
#include "video_output.h"
#include "mtime.h"
#include "plugins.h"
-#include "input.h"
+#include "stream_control.h"
+#include "input_ext-intf.h"
+
#include "video.h"
#include "video_output.h"
#include "mtime.h"
#include "plugins.h"
-#include "input.h"
+#include "stream_control.h"
+#include "input_ext-intf.h"
+
#include "video.h"
#include "video_output.h"
#include "mtime.h"
#include "plugins.h"
-#include "input.h"
+#include "stream_control.h"
+#include "input_ext-intf.h"
+
#include "video.h"
#include "video_output.h"
#include "mtime.h"
#include "plugins.h"
-#include "input.h"
+#include "stream_control.h"
+#include "input_ext-intf.h"
+
#include "video.h"
#include "video_output.h"
#include "mtime.h"
#include "plugins.h"
-#include "input.h"
+#include "stream_control.h"
+#include "input_ext-intf.h"
+
#include "video.h"
#include "video_output.h"
#include "mtime.h"
#include "plugins.h"
-#include "input.h"
+#include "stream_control.h"
+#include "input_ext-intf.h"
+
#include "video.h"
#include "video_output.h"
#include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */
-#include "input.h" /* pes_packet_t */
-#include "input_netlist.h" /* input_NetlistFreePES() */
-#include "decoder_fifo.h" /* DECODER_FIFO_(ISEMPTY|START|INCSTART)() */
+#include "stream_control.h"
+#include "input_ext-dec.h"
#include "audio_output.h"
/*****************************************************************************
* ac3dec_CreateThread: creates an ac3 decoder thread
*****************************************************************************/
-ac3dec_thread_t * ac3dec_CreateThread (input_thread_t * p_input)
+vlc_thread_t ac3dec_CreateThread( adec_config_t * p_config )
{
ac3dec_thread_t * p_ac3dec;
{
intf_ErrMsg ( "ac3dec error: not enough memory "
"for ac3dec_CreateThread() to create the new thread\n");
- return NULL;
+ return 0;
}
/*
*/
p_ac3dec->b_die = 0;
p_ac3dec->b_error = 0;
-
- /*
- * Initialize the input properties
- */
- /* Initialize the decoder fifo's data lock and conditional variable and set
- * its buffer as empty */
- vlc_mutex_init (&p_ac3dec->fifo.data_lock);
- vlc_cond_init (&p_ac3dec->fifo.data_wait);
- p_ac3dec->fifo.i_start = 0;
- p_ac3dec->fifo.i_end = 0;
+ p_ac3dec->p_config = p_config;
+ p_ac3dec->p_fifo = p_config->decoder_config.p_decoder_fifo;
/* Initialize the ac3 decoder structures */
ac3_init (&p_ac3dec->ac3_decoder);
- /* Initialize the bit stream structure */
- p_ac3dec->p_input = p_input;
-
/*
* Initialize the output properties
*/
- p_ac3dec->p_aout = p_input->p_aout;
+ p_ac3dec->p_aout = p_config->p_aout;
p_ac3dec->p_aout_fifo = NULL;
/* Spawn the ac3 decoder thread */
{
intf_ErrMsg( "ac3dec error: can't spawn ac3 decoder thread\n" );
free (p_ac3dec);
- return NULL;
+ return 0;
}
intf_DbgMsg ("ac3dec debug: ac3 decoder thread (%p) created\n", p_ac3dec);
- return p_ac3dec;
-}
-
-/*****************************************************************************
- * ac3dec_DestroyThread: destroys an ac3 decoder thread
- *****************************************************************************/
-void ac3dec_DestroyThread (ac3dec_thread_t * p_ac3dec)
-{
- intf_DbgMsg ("ac3dec debug: requesting termination of ac3 decoder thread %p\n", p_ac3dec);
-
- /* Ask thread to kill itself */
- p_ac3dec->b_die = 1;
-
- /* Make sure the decoder thread leaves the GetByte() function */
- vlc_mutex_lock (&(p_ac3dec->fifo.data_lock));
- vlc_cond_signal (&(p_ac3dec->fifo.data_wait));
- vlc_mutex_unlock (&(p_ac3dec->fifo.data_lock));
-
- /* Waiting for the decoder thread to exit */
- /* Remove this as soon as the "status" flag is implemented */
- vlc_thread_join (p_ac3dec->thread_id);
+ return p_ac3dec->thread_id;
}
/* Following functions are local */
intf_DbgMsg ("ac3dec debug: initializing ac3 decoder thread %p\n", p_ac3dec);
- /* Our first job is to initialize the bit stream structure with the
- * beginning of the input stream */
- vlc_mutex_lock (&p_ac3dec->fifo.data_lock);
- while (DECODER_FIFO_ISEMPTY(p_ac3dec->fifo))
- {
- if (p_ac3dec->b_die)
- {
- vlc_mutex_unlock (&p_ac3dec->fifo.data_lock);
- return -1;
- }
- vlc_cond_wait (&p_ac3dec->fifo.data_wait, &p_ac3dec->fifo.data_lock);
- }
- p_ac3dec->p_ts = DECODER_FIFO_START (p_ac3dec->fifo)->p_first_ts;
+ p_ac3dec->p_data = DECODER_FIFO_START(*p_ac3dec->p_fifo)->p_first;
byte_stream = ac3_byte_stream (&p_ac3dec->ac3_decoder);
- byte_stream->p_byte =
- p_ac3dec->p_ts->buffer + p_ac3dec->p_ts->i_payload_start;
- byte_stream->p_end =
- p_ac3dec->p_ts->buffer + p_ac3dec->p_ts->i_payload_end;
+ byte_stream->p_byte = p_ac3dec->p_data->p_payload_start;
+ byte_stream->p_end = p_ac3dec->p_data->p_payload_end;
byte_stream->info = p_ac3dec;
- vlc_mutex_unlock (&p_ac3dec->fifo.data_lock);
+ vlc_mutex_unlock (&p_ac3dec->p_fifo->data_lock);
aout_fifo.i_type = AOUT_ADEC_STEREO_FIFO;
aout_fifo.i_channels = 2;
intf_DbgMsg ("ac3dec debug: running ac3 decoder thread (%p) (pid == %i)\n", p_ac3dec, getpid());
- msleep (INPUT_PTS_DELAY);
+ /* FIXME ! Qu'est-ce que c'est que ce bordel !?!?!?!? --Meuuh */
+ //msleep (INPUT_PTS_DELAY);
/* Initializing the ac3 decoder thread */
if (InitThread (p_ac3dec)) /* XXX?? */
p_ac3dec->sync_ptr = 0;
}
- if (DECODER_FIFO_START(p_ac3dec->fifo)->b_has_pts)
+ if (DECODER_FIFO_START(*p_ac3dec->p_fifo)->b_has_pts)
{
- p_ac3dec->p_aout_fifo->date[p_ac3dec->p_aout_fifo->l_end_frame] = DECODER_FIFO_START(p_ac3dec->fifo)->i_pts;
- DECODER_FIFO_START(p_ac3dec->fifo)->b_has_pts = 0;
+ p_ac3dec->p_aout_fifo->date[p_ac3dec->p_aout_fifo->l_end_frame] = DECODER_FIFO_START(*p_ac3dec->p_fifo)->i_pts;
+ DECODER_FIFO_START(*p_ac3dec->p_fifo)->b_has_pts = 0;
}
else
{
{
/* We take the lock, because we are going to read/write the start/end
* indexes of the decoder fifo */
- vlc_mutex_lock (&p_ac3dec->fifo.data_lock);
+ vlc_mutex_lock (&p_ac3dec->p_fifo->data_lock);
/* Wait until a `die' order is sent */
while (!p_ac3dec->b_die)
{
/* Trash all received PES packets */
- while (!DECODER_FIFO_ISEMPTY(p_ac3dec->fifo))
+ while (!DECODER_FIFO_ISEMPTY(*p_ac3dec->p_fifo))
{
- input_NetlistFreePES (p_ac3dec->p_input, DECODER_FIFO_START(p_ac3dec->fifo));
- DECODER_FIFO_INCSTART (p_ac3dec->fifo);
+ p_ac3dec->p_fifo->pf_delete_pes(p_ac3dec->p_fifo->p_packets_mgt,
+ DECODER_FIFO_START(*p_ac3dec->p_fifo));
+ DECODER_FIFO_INCSTART (*p_ac3dec->p_fifo);
}
/* Waiting for the input thread to put new PES packets in the fifo */
- vlc_cond_wait (&p_ac3dec->fifo.data_wait, &p_ac3dec->fifo.data_lock);
+ vlc_cond_wait (&p_ac3dec->p_fifo->data_wait,
+ &p_ac3dec->p_fifo->data_lock);
}
/* We can release the lock before leaving */
- vlc_mutex_unlock (&p_ac3dec->fifo.data_lock);
+ vlc_mutex_unlock (&p_ac3dec->p_fifo->data_lock);
}
/*****************************************************************************
{
/* We were reading the last TS packet of this PES packet... It's
* time to jump to the next PES packet */
- if (p_ac3dec->p_ts->p_next_ts == NULL)
+ if (p_ac3dec->p_data->p_next == NULL)
{
int ptr;
/* We are going to read/write the start and end indexes of the
* decoder fifo and to use the fifo's conditional variable,
* that's why we need to take the lock before */
- vlc_mutex_lock (&p_ac3dec->fifo.data_lock);
+ vlc_mutex_lock (&p_ac3dec->p_fifo->data_lock);
/* Is the input thread dying ? */
- if (p_ac3dec->p_input->b_die)
+ if (p_ac3dec->p_fifo->b_die)
{
- vlc_mutex_unlock (&(p_ac3dec->fifo.data_lock));
+ vlc_mutex_unlock (&p_ac3dec->p_fifo->data_lock);
return;
}
* pointer to the current PES packet, and we weren't able to
* give it back to the netlist. That's why we free the PES
* packet first. */
- input_NetlistFreePES (p_ac3dec->p_input, DECODER_FIFO_START(p_ac3dec->fifo));
+ p_ac3dec->p_fifo->pf_delete_pes(p_ac3dec->p_fifo->p_packets_mgt,
+ DECODER_FIFO_START(*p_ac3dec->p_fifo));
- DECODER_FIFO_INCSTART (p_ac3dec->fifo);
+ DECODER_FIFO_INCSTART (*p_ac3dec->p_fifo);
- while (DECODER_FIFO_ISEMPTY(p_ac3dec->fifo))
+ while (DECODER_FIFO_ISEMPTY(*p_ac3dec->p_fifo))
{
- vlc_cond_wait (&p_ac3dec->fifo.data_wait, &p_ac3dec->fifo.data_lock);
+ vlc_cond_wait(&p_ac3dec->p_fifo->data_wait, &p_ac3dec->p_fifo->data_lock);
- if (p_ac3dec->p_input->b_die)
+ if (p_ac3dec->p_fifo->b_die)
{
- vlc_mutex_unlock (&(p_ac3dec->fifo.data_lock));
+ vlc_mutex_unlock (&p_ac3dec->p_fifo->data_lock);
return;
}
}
/* The next byte could be found in the next PES packet */
- p_ac3dec->p_ts = DECODER_FIFO_START (p_ac3dec->fifo)->p_first_ts;
+ p_ac3dec->p_data = DECODER_FIFO_START(*p_ac3dec->p_fifo)->p_first;
/* parse ac3 magic header */
- ptr = p_ac3dec->p_ts->buffer [p_ac3dec->p_ts->i_payload_start+2];
+ ptr = *(p_ac3dec->p_data->p_payload_start + 2);
ptr <<= 8;
- ptr |= p_ac3dec->p_ts->buffer [p_ac3dec->p_ts->i_payload_start+3];
+ ptr |= *(p_ac3dec->p_data->p_payload_start + 3);
p_ac3dec->sync_ptr = ptr;
- p_ac3dec->p_ts->i_payload_start += 4;
+ p_ac3dec->p_data->p_payload_start += 4;
/* We can release the fifo's data lock */
- vlc_mutex_unlock (&p_ac3dec->fifo.data_lock);
+ vlc_mutex_unlock (&p_ac3dec->p_fifo->data_lock);
}
/* Perhaps the next TS packet of the current PES packet contains
* real data (ie its payload's size is greater than 0) */
else
{
- p_ac3dec->p_ts = p_ac3dec->p_ts->p_next_ts;
+ p_ac3dec->p_data = p_ac3dec->p_data->p_next;
}
- } while (p_ac3dec->p_ts->i_payload_start == p_ac3dec->p_ts->i_payload_end);
- p_byte_stream->p_byte =
- p_ac3dec->p_ts->buffer + p_ac3dec->p_ts->i_payload_start;
- p_byte_stream->p_end =
- p_ac3dec->p_ts->buffer + p_ac3dec->p_ts->i_payload_end;
+ } while (p_ac3dec->p_data->p_payload_start == p_ac3dec->p_data->p_payload_end);
+ p_byte_stream->p_byte = p_ac3dec->p_data->p_payload_start;
+ p_byte_stream->p_end = p_ac3dec->p_data->p_payload_end;
}
/*
* Input properties
*/
- decoder_fifo_t fifo; /* stores the PES stream data */
- input_thread_t * p_input;
- ts_packet_t * p_ts;
- int sync_ptr; /* sync ptr from ac3 magic header */
+ decoder_fifo_t * p_fifo; /* stores the PES stream data */
+ data_packet_t * p_data;
+ int sync_ptr; /* sync ptr from ac3 magic header */
+ adec_config_t * p_config;
/*
* Decoder properties
/*****************************************************************************
* Prototypes
*****************************************************************************/
-ac3dec_thread_t * ac3dec_CreateThread( input_thread_t * p_input );
-void ac3dec_DestroyThread( ac3dec_thread_t * p_ac3dec );
+vlc_thread_t ac3dec_CreateThread( adec_config_t * p_config );
#include "debug.h" /* "input_netlist.h" */
#include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */
-
-#include "input.h" /* pes_packet_t */
-#include "input_netlist.h" /* input_NetlistFreePES() */
-#include "decoder_fifo.h" /* DECODER_FIFO_(ISEMPTY|START|INCSTART)() */
+
+#include "stream_control.h"
+#include "input_ext-dec.h"
#include "audio_output.h" /* aout_fifo_t (for audio_decoder.h) */
* This function creates a new audio decoder thread, and returns a pointer to
* its description. On error, it returns NULL.
*****************************************************************************/
-adec_thread_t * adec_CreateThread ( input_thread_t * p_input )
+vlc_thread_t adec_CreateThread ( adec_config_t * p_config )
{
adec_thread_t * p_adec;
if ( (p_adec = (adec_thread_t *)malloc (sizeof(adec_thread_t))) == NULL )
{
intf_ErrMsg ( "adec error: not enough memory for adec_CreateThread() to create the new thread\n" );
- return NULL;
+ return 0;
}
/*
*/
p_adec->b_die = 0;
p_adec->b_error = 0;
+ p_adec->p_config = p_config;
+ p_adec->p_fifo = p_config->decoder_config.p_decoder_fifo;
- /*
- * Initialize the input properties
- */
- /* Initialize the decoder fifo's data lock and conditional variable and set
- * its buffer as empty */
- vlc_mutex_init ( &p_adec->fifo.data_lock );
- vlc_cond_init ( &p_adec->fifo.data_wait );
- p_adec->fifo.i_start = 0;
- p_adec->fifo.i_end = 0;
-
- /* Initialize the bit stream structure */
- p_adec->p_input = p_input;
/*
* Initialize the decoder properties
/*
* Initialize the output properties
*/
- p_adec->p_aout = p_input->p_aout;
+ p_adec->p_aout = p_config->p_aout;
p_adec->p_aout_fifo = NULL;
/* Spawn the audio decoder thread */
{
intf_ErrMsg ("adec error: can't spawn audio decoder thread\n");
free (p_adec);
- return NULL;
+ return 0;
}
intf_DbgMsg ("adec debug: audio decoder thread (%p) created\n", p_adec);
- return p_adec;
-}
-
-/*****************************************************************************
- * adec_DestroyThread: destroys an audio decoder thread
- *****************************************************************************
- * This function asks an audio decoder thread to terminate. This function has
- * not to wait until the decoder thread has really died, because the killer (ie
- * this function's caller) is the input thread, that's why we are sure that no
- * other thread will try to access to this thread's descriptor after its
- * destruction.
- *****************************************************************************/
-void adec_DestroyThread (adec_thread_t * p_adec)
-{
- intf_DbgMsg ("adec debug: requesting termination of audio decoder thread %p\n", p_adec);
-
- /* Ask thread to kill itself */
- p_adec->b_die = 1;
-
- /* Make sure the decoder thread leaves the GetByte() function */
- vlc_mutex_lock (&(p_adec->fifo.data_lock));
- vlc_cond_signal (&(p_adec->fifo.data_wait));
- vlc_mutex_unlock (&(p_adec->fifo.data_lock));
-
- /* Waiting for the decoder thread to exit */
- /* Remove this as soon as the "status" flag is implemented */
- vlc_thread_join (p_adec->thread_id);
+ return p_adec->thread_id;
}
/*****************************************************************************
/* Our first job is to initialize the bit stream structure with the
* beginning of the input stream */
- vlc_mutex_lock ( &p_adec->fifo.data_lock );
- while ( DECODER_FIFO_ISEMPTY(p_adec->fifo) )
+ vlc_mutex_lock ( &p_adec->p_fifo->data_lock );
+ while ( DECODER_FIFO_ISEMPTY(*p_adec->p_fifo) )
{
if (p_adec->b_die)
{
- vlc_mutex_unlock ( &p_adec->fifo.data_lock );
+ vlc_mutex_unlock ( &p_adec->p_fifo->data_lock );
return -1;
}
- vlc_cond_wait ( &p_adec->fifo.data_wait, &p_adec->fifo.data_lock );
+ vlc_cond_wait ( &p_adec->p_fifo->data_wait, &p_adec->p_fifo->data_lock );
}
- p_adec->p_ts = DECODER_FIFO_START ( p_adec->fifo )->p_first_ts;
+ p_adec->p_data = DECODER_FIFO_START ( *p_adec->p_fifo )->p_first;
byte_stream = adec_byte_stream ( &p_adec->audio_decoder );
- byte_stream->p_byte =
- p_adec->p_ts->buffer + p_adec->p_ts->i_payload_start;
- byte_stream->p_end =
- p_adec->p_ts->buffer + p_adec->p_ts->i_payload_end;
+ byte_stream->p_byte = p_adec->p_data->p_payload_start;
+ byte_stream->p_end = p_adec->p_data->p_payload_end;
byte_stream->info = p_adec;
- vlc_mutex_unlock ( &p_adec->fifo.data_lock );
+ vlc_mutex_unlock ( &p_adec->p_fifo->data_lock );
aout_fifo.i_type = AOUT_ADEC_STEREO_FIFO;
aout_fifo.i_channels = 2;
intf_DbgMsg ( "adec debug: running audio decoder thread (%p) (pid == %i)\n", p_adec, getpid() );
- msleep ( INPUT_PTS_DELAY );
+ /* You really suck */
+ //msleep ( INPUT_PTS_DELAY );
/* Initializing the audio decoder thread */
if( InitThread (p_adec) )
sync = 1;
}
- if( DECODER_FIFO_START( p_adec->fifo)->b_has_pts )
+ if( DECODER_FIFO_START( *p_adec->p_fifo)->b_has_pts )
{
p_adec->p_aout_fifo->date[p_adec->p_aout_fifo->l_end_frame] =
- DECODER_FIFO_START( p_adec->fifo )->i_pts;
- DECODER_FIFO_START(p_adec->fifo)->b_has_pts = 0;
+ DECODER_FIFO_START( *p_adec->p_fifo )->i_pts;
+ DECODER_FIFO_START(*p_adec->p_fifo)->b_has_pts = 0;
}
else
{
{
/* We take the lock, because we are going to read/write the start/end
* indexes of the decoder fifo */
- vlc_mutex_lock ( &p_adec->fifo.data_lock );
+ vlc_mutex_lock ( &p_adec->p_fifo->data_lock );
/* Wait until a `die' order is sent */
while ( !p_adec->b_die )
{
/* Trash all received PES packets */
- while ( !DECODER_FIFO_ISEMPTY(p_adec->fifo) )
+ while ( !DECODER_FIFO_ISEMPTY(*p_adec->p_fifo) )
{
- input_NetlistFreePES ( p_adec->p_input,
- DECODER_FIFO_START(p_adec->fifo) );
- DECODER_FIFO_INCSTART ( p_adec->fifo );
+ p_adec->p_fifo->pf_delete_pes ( p_adec->p_fifo->p_packets_mgt,
+ DECODER_FIFO_START(*p_adec->p_fifo) );
+ DECODER_FIFO_INCSTART ( *p_adec->p_fifo );
}
/* Waiting for the input thread to put new PES packets in the fifo */
- vlc_cond_wait ( &p_adec->fifo.data_wait, &p_adec->fifo.data_lock );
+ vlc_cond_wait ( &p_adec->p_fifo->data_wait, &p_adec->p_fifo->data_lock );
}
/* We can release the lock before leaving */
- vlc_mutex_unlock ( &p_adec->fifo.data_lock );
+ vlc_mutex_unlock ( &p_adec->p_fifo->data_lock );
}
/*****************************************************************************
{
/* We were reading the last TS packet of this PES packet... It's
* time to jump to the next PES packet */
- if (p_adec->p_ts->p_next_ts == NULL)
+ if (p_adec->p_data->p_next == NULL)
{
/* We are going to read/write the start and end indexes of the
* decoder fifo and to use the fifo's conditional variable,
* that's why we need to take the lock before */
- vlc_mutex_lock (&p_adec->fifo.data_lock);
+ vlc_mutex_lock (&p_adec->p_fifo->data_lock);
/* Is the input thread dying ? */
- if (p_adec->p_input->b_die)
+ if (p_adec->p_fifo->b_die)
{
- vlc_mutex_unlock (&(p_adec->fifo.data_lock));
+ vlc_mutex_unlock (&(p_adec->p_fifo->data_lock));
return;
}
* pointer to the current PES packet, and we weren't able to
* give it back to the netlist. That's why we free the PES
* packet first. */
- input_NetlistFreePES (p_adec->p_input, DECODER_FIFO_START(p_adec->fifo));
- DECODER_FIFO_INCSTART (p_adec->fifo);
+ p_adec->p_fifo->pf_delete_pes (p_adec->p_fifo->p_packets_mgt,
+ DECODER_FIFO_START(*p_adec->p_fifo));
+ DECODER_FIFO_INCSTART (*p_adec->p_fifo);
- while (DECODER_FIFO_ISEMPTY(p_adec->fifo))
+ while (DECODER_FIFO_ISEMPTY(*p_adec->p_fifo))
{
- vlc_cond_wait (&p_adec->fifo.data_wait, &p_adec->fifo.data_lock);
- if (p_adec->p_input->b_die)
+ vlc_cond_wait (&p_adec->p_fifo->data_wait, &p_adec->p_fifo->data_lock);
+ if (p_adec->p_fifo->b_die)
{
- vlc_mutex_unlock (&(p_adec->fifo.data_lock));
+ vlc_mutex_unlock (&(p_adec->p_fifo->data_lock));
return;
}
}
/* The next byte could be found in the next PES packet */
- p_adec->p_ts = DECODER_FIFO_START (p_adec->fifo)->p_first_ts;
- if (DECODER_FIFO_START (p_adec->fifo)->b_data_alignment)
+ p_adec->p_data = DECODER_FIFO_START (*p_adec->p_fifo)->p_first;
+ if (DECODER_FIFO_START (*p_adec->p_fifo)->b_data_alignment)
{
p_adec->align = 1;
}
/* We can release the fifo's data lock */
- vlc_mutex_unlock (&p_adec->fifo.data_lock);
+ vlc_mutex_unlock (&p_adec->p_fifo->data_lock);
}
/* Perhaps the next TS packet of the current PES packet contains
* real data (ie its payload's size is greater than 0) */
else
{
- p_adec->p_ts = p_adec->p_ts->p_next_ts;
+ p_adec->p_data = p_adec->p_data->p_next;
}
- } while (p_adec->p_ts->i_payload_start == p_adec->p_ts->i_payload_end);
+ } while (p_adec->p_data->p_payload_start == p_adec->p_data->p_payload_end);
/* We've found a TS packet which contains interesting data... */
- p_byte_stream->p_byte =
- p_adec->p_ts->buffer + p_adec->p_ts->i_payload_start;
- p_byte_stream->p_end =
- p_adec->p_ts->buffer + p_adec->p_ts->i_payload_end;
+ p_byte_stream->p_byte = p_adec->p_data->p_payload_start;
+ p_byte_stream->p_end = p_adec->p_data->p_payload_end;
}
/*
* Input properties
*/
- decoder_fifo_t fifo; /* stores the PES stream data */
- input_thread_t * p_input;
- ts_packet_t * p_ts;
- int align;
+ decoder_fifo_t * p_fifo; /* stores the PES stream data */
+ data_packet_t * p_data;
+ int align;
+ adec_config_t * p_config;
+
/*
* Decoder properties
/*****************************************************************************
* Prototypes
*****************************************************************************/
-adec_thread_t * adec_CreateThread ( input_thread_t * p_input /* !! , aout_thread_t * p_aout !! */ );
-void adec_DestroyThread ( adec_thread_t * p_adec );
+vlc_thread_t adec_CreateThread ( adec_config_t * p_config );
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
*
- * Authors: Christophe Massiot <massiot@via.ecp.fr>
- * Benoît Steiner <benny@via.ecp.fr>
+ * Authors:
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*****************************************************************************/
#include "defs.h"
-#include <errno.h> /* errno */
-#include <sys/types.h> /* on BSD, uio.h needs types.h */
-#include <sys/uio.h> /* "input.h" */
-#include <string.h> /* strerror() */
-
-#include <stdlib.h> /* free() */
-#include <netinet/in.h> /* ntohs() */
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
#include "config.h"
#include "common.h"
#include "threads.h"
#include "mtime.h"
-#include "intf_msg.h"
-#include "plugins.h"
-#include "debug.h"
-
-#include "input.h"
-#include "input_psi.h"
-#include "input_pcr.h"
-#include "input_netlist.h"
-#include "decoder_fifo.h"
-#include "input_file.h"
-#include "input_network.h"
-
-#include "audio_output.h" /* aout_thread_t */
-
-#include "audio_decoder.h" /* audiodec_t (for audio_decoder_thread.h) */
-#include "audio_decoder_thread.h" /* adec_thread_t */
-
-#include "ac3_decoder.h" /* ac3dec_t (for ac3_decoder_thread.h) */
-#include "ac3_decoder_thread.h" /* ac3dec_thread_t */
-#include "lpcm_decoder.h"
-#include "lpcm_decoder_thread.h"
-
-#include "video.h" /* picture_t (for video_output.h) */
-#include "video_output.h" /* vout_thread_t */
-
-#include "vdec_idct.h" /* dctelem_t (for video_parser.h) */
-#include "vdec_motion.h" /* f_motion_t (for video_parser.h) */
-#include "vpar_blocks.h" /* macroblock_t (for video_parser.h) */
-#include "vpar_headers.h" /* sequence_t (for video_parser.h) */
-#include "vpar_synchro.h" /* video_synchro_t (for video_parser.h) */
-#include "video_parser.h" /* vpar_thread_t */
+#include "intf_msg.h"
-#include "spu_decoder.h" /* spudec_thread_t */
+#include "stream_control.h"
+#include "input_ext-intf.h"
+#include "input_ext-dec.h"
-#include "main.h"
+#include "input.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static void RunThread ( input_thread_t *p_input );
+static void InitThread ( input_thread_t *p_input );
static void ErrorThread ( input_thread_t *p_input );
static void EndThread ( input_thread_t *p_input );
-
-static __inline__ int input_ReadPacket( input_thread_t *p_input );
-static __inline__ void input_SortPacket( input_thread_t *p_input,
- ts_packet_t *ts_packet );
-static __inline__ void input_DemuxTS( input_thread_t *p_input,
- ts_packet_t *ts_packet,
- es_descriptor_t *es_descriptor );
-static __inline__ void input_DemuxPES( input_thread_t *p_input,
- ts_packet_t *ts_packet,
- es_descriptor_t *p_es_descriptor,
- boolean_t b_unit_start,
- boolean_t b_packet_lost );
-static __inline__ void input_ParsePES( input_thread_t *p_input,
- es_descriptor_t *p_es_descriptor );
-static __inline__ void input_DemuxPSI( input_thread_t *p_input,
- ts_packet_t *ts_packet,
- es_descriptor_t *p_es_descriptor,
- boolean_t b_unit_start,
- boolean_t b_packet_lost );
+static void NetworkOpen ( input_thread_t *p_input );
+static void FileOpen ( input_thread_t *p_input );
/*****************************************************************************
* input_CreateThread: creates a new input thread
* If pi_status is NULL, then the function will block until the thread is ready.
* If not, it will be updated using one of the THREAD_* constants.
*****************************************************************************/
-input_thread_t *input_CreateThread ( int i_method, void *p_source, int i_port,
- int i_vlan, p_vout_thread_t p_vout,
- p_aout_thread_t p_aout, int *pi_status )
+input_thread_t *input_CreateThread ( input_config_t * p_config, int *pi_status )
{
input_thread_t * p_input; /* thread descriptor */
int i_status; /* thread status */
- int i_index; /* index for tables initialization */
+ int i;
/* Allocate descriptor */
intf_DbgMsg("\n");
p_input = (input_thread_t *)malloc( sizeof(input_thread_t) );
if( p_input == NULL )
{
- intf_ErrMsg("error: %s\n", strerror(ENOMEM));
+ intf_ErrMsg("error: %s\n", strerror(errno));
+ free( p_config );
return( NULL );
}
/* Initialize thread properties */
p_input->b_die = 0;
p_input->b_error = 0;
+ /* I have never understood that stuff --Meuuh */
p_input->pi_status = (pi_status != NULL) ? pi_status : &i_status;
*p_input->pi_status = THREAD_CREATE;
-
- /* Initialize input method description */
- p_input->i_method = i_method;
- p_input->p_source = p_source;
- p_input->i_port = i_port;
- p_input->i_vlan = i_vlan;
- switch( i_method )
- {
- case INPUT_METHOD_TS_FILE: /* file methods */
- p_input->p_Open = input_FileOpen;
- p_input->p_Read = input_FileRead;
- p_input->p_Close = input_FileClose;
- break;
- case INPUT_METHOD_TS_VLAN_BCAST: /* vlan network method */
- if( !p_main->b_vlans )
- {
- intf_ErrMsg("error: vlans are not activated\n");
- free( p_input );
- return( NULL );
- }
- /* ... pass through */
- case INPUT_METHOD_TS_UCAST: /* network methods */
- case INPUT_METHOD_TS_MCAST:
- case INPUT_METHOD_TS_BCAST:
- p_input->p_Open = input_NetworkOpen;
- p_input->p_Read = input_NetworkRead;
- p_input->p_Close = input_NetworkClose;
- break;
- default:
- intf_ErrMsg("error: unknow input method\n");
- free( p_input );
- return( NULL );
- break;
- }
+ p_input->p_config = p_config;
/* Initialize stream description */
- for( i_index = 0; i_index < INPUT_MAX_ES; i_index++ )
- {
- p_input->p_es[i_index].i_id = EMPTY_PID;
- p_input->pp_selected_es[i_index] = NULL;
- }
-
- /* Initialize default settings for spawned decoders */
- p_input->p_aout = p_aout;
- p_input->p_vout = p_vout;
-
-#ifdef STATS
- /* Initialize statistics */
- p_input->c_loops = 0;
- p_input->c_bytes = 0;
- p_input->c_payload_bytes = 0;
- p_input->c_packets_read = 0;
- p_input->c_packets_trashed = 0;
-#endif
-
- /* Initialize PSI and PCR decoders */
- if( input_PsiInit( p_input ) )
- {
- free( p_input );
- return( NULL );
- }
-
- if( input_PcrInit( p_input ) )
+ for( i = 0; i < INPUT_MAX_SELECTED_ES; i++ )
{
- input_PsiEnd( p_input );
- free( p_input );
- return( NULL );
+ p_input->pp_selected_es[i] = NULL;
}
-
- /* Initialize netlists */
- if( input_NetlistInit( p_input ) )
+ for( i= 0; i < INPUT_MAX_ES; i++ )
{
- input_PsiEnd( p_input );
- input_PcrEnd( p_input );
- free( p_input );
- return( NULL );
+ p_input->p_es[i].i_id = EMPTY_ID;
}
+ p_input->stream.i_pgrm_number = 0;
- intf_DbgMsg("configuration: method=%d, source=%s, port=%d, vlan=%d\n",
- i_method, p_source, i_port, i_vlan );
-
- /* Let the appropriate method open the socket. */
- if( p_input->p_Open( p_input ) )
- {
- input_NetlistEnd( p_input );
- input_PsiEnd( p_input );
- input_PcrEnd( p_input );
- free( p_input );
- return( NULL );
- }
+ /* Initialize stream control properties. */
+ p_input->stream.control.i_status = PLAYING_S;
+ p_input->stream.control.i_rate = DEFAULT_RATE;
+ p_input->stream.control.i_ref_sysdate = 0;
+ p_input->stream.control.i_ref_clock = 0;
+ p_input->stream.control.b_mute = 0;
+ p_input->stream.control.b_bw = 0;
/* Create thread and set locks. */
- vlc_mutex_init( &p_input->netlist.lock );
- vlc_mutex_init( &p_input->programs_lock );
- vlc_mutex_init( &p_input->es_lock );
- if( vlc_thread_create(&p_input->thread_id, "input", (void *) RunThread, (void *) p_input) )
+ vlc_mutex_init( &p_input->stream.stream_lock );
+ vlc_mutex_init( &p_input->stream.control.control_lock );
+ if( vlc_thread_create( &p_input->thread_id, "input", (void *) RunThread,
+ (void *) p_input ) )
{
intf_ErrMsg("error: %s\n", strerror(errno) );
- p_input->p_Close( p_input );
- input_NetlistEnd( p_input );;
- input_PsiEnd( p_input );
- input_PcrEnd( p_input );
free( p_input );
+ free( p_config );
return( NULL );
}
- intf_Msg("Input initialized\n");
-
/* If status is NULL, wait until the thread is created */
if( pi_status == NULL )
{
do
{
msleep( THREAD_SLEEP );
- }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
+ } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
&& (i_status != THREAD_FATAL) );
if( i_status != THREAD_READY )
{
do
{
msleep( THREAD_SLEEP );
- }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
- && (i_status != THREAD_FATAL) );
+ } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
+ && (i_status != THREAD_FATAL) );
}
}
-#if 0
-/*****************************************************************************
- * input_OpenAudioStream: open an audio stream
- *****************************************************************************
- * This function spawns an audio decoder and plugs it on the audio output
- * thread.
- *****************************************************************************/
-int input_OpenAudioStream( input_thread_t *p_input, int i_id )
-{
- /* XXX?? */
-}
-
/*****************************************************************************
- * input_CloseAudioStream: close an audio stream
+ * RunThread: main thread loop
*****************************************************************************
- * This function destroys an audio decoder.
+ * Thread in charge of processing the network packets and demultiplexing.
*****************************************************************************/
-void input_CloseAudioStream( input_thread_t *p_input, int i_id )
+static void RunThread( input_thread_t *p_input )
{
- /* XXX?? */
-}
+ data_packet_t * pp_packets[INPUT_READ_ONCE];
-/*****************************************************************************
- * input_OpenVideoStream: open a video stream
- *****************************************************************************
- * This function spawns a video decoder and plugs it on a video output thread.
- *****************************************************************************/
-int input_OpenVideoStream( input_thread_t *p_input,
- struct vout_thread_s *p_vout, struct video_cfg_s * p_cfg )
-{
- /* XXX?? */
-}
+ InitThread( p_input );
-/*****************************************************************************
- * input_CloseVideoStream: close a video stream
- *****************************************************************************
- * This function destroys an video decoder.
- *****************************************************************************/
-void input_CloseVideoStream( input_thread_t *p_input, int i_id )
-{
- /* XXX?? */
-}
+ while( !p_input->b_die && !p_input->b_error )
+ {
+#ifdef STATS
+ p_input->c_loops++;
#endif
-/* following functions are local */
-
-/*****************************************************************************
- * InitThread: initialize input thread
- *****************************************************************************
- * This function is called from RunThread and performs the second step of the
- * initialization. It returns 0 on success. Note that the thread's flag are not
- * modified inside this function.
- *****************************************************************************/
-static int InitThread( input_thread_t *p_input )
-{
- /* Mark thread as running and return */
- intf_DbgMsg("\n");
- *p_input->pi_status = THREAD_READY;
- intf_DbgMsg("thread ready\n");
- return( 0 );
-}
-
-/*****************************************************************************
- * input_DemuxPSI:
- *****************************************************************************
- * Notice that current ES state has been locked by input_SortPacket.
- * (No more true, changed by benny - FIXME: See if it's ok, and definitely
- * change the code ?? )
- *****************************************************************************/
-static __inline__ void input_DemuxPSI( input_thread_t *p_input,
- ts_packet_t *p_ts_packet,
- es_descriptor_t *p_es_descriptor,
- boolean_t b_unit_start,
- boolean_t b_packet_lost )
-{
- int i_data_offset; /* Offset of the interesting data in the TS packet */
- u16 i_data_length; /* Length of those data */
- //boolean_t b_first_section; /* another section in the TS packet ? */
-
- ASSERT(p_input);
- ASSERT(p_ts_packet);
- ASSERT(p_es_descriptor);
-
-#define p_psi (p_es_descriptor->p_psi_section)
-
- //intf_DbgMsg( "input debug: PSI demultiplexing %p (%p)\n", p_ts_packet, p_input);
-
- //intf_DbgMsg( "Packet: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x (unit start: %d)\n", p_ts_packet->buffer[p_ts_packet->i_payload_start], p_ts_packet->buffer[p_ts_packet->i_payload_start+1], p_ts_packet->buffer[p_ts_packet->i_payload_start+2], p_ts_packet->buffer[p_ts_packet->i_payload_start+3], p_ts_packet->buffer[p_ts_packet->i_payload_start+4], p_ts_packet->buffer[p_ts_packet->i_payload_start+5], p_ts_packet->buffer[p_ts_packet->i_payload_start+6], p_ts_packet->buffer[p_ts_packet->i_payload_start+7], p_ts_packet->buffer[p_ts_packet->i_payload_start+8], p_ts_packet->buffer[p_ts_packet->i_payload_start+9], p_ts_packet->buffer[p_ts_packet->i_payload_start+10], p_ts_packet->buffer[p_ts_packet->i_payload_start+11], p_ts_packet->buffer[p_ts_packet->i_payload_start+12], p_ts_packet->buffer[p_ts_packet->i_payload_start+13], p_ts_packet->buffer[p_ts_packet->i_payload_start+14], p_ts_packet->buffer[p_ts_packet->i_payload_start+15], p_ts_packet->buffer[p_ts_packet->i_payload_start+16], p_ts_packet->buffer[p_ts_packet->i_payload_start+17], p_ts_packet->buffer[p_ts_packet->i_payload_start+18], p_ts_packet->buffer[p_ts_packet->i_payload_start+19], p_ts_packet->buffer[p_ts_packet->i_payload_start+20], b_unit_start);
-
-
- /* Try to find the beginning of the payload in the packet to initialise
- * the do-while loop that follows -> Compute the i_data_offset variable:
- * by default, the value is set so that we won't enter in the while loop.
- * It will be set to a correct value if the data are not corrupted */
- i_data_offset = TS_PACKET_SIZE;
-
- /* Has the reassembly of a section already begun in a previous packet ? */
- if( p_psi->b_running_section )
- {
- /* Was data lost since the last TS packet ? */
- if( b_packet_lost )
- {
- /* Discard the packet and wait for the begining of a new one
- * to resynch */
- p_psi->b_running_section = 0;
- p_psi->i_current_position = 0;
- intf_DbgMsg( "PSI section(s) discarded due to packet loss\n" );
- }
- else
- {
- /* The data that complete a previously began section are always at
- * the beginning of the TS payload... */
- i_data_offset = p_ts_packet->i_payload_start;
- /* ...Unless there is a pointer field, that we have to bypass */
- if( b_unit_start )
- i_data_offset++;
- //intf_DbgMsg( "New part of the section received at offset %d\n", i_data_offset );
- }
- }
- /* We are looking for the beginning of a new section */
- else
- {
- if( b_unit_start )
- {
- /* Get the offset at which the data for that section can be found
- * The offset is stored in the pointer_field since we are
- * interested in the first section of the TS packet. Note that
- * the +1 is to bypass the pointer field */
- i_data_offset = p_ts_packet->i_payload_start +
- p_ts_packet->buffer[p_ts_packet->i_payload_start] + 1;
- //intf_DbgMsg( "New section beginning at offset %d in TS packet\n", i_data_offset );
- }
- else
+ vlc_mutex_lock( &p_input->stream.control.control_lock );
+ if( p_input->stream.control.i_status == BACKWARD_S
+ && p_input->p_plugin->pf_rewind != NULL )
{
- /* This may either mean that the TS is bad or that the packet
- * contains the end of a section that had been discarded in a
- * previous loop: trash the TS packet since we cannot do
- * anything with those data: */
- p_psi->b_running_section = 0;
- p_psi->i_current_position = 0;
- intf_DbgMsg( "PSI packet discarded due to lack of synchronisation\n" );
+ p_input->p_plugin->pf_rewind( p_input );
+ /* FIXME: probably don't do it every loop, but when ? */
}
- }
-
- /* The section we will deal with during the first iteration of the
- * following loop is the first one contained in the TS packet */
- // b_first_section = 1;
+ vlc_mutex_unlock( &p_input->stream.control.control_lock );
- /* Reassemble the pieces of sections contained in the TS packet and
- * decode the sections that could have been completed.
- * Stop when we reach the end of the packet or stuffing bytes */
- while( i_data_offset < TS_PACKET_SIZE && p_ts_packet->buffer[i_data_offset] != 0xFF )
- {
- /* If the current section is a new one, reinit the data fields of
- * the p_psi struct to start its decoding */
- if( !p_psi->b_running_section )
+ p_input->p_plugin->pf_read( p_input, pp_packets );
+ if( !p_input->b_error )
{
- /* Read the length of the new section */
- p_psi->i_length = (U16_AT(&p_ts_packet->buffer[i_data_offset+1]) & 0xFFF) + 3;
- //intf_DbgMsg( "Section length %d\n", p_psi->i_length );
- if( p_psi->i_length > PSI_SECTION_SIZE )
+ int i;
+
+ for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
{
- /* The TS packet is corrupted, stop here to avoid possible
- * a seg fault */
- intf_DbgMsg( "PSI Section size is too big, aborting its reception\n" );
- break;
+ p_input->p_plugin->pf_demux( p_input, pp_packets[i] );
}
-
- /* Init the reassembly of that section */
- p_psi->b_running_section = 1;
- p_psi->i_current_position = 0;
- }
-
- /* Compute the length of data related to the section in this TS packet */
- if( p_psi->i_length - p_psi->i_current_position > TS_PACKET_SIZE - i_data_offset)
- i_data_length = TS_PACKET_SIZE - i_data_offset;
- else
- i_data_length = p_psi->i_length - p_psi->i_current_position;
-
- /* Copy those data in the section buffer */
- memcpy( &p_psi->buffer[p_psi->i_current_position], &p_ts_packet->buffer[i_data_offset],
- i_data_length );
-
- /* Interesting data are now after the ones we copied, since no gap is
- * allowed between 2 sections in a TS packets */
- i_data_offset += i_data_length;
-
- /* Decode the packet if it is now complete */
- if (p_psi->i_length == p_psi->i_current_position + i_data_length)
- {
- /* Packet is complete, decode it */
- //intf_DbgMsg( "SECTION COMPLETE: starting decoding of its data\n" );
- input_PsiDecode( p_input, p_psi );
-
- /* Prepare the buffer to receive a new section */
- p_psi->i_current_position = 0;
- p_psi->b_running_section = 0;
-
- /* The new section won't be the first anymore */
- //b_first_section = 0;
- }
- else
- {
- /* Prepare the buffer to receive the next part of the section */
- p_psi->i_current_position += i_data_length;
- //intf_DbgMsg( "Section not complete, waiting for the end\n" );
}
-
- //intf_DbgMsg( "Must loop ? Next data offset: %d, stuffing: %d\n",
- // i_data_offset, p_ts_packet->buffer[i_data_offset] );
}
- /* Relase the TS packet, we don't need it anymore */
- input_NetlistFreeTS( p_input, p_ts_packet );
+ if( p_input->b_error )
+ {
+ ErrorThread( p_input );
+ }
-#undef p_psi
+ EndThread( p_input );
+ intf_DbgMsg("Thread end");
}
/*****************************************************************************
- * input_ParsePES
- *****************************************************************************
- * Parse a finished PES packet and analyze its header.
+ * InitThread: init the input thread
*****************************************************************************/
-static __inline__ void input_ParsePES( input_thread_t *p_input,
- es_descriptor_t *p_es_descriptor )
+input_capabilities_t * PSKludge( void );
+static void InitThread( input_thread_t * p_input )
{
- decoder_fifo_t * p_fifo;
- u8 i_pes_header_size;
- ts_packet_t * p_ts;
- int i_ts_payload_size;
-
-
-#define p_pes (p_es_descriptor->p_pes_packet)
-
- //intf_DbgMsg("End of PES packet %p\n", p_pes);
-
- /* First read the 6 header bytes common to all PES packets:
- use them to test the PES validity */
- if( (p_pes->p_pes_header[0] || p_pes->p_pes_header[1] ||
- (p_pes->p_pes_header[2] != 1)) ||
- /* packet_start_code_prefix != 0x000001 */
- ((p_pes->i_pes_real_size) &&
- (p_pes->i_pes_real_size != p_pes->i_pes_size)) )
- /* PES_packet_length is set and != total received payload */
- {
- /* Trash the packet and set p_pes to NULL to be sure the next PES
- packet will have its b_data_lost flag set */
- intf_DbgMsg("Corrupted PES packet (size doesn't match) : trashed\n");
- input_NetlistFreePES( p_input, p_pes );
- p_pes = NULL;
- /* Stats XXX?? */
- }
- else
- {
- /* The PES packet is valid. Check its type to test if it may
- carry additional informations in a header extension */
- p_pes->i_stream_id = p_pes->p_pes_header[3];
-
- switch( p_pes->i_stream_id )
- {
- case 0xBE: /* Padding */
- case 0xBC: /* Program stream map */
- 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 immediatly after the 6 bytes header, so
- we have finished with the parsing */
- i_pes_header_size = 6;
- break;
-
- default:
- switch( p_pes->p_pes_header[8] & 0xc0 )
- {
- case 0x80: /* MPEG2: 10xx xxxx */
- case 0x00: /* FIXME: This shouldn't be allowed !! */
- /* The PES header contains at least 3 more bytes: parse them */
- p_pes->b_data_alignment = p_pes->p_pes_header[6] & 0x04;
- p_pes->b_has_pts = p_pes->p_pes_header[7] & 0x80;
- i_pes_header_size = p_pes->p_pes_header[8] + 9;
-
- /* Now parse the optional header extensions (in the limit of
- the 14 bytes */
- if( p_pes->b_has_pts )
- {
- pcr_descriptor_t * p_pcr;
-
- p_pcr = p_input->p_pcr;
-
- p_pes->i_pts =
- ( ((mtime_t)(p_pes->p_pes_header[9] & 0x0E) << 29) |
- (((mtime_t)U16_AT(p_pes->p_pes_header + 10) << 14) - (1 << 14)) |
- ((mtime_t)U16_AT(p_pes->p_pes_header + 12) >> 1) ) * 300;
- p_pes->i_pts /= 27;
-
- if( p_pcr->i_synchro_state )
- {
- switch( p_pcr->i_synchro_state )
- {
- case SYNCHRO_NOT_STARTED:
- p_pes->b_has_pts = 0;
- break;
-
- case SYNCHRO_START:
- p_pes->i_pts += p_pcr->delta_pcr;
- p_pcr->delta_absolute = mdate() - p_pes->i_pts + INPUT_PTS_DELAY;
- p_pes->i_pts += p_pcr->delta_absolute;
- p_pcr->i_synchro_state = 0;
- break;
-
- case SYNCHRO_REINIT: /* We skip a PES */
- p_pes->b_has_pts = 0;
- p_pcr->i_synchro_state = SYNCHRO_START;
- break;
- }
- }
- else
- {
- p_pes->i_pts += p_pcr->delta_pcr + p_pcr->delta_absolute;
- }
- }
- break;
-
- default: /* MPEG1 or some strange thing */
- /* since this isn't supported yet, we certainly gonna crash */
- intf_ErrMsg( "FIXME: unknown PES type %.2x\n",
- p_pes->p_pes_header[8] );
- i_pes_header_size = 6;
- break;
-
- }
- break;
- }
-
- /* Now we've parsed the header, we just have to indicate in some
- * specific TS packets where the PES payload begins (renumber
- * i_payload_start), so that the decoders can find the beginning
- * of their data right out of the box. */
- p_ts = p_pes->p_first_ts;
- i_ts_payload_size = p_ts->i_payload_end - p_ts->i_payload_start;
- while( i_pes_header_size > i_ts_payload_size )
- {
- /* These packets are entirely filled by the PES header. */
- i_pes_header_size -= i_ts_payload_size;
- p_ts->i_payload_start = p_ts->i_payload_end;
- /* Go to the next TS packet: here we won't have to test it is
- * not NULL because we trash the PES packets when packet lost
- * occurs */
- p_ts = p_ts->p_next_ts;
- i_ts_payload_size = p_ts->i_payload_end - p_ts->i_payload_start;
- }
- /* This last packet is partly header, partly payload. */
- p_ts->i_payload_start += i_pes_header_size;
-
-
- /* Now we can eventually put the PES packet in the decoder's
- * PES fifo */
- switch( p_es_descriptor->i_type )
- {
- case MPEG1_VIDEO_ES:
- case MPEG2_VIDEO_ES:
- p_fifo = &(((vpar_thread_t*)(p_es_descriptor->p_dec))->fifo);
- break;
-
- case MPEG1_AUDIO_ES:
- case MPEG2_AUDIO_ES:
- p_fifo = &(((adec_thread_t*)(p_es_descriptor->p_dec))->fifo);
- break;
-
- case AC3_AUDIO_ES:
- p_fifo = &(((ac3dec_thread_t *)(p_es_descriptor->p_dec))->fifo);
- break;
-
- case LPCM_AUDIO_ES:
- p_fifo = &(((lpcmdec_thread_t *)(p_es_descriptor->p_dec))->fifo);
- break;
-
- case DVD_SPU_ES:
- /* we skip the first byte at the beginning of the
- * subpicture payload, it only contains the SPU ID. */
- p_ts->i_payload_start++;
- p_fifo = &(((spudec_thread_t *)(p_es_descriptor->p_dec))->fifo);
- break;
-
- default:
- /* This should never happen */
- intf_DbgMsg("Unknown stream type (%d, %d): PES trashed\n",
- p_es_descriptor->i_id, p_es_descriptor->i_type);
- p_fifo = NULL;
- break;
- }
+ /* Initialize default settings for spawned decoders */
+ p_input->p_default_aout = p_input->p_config->p_default_aout;
+ p_input->p_default_vout = p_input->p_config->p_default_vout;
- if( p_fifo != NULL )
- {
- vlc_mutex_lock( &p_fifo->data_lock );
- if( DECODER_FIFO_ISFULL( *p_fifo ) )
- {
- /* The FIFO is full !!! This should not happen. */
#ifdef STATS
- p_input->c_packets_trashed += p_pes->i_ts_packets;
- p_es_descriptor->c_invalid_packets += p_pes->i_ts_packets;
+ /* Initialize statistics */
+ p_input->c_loops = 0;
+ p_input->c_bytes = 0;
+ p_input->c_payload_bytes = 0;
+ p_input->c_packets_read = 0;
+ p_input->c_packets_trashed = 0;
#endif
- input_NetlistFreePES( p_input, p_pes );
- intf_DbgMsg("PES trashed - fifo full ! (%d, %d)\n",
- p_es_descriptor->i_id, p_es_descriptor->i_type);
- }
- else
- {
- //intf_DbgMsg("Putting %p into fifo %p/%d\n",
- // p_pes, p_fifo, p_fifo->i_end);
- p_fifo->buffer[p_fifo->i_end] = p_pes;
- DECODER_FIFO_INCEND( *p_fifo );
- /* Warn the decoder that it's got work to do. */
- vlc_cond_signal( &p_fifo->data_wait );
- }
- vlc_mutex_unlock( &p_fifo->data_lock );
- }
- else
+ /* Use the appropriate input method */
+ switch( p_input->p_config->i_method )
+ {
+ case INPUT_METHOD_FILE: /* file methods */
+ FileOpen( p_input );
+ break;
+ case INPUT_METHOD_VLAN_BCAST: /* vlan network method */
+/* if( !p_main->b_vlans )
{
- intf_DbgMsg("No fifo to receive PES %p: trash\n", p_pes);
-#ifdef STATS
- p_input->c_packets_trashed += p_pes->i_ts_packets;
- p_es_descriptor->c_invalid_packets += p_pes->i_ts_packets;
+ intf_ErrMsg("error: vlans are not activated\n");
+ free( p_input );
+ return( NULL );
+ } */ /* la-lala */
+ /* ... pass through */
+ case INPUT_METHOD_UCAST: /* network methods */
+ case INPUT_METHOD_MCAST:
+ case INPUT_METHOD_BCAST:
+ NetworkOpen( p_input );
+ break;
+#ifdef DEBUG
+ default:
+ intf_ErrMsg("Unknow input method");
+ free( p_input->p_config );
+ p_input->b_error = 1;
+ break;
#endif
- input_NetlistFreePES( p_input, p_pes );
- }
}
-#undef p_pes
+
+ free( p_input->p_config );
+
+ /* Probe plugin (FIXME: load plugins before & write this) */
+ p_input->p_plugin = PSKludge();
+ p_input->p_plugin->pf_init( p_input );
+
+ *p_input->pi_status = THREAD_READY;
}
/*****************************************************************************
- * input_DemuxPES:
+ * ErrorThread: RunThread() error loop
*****************************************************************************
- * Gather a PES packet.
+ * This function is called when an error occured during thread main's loop.
*****************************************************************************/
-static __inline__ void input_DemuxPES( input_thread_t *p_input,
- ts_packet_t *p_ts_packet,
- es_descriptor_t *p_es_descriptor,
- boolean_t b_unit_start,
- boolean_t b_packet_lost )
+static void ErrorThread( input_thread_t *p_input )
{
- int i_dummy;
- pes_packet_t* p_last_pes;
- ts_packet_t * p_ts;
- int i_ts_payload_size;
-
-
-#define p_pes (p_es_descriptor->p_pes_packet)
-
- ASSERT(p_input);
- ASSERT(p_ts_packet);
- ASSERT(p_es_descriptor);
-
- //intf_DbgMsg("PES-demultiplexing %p (%p)\n", p_ts_packet, p_pes);
-
- /* If we lost data, discard the PES packet we are trying to reassemble
- if any and wait for the beginning of a new one in order to synchronise
- again */
- if( b_packet_lost && p_pes != NULL )
- {
- intf_DbgMsg("PES %p trashed because of packet lost\n", p_pes);
- input_NetlistFreePES( p_input, p_pes );
- p_pes = NULL;
- }
-
- /* If the TS 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 */
- if( b_unit_start && p_pes != NULL )
- {
- /* 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 */
-
- /* If this part of the header did not fit in the current TS packet,
- copy the part of the header we are interested in to the
- p_pes_header_save buffer. The buffer is dynamicly allocated if
- needed so it's time expensive but this situation almost never
- occurs. */
- p_ts = p_pes->p_first_ts;
- i_ts_payload_size = p_ts->i_payload_end - p_ts->i_payload_start;
-
- if(i_ts_payload_size < PES_HEADER_SIZE)
- {
- intf_WarnMsg(3, "Code never tested encountered, WARNING ! (benny)\n");
- if( !p_pes->p_pes_header_save )
- {
- p_pes->p_pes_header_save = malloc(PES_HEADER_SIZE);
- }
-
- i_dummy = 0;
- do
- {
- memcpy( p_pes->p_pes_header_save + i_dummy,
- &p_ts->buffer[p_ts->i_payload_start],
- i_ts_payload_size);
- i_dummy += i_ts_payload_size;
-
- p_ts = p_ts->p_next_ts;
- if(!p_ts)
- {
- /* The payload of the PES packet is shorter than the 14 bytes
- we would read. This means that high packet lost occured
- so the PES won't be useful for any decoder. Moreover,
- this should never happen so we can trash the packet and
- exit roughly without regrets */
- intf_DbgMsg("PES packet too short: trashed\n");
- input_NetlistFreePES( p_input, p_pes );
- p_pes = NULL;
- /* XXX: Stats */
- return;
- }
-
- i_ts_payload_size = p_ts->i_payload_end - p_ts->i_payload_start;
- }
- while(i_ts_payload_size + i_dummy < PES_HEADER_SIZE);
-
- /* This last TS packet is partly header, partly payload, so just
- copy the header part */
- memcpy(p_pes->p_pes_header_save + i_dummy,
- &p_ts->buffer[p_ts->i_payload_start],
- PES_HEADER_SIZE - i_dummy);
-
- /* The header must be read in the buffer not in any TS packet */
- p_pes->p_pes_header = p_pes->p_pes_header_save;
-
- /* Get the PES size if defined */
- if( (i_dummy = U16_AT(p_pes->p_pes_header + 4)) )
- {
- p_pes->i_pes_real_size = i_dummy + 6;
- }
- }
-
- /* Now we have the part of the PES header we were interested in:
- p_pes_header and i_pes_real_size ; we can parse it */
- input_ParsePES( p_input, p_es_descriptor );
- }
-
- /* 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 synchronise with the stream if we we lost
- packets or if the decoder has just started */
- if( b_unit_start )
- {
- p_last_pes = p_pes;
-
- /* Get a new one PES from the PES netlist. */
- if( (p_pes = input_NetlistGetPES( p_input )) == (NULL) )
- {
- /* PES netlist is empty ! */
- p_input->b_error = 1;
- }
- else
- {
- //intf_DbgMsg("New PES packet %p (first TS: %p)\n", p_pes, p_ts_packet);
-
- /* Init the PES fields so that the first TS packet could be
- * correctly added to the PES packet (see below) */
- p_pes->p_first_ts = p_ts_packet;
- p_pes->p_last_ts = NULL;
-
- /* If the last pes packet was null, this means that the
- * synchronization was lost and so warn the decoder that he
- * will have to find a way to recover */
- if( !p_last_pes )
- p_pes->b_data_loss = 1;
-
- /* Read the b_random_access flag status and then reinit it */
- p_pes->b_random_access = p_es_descriptor->b_random;
- p_es_descriptor->b_random = 0;
- }
-
- /* If the PES header fits in the first TS packet, we can
- * already set p_pes->p_pes_header, and in all cases we
- * set p_pes->i_pes_real_size */
- if( p_ts_packet->i_payload_end - p_ts_packet->i_payload_start
- >= PES_HEADER_SIZE )
- {
- p_pes->p_pes_header = &(p_ts_packet->buffer[p_ts_packet->i_payload_start]);
- if( (i_dummy = U16_AT(p_pes->p_pes_header + 4)) )
- {
- p_pes->i_pes_real_size = i_dummy + 6;
- }
- }
- }
-
-
- /* If we are synchronized with the stream, and so if we are ready to
- receive correctly the data, add the TS packet to the current PES
- packet */
- if( p_pes != NULL )
- {
- //intf_DbgMsg("Adding TS %p to PES %p\n", p_ts_packet, p_pes);
-
- /* Size of the payload carried in the TS packet */
- i_ts_payload_size = p_ts_packet->i_payload_end -
- p_ts_packet->i_payload_start;
-
- /* Update the relations between the TS packets */
- p_ts_packet->p_prev_ts = p_pes->p_last_ts;
- p_ts_packet->p_next_ts = NULL;
- if( p_pes->i_ts_packets != 0 )
- {
- /* Regarder si il serait pas plus efficace de ne creer que
- * les liens precedent->suivant pour le moment, et les
- * liens suivant->precedent quand le paquet est termine */
- /* Otherwise it is the first TS packet. */
- p_pes->p_last_ts->p_next_ts = p_ts_packet;
- }
- /* Now add the TS to the PES packet */
- p_pes->p_last_ts = p_ts_packet;
- p_pes->i_ts_packets++;
- p_pes->i_pes_size += i_ts_payload_size;
-
- /* Stats */
-#ifdef STATS
- i_dummy = p_ts_packet->i_payload_end - p_ts_packet->i_payload_start;
- p_es_descriptor->c_payload_bytes += i_dummy;
- p_input->c_payload_bytes += i_dummy;
-#endif
-
- /* We can check if the packet is finished */
- if( p_pes->i_pes_size == p_pes->i_pes_real_size )
- {
- /* The packet is finished, parse it */
- input_ParsePES( p_input, p_es_descriptor );
-
- /* Tell the Demux we have parsed this PES, no need to redo it */
- p_pes = NULL;
- }
- }
- else
+ while( !p_input->b_die )
{
- /* Since we don't use the TS packet to build a PES packet, we don't
- need it anymore, so give it back to the netlist */
- //intf_DbgMsg("Trashing TS %p: no PES being build\n", p_ts_packet);
- input_NetlistFreeTS( p_input, p_ts_packet );
+ /* Sleep a while */
+ msleep( INPUT_IDLE_SLEEP );
}
-
-#undef p_pes
}
/*****************************************************************************
- * input_DemuxTS: first step of demultiplexing: the TS header
- *****************************************************************************
- * Stream must also only contain PES and PSI, so PID must have been filtered
+ * EndThread: end the input thread
*****************************************************************************/
-static __inline__ void input_DemuxTS( input_thread_t *p_input,
- ts_packet_t *p_ts_packet,
- es_descriptor_t *p_es_descriptor )
+static void EndThread( input_thread_t * p_input )
{
- int i_dummy;
- boolean_t b_adaption; /* Adaption field is present */
- boolean_t b_payload; /* Packet carries payload */
- boolean_t b_unit_start; /* A PSI or a PES start in the packet */
- boolean_t b_trash = 0; /* Must the packet be trashed ? */
- boolean_t b_lost = 0; /* Was there a packet lost ? */
-
- ASSERT(p_input);
- ASSERT(p_ts_packet);
- ASSERT(p_es_descriptor);
-
-#define p (p_ts_packet->buffer)
-
- //intf_DbgMsg("input debug: TS-demultiplexing packet %p, pid %d, number %d\n",
- // p_ts_packet, U16_AT(&p[1]) & 0x1fff, p[3] & 0x0f);
-
-#ifdef STATS
- p_es_descriptor->c_packets++;
- p_es_descriptor->c_bytes += TS_PACKET_SIZE;
-#endif
+ int * pi_status; /* thread status */
+ int i_es_loop; /* es index */
- /* Extract flags values from TS common header. */
- b_unit_start = (p[1] & 0x40);
- b_adaption = (p[3] & 0x20);
- b_payload = (p[3] & 0x10);
+ /* Store status */
+ pi_status = p_input->pi_status;
+ *pi_status = THREAD_END;
- /* Extract adaption field informations if any */
- if( !b_adaption )
- {
- /* We don't have any adaptation_field, so payload start immediately
- after the 4 byte TS header */
- p_ts_packet->i_payload_start = 4;
- }
- else
+ /* Destroy all decoder threads */
+ for( i_es_loop = 0;
+ (i_es_loop < INPUT_MAX_ES)
+ && (p_input->pp_selected_es[i_es_loop] != NULL) ;
+ i_es_loop++ )
{
- /* p[4] is adaptation_field_length minus one */
- p_ts_packet->i_payload_start = 5 + p[4];
-
- /* The adaption 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) )
- {
- intf_DbgMsg("input debug: invalid TS adaptation field (%p)\n",
- p_ts_packet);
-#ifdef STATS
- p_es_descriptor->c_invalid_packets++;
-#endif
- b_trash = 1;
- }
-
- /* No we are sure that the byte containing flags is present: read it */
- else
- {
- /* discontinuity_indicator */
- if( p[5] & 0x80 )
- {
- intf_DbgMsg("discontinuity_indicator encountered by TS demux " \
- "(position read: %d, saved: %d)\n", p[5] & 0x80,
- p_es_descriptor->i_continuity_counter);
-
- /* If the PID carries the PCR, there will be a system time-base
- discontinuity. We let the PCR decoder handle that. */
- p_es_descriptor->b_discontinuity = 1;
+ p_input->pp_selected_es[i_es_loop]->p_decoder_fifo->b_die = 1;
+ /* Make sure the thread leaves the GetByte() function */
+ vlc_mutex_lock( &p_input->pp_selected_es[i_es_loop]->p_decoder_fifo->data_lock);
+ vlc_cond_signal( &p_input->pp_selected_es[i_es_loop]->p_decoder_fifo->data_wait );
+ vlc_mutex_unlock( &p_input->pp_selected_es[i_es_loop]->p_decoder_fifo->data_lock );
- /* There also may be a continuity_counter discontinuity:
- resynchronise our counter with the one of the stream */
- p_es_descriptor->i_continuity_counter = (p[3] & 0x0f) - 1;
- }
-
- /* random_access_indicator */
- p_es_descriptor->b_random |= p[5] & 0x40;
-
- /* If this is a PCR_PID, and this TS packet contains a PCR,
- we pass it along to the PCR decoder. */
- if( (p_es_descriptor->b_pcr) && (p[5] & 0x10) )
- {
- /* There should be a PCR field in the packet, check if the
- adaption field is long enough to carry it */
- if( p[4] >= 7 )
- {
- /* Call the PCR decoder */
- input_PcrDecode( p_input, p_es_descriptor, &p[6] );
- }
- }
- }
- }
+ /* Waiting for the thread to exit */
+ vlc_thread_join( p_input->pp_selected_es[i_es_loop]->thread_id );
+ free( p_input->pp_selected_es[i_es_loop]->p_decoder_fifo );
}
- /* Check the continuity of the stream. */
- i_dummy = ((p[3] & 0x0f) - p_es_descriptor->i_continuity_counter) & 0x0f;
- if( i_dummy == 1 )
- {
- /* Everything is ok, just increase our counter */
- p_es_descriptor->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. */
- intf_DbgMsg("Packet without payload received by TS demux\n");
- b_trash = 1;
- }
- else if( i_dummy <= 0 )
- {
- /* Duplicate packet: mark it as being to be trashed. */
- intf_DbgMsg("Duplicate packet received by TS demux\n");
- b_trash = 1;
- }
- else if( p_es_descriptor->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. */
- intf_DbgMsg("First packet for PID %d received by TS demux\n",
- p_es_descriptor->i_id);
- p_es_descriptor->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 */
- intf_DbgMsg("Packet lost by TS demux: current %d, packet %d\n",
- p_es_descriptor->i_continuity_counter & 0x0f,
- p[3] & 0x0f);
- b_lost = 1;
- p_es_descriptor->i_continuity_counter = p[3] & 0x0f;
- }
- }
+ /* Free demultiplexer's data */
- /* Trash the packet if it has no payload or if it is bad */
- if( b_trash )
- {
- input_NetlistFreeTS( p_input, p_ts_packet );
-#ifdef STATS
- p_input->c_packets_trashed++;
-#endif
- }
- else
- {
- if( p_es_descriptor->b_psi )
- {
- /* The payload contains PSI tables */
- input_DemuxPSI( p_input, p_ts_packet, p_es_descriptor,
- b_unit_start, b_lost );
- }
- else
- {
- /* The payload carries a PES stream */
- input_DemuxPES( p_input, p_ts_packet, p_es_descriptor,
- b_unit_start, b_lost );
- }
- }
-
-#undef p
+ /* Update status */
+ *pi_status = THREAD_OVER;
}
/*****************************************************************************
- * input_SortPacket: find out whether we need that packet
+ * NetworkOpen : open a network socket descriptor
*****************************************************************************/
-static __inline__ void input_SortPacket( input_thread_t *p_input,
- ts_packet_t *p_ts_packet )
+static void NetworkOpen( input_thread_t * p_input )
{
- int i_current_pid;
- int i_es_loop;
+ /* straight copy & paste of input_network.c of input-I */
- /* Verify that sync_byte, error_indicator and scrambling_control are
- what we expected. */
- if( !(p_ts_packet->buffer[0] == 0x47) || (p_ts_packet->buffer[1] & 0x80) ||
- (p_ts_packet->buffer[3] & 0xc0) )
- {
- intf_DbgMsg("input debug: invalid TS header (%p)\n", p_ts_packet);
- }
- else
- {
- /* Get the PID of the packet. Note that ntohs is needed, for endianness
- purposes (see man page). */
- i_current_pid = U16_AT(&p_ts_packet->buffer[1]) & 0x1fff;
-
- //intf_DbgMsg("input debug: pid %d received (%p)\n",
- // i_current_pid, p_ts_packet);
-
- /* Lock current ES state. */
- vlc_mutex_lock( &p_input->es_lock );
-
- /* Verify that we actually want this PID. */
- for( i_es_loop = 0; i_es_loop < INPUT_MAX_SELECTED_ES; i_es_loop++ )
- {
- if( p_input->pp_selected_es[i_es_loop] != NULL)
- {
- if( (*p_input->pp_selected_es[i_es_loop]).i_id
- == i_current_pid )
- {
- /* Don't need the lock anymore, since the value pointed
- out by p_input->pp_selected_es[i_es_loop] can only be
- modified from inside the input_thread (by the PSI
- decoder): interface thread is only allowed to modify
- the pp_selected_es table */
- vlc_mutex_unlock( &p_input->es_lock );
-
- /* We're interested. Pass it to the demultiplexer. */
- input_DemuxTS( p_input, p_ts_packet,
- p_input->pp_selected_es[i_es_loop] );
- return;
- }
- }
- else
- {
- /* pp_selected_es should not contain any hole. */
- break;
- }
- }
- vlc_mutex_unlock( &p_input->es_lock );
- }
-
- /* We weren't interested in receiving this packet. Give it back to the
- netlist. */
- //intf_DbgMsg("SortPacket: freeing unwanted TS %p (pid %d)\n", p_ts_packet,
- // U16_AT(&p_ts_packet->buffer[1]) & 0x1fff);
- input_NetlistFreeTS( p_input, p_ts_packet );
-#ifdef STATS
- p_input->c_packets_trashed++;
-#endif
+ /* We cannot rewind nor lseek() */
+ p_input->stream.b_seekable = 0;
+ /* We cannot control the pace */
+ p_input->stream.b_pace_control = 0;
}
/*****************************************************************************
- * input_ReadPacket: reads a packet from the network or the file
+ * FileOpen : open a file descriptor
*****************************************************************************/
-static __inline__ int input_ReadPacket( input_thread_t *p_input )
+static void FileOpen( input_thread_t * p_input )
{
- int i_base_index; /* index of the first free iovec */
- int i_current_index;
- int i_packet_size;
-#ifdef INPUT_LIFO_TS_NETLIST
- int i_meanwhile_released;
- int i_currently_removed;
-#endif
- ts_packet_t * p_ts_packet;
-
- /* In this function, we only care about the TS netlist. PES netlist
- * is for the demultiplexer. */
-#ifdef INPUT_LIFO_TS_NETLIST
- i_base_index = p_input->netlist.i_ts_index;
+ struct stat stat_info;
- /* Verify that we still have packets in the TS netlist */
- if( (INPUT_MAX_TS + INPUT_TS_READ_ONCE - 1 - p_input->netlist.i_ts_index) <= INPUT_TS_READ_ONCE )
- {
- intf_ErrMsg("input error: TS netlist is empty !\n");
- return( -1 );
- }
+#define p_config p_input->p_config
-#else /* FIFO netlist */
- i_base_index = p_input->netlist.i_ts_start;
- if( p_input->netlist.i_ts_start + INPUT_TS_READ_ONCE -1 > INPUT_MAX_TS )
+ if( stat( p_config->p_source, &stat_info ) == (-1) )
{
- /* The netlist is split in 2 parts. We must gather them to consolidate
- the FIFO (we make the loop easily in having the same iovec at the far
- end and in the beginning of netlist_free).
- That's why the netlist is (INPUT_MAX_TS +1) + (INPUT_TS_READ_ONCE -1)
- large. */
- memcpy( p_input->netlist.p_ts_free + INPUT_MAX_TS + 1,
- p_input->netlist.p_ts_free,
- (p_input->netlist.i_ts_start + INPUT_TS_READ_ONCE - 1 - INPUT_MAX_TS)
- * sizeof(struct iovec) );
- }
-
- /* Verify that we still have packets in the TS netlist */
- if( ((p_input->netlist.i_ts_end -1 - p_input->netlist.i_ts_start) & INPUT_MAX_TS) <= INPUT_TS_READ_ONCE )
- {
- intf_ErrMsg("input error: TS netlist is empty !\n");
- return( -1 );
+ intf_ErrMsg("Cannot stat() file %s (%s)", p_config->p_source,
+ strerror(errno));
+ p_input->b_error = 1;
+ return;
}
-#endif /* FIFO netlist */
- /* Scatter read the buffer. */
- i_packet_size = (*p_input->p_Read)( p_input,
- &p_input->netlist.p_ts_free[i_base_index],
- INPUT_TS_READ_ONCE );
- if( i_packet_size == (-1) )
- {
-#if 0
- intf_DbgMsg("Read packet %d %p %d %d\n", i_base_index,
- &p_input->netlist.p_ts_free[i_base_index],
- p_input->netlist.i_ts_start,
- p_input->netlist.i_ts_end);
-#endif
- intf_ErrMsg("input error: readv() failed (%s)\n", strerror(errno));
- return( -1 );
- }
+ vlc_mutex_lock( &p_input->stream.stream_lock );
- if( i_packet_size == 0 )
- {
- /* No packet has been received, so stop here. */
- return( 0 );
- }
+ /* If we are here we can control the pace... */
+ p_input->stream.b_pace_control = 1;
- /* Demultiplex the TS packets (1..INPUT_TS_READ_ONCE) received. */
- for( i_current_index = i_base_index;
- (i_packet_size -= TS_PACKET_SIZE) >= 0;
- i_current_index++ )
+ if( S_ISREG(stat_info.st_mode) || S_ISCHR(stat_info.st_mode)
+ || S_ISBLK(stat_info.st_mode) )
{
- /* BTW, something REALLY bad could happen if we receive packets with
- a wrong size. */
- p_ts_packet = (ts_packet_t*)(p_input->netlist.p_ts_free[i_current_index].iov_base);
- /* Don't cry :-), we are allowed to do that cast, because initially,
- our buffer was malloc'ed with sizeof(ts_packet_t) */
-
- /* Find out if we need this packet and demultiplex. */
- input_SortPacket( p_input /* for current PIDs and netlist */,
- p_ts_packet);
+ p_input->stream.b_seekable = 1;
+ p_input->stream.i_size = stat_info.st_size;
}
-
- if( i_packet_size > 0 )
+ else if( S_ISFIFO(stat_info.st_mode) || S_ISSOCK(stat_info.st_mode) )
{
- intf_ErrMsg("input error: wrong size\n");
- return( -1 );
- }
-
- /* Remove the TS packets we have just filled from the netlist */
-#ifdef INPUT_LIFO_TS_NETLIST
- /* We need to take a lock here while we're calculating index positions. */
- vlc_mutex_lock( &p_input->netlist.lock );
-
- i_meanwhile_released = i_base_index - p_input->netlist.i_ts_index;
- if( i_meanwhile_released )
- {
- /* That's where it becomes funny :-). Since we didn't take locks for
- efficiency reasons, other threads (including ourselves, with
- input_DemuxPacket) might have released packets to the netlist.
- So we have to copy these iovec where they should go.
-
- BTW, that explains why the TS netlist is
- (INPUT_MAX_TS +1) + (TS_READ_ONCE -1) large. */
-
- i_currently_removed = i_current_index - i_base_index;
- if( i_meanwhile_released < i_currently_removed )
- {
- /* Copy all iovecs in that case */
- memcpy( &p_input->netlist.p_ts_free[p_input->netlist.i_ts_index]
- + i_currently_removed,
- &p_input->netlist.p_ts_free[p_input->netlist.i_ts_index],
- i_meanwhile_released * sizeof(struct iovec) );
- }
- else
- {
- /* We have fewer places than items, so we only move
- i_currently_removed of them. */
- memcpy( &p_input->netlist.p_ts_free[i_base_index],
- &p_input->netlist.p_ts_free[p_input->netlist.i_ts_index],
- i_currently_removed * sizeof(struct iovec) );
- }
-
- /* Update i_netlist_index with the information gathered above. */
- p_input->netlist.i_ts_index += i_currently_removed;
+ p_input->stream.b_seekable = 0;
+ p_input->stream.i_size = 0;
}
else
{
- /* Nothing happened. */
- p_input->netlist.i_ts_index = i_current_index;
- }
-
- vlc_mutex_unlock( &p_input->netlist.lock );
-
-#else /* FIFO netlist */
- /* & is modulo ; that's where we make the loop. */
- p_input->netlist.i_ts_start = i_current_index & INPUT_MAX_TS;
-#endif
-
-#ifdef STATS
- p_input->c_packets_read += i_current_index - i_base_index;
- p_input->c_bytes += (i_current_index - i_base_index) * TS_PACKET_SIZE;
-#endif
- return( 0 );
-}
-
-/*****************************************************************************
- * RunThread: main thread loop
- *****************************************************************************
- * Thread in charge of processing the network packets and demultiplexing.
- *****************************************************************************/
-static void RunThread( input_thread_t *p_input )
-{
- /*
- * Initialize thread and free configuration
- */
- p_input->b_error = InitThread( p_input );
- if( p_input->b_error )
- {
- free( p_input ); /* destroy descriptor */
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ intf_ErrMsg("Unknown file type");
+ p_input->b_error = 1;
return;
}
- /*
- * Main loop
- */
- intf_DbgMsg("\n");
- while( !p_input->b_die && !p_input->b_error )
- {
- /* Scatter read the UDP packet from the network or the file. */
- if( (input_ReadPacket( p_input )) == (-1) )
- {
- /* FIXME??: Normally, a thread can't kill itself, but we don't have
- * any method in case of an error condition ... */
- p_input->b_error = 1;
- }
-
-#ifdef STATS
- p_input->c_loops++;
-#endif
- }
-
- /*
- * Error loop
- */
- if( p_input->b_error )
- {
- ErrorThread( p_input );
- }
-
- /* End of thread */
- EndThread( p_input );
- intf_DbgMsg("thread end\n");
-}
-
+ p_input->stream.i_tell = 0;
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
-/*****************************************************************************
- * ErrorThread: RunThread() error loop
- *****************************************************************************
- * This function is called when an error occured during thread main's loop.
- *****************************************************************************/
-static void ErrorThread( input_thread_t *p_input )
-{
- /* Wait until a `die' order */
- intf_DbgMsg("\n");
- while( !p_input->b_die )
+ intf_Msg( "Opening file %s", p_config->p_source );
+ if( (p_input->i_handle = open( p_config->p_source,
+ /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
{
- /* Sleep a while */
- msleep( VOUT_IDLE_SLEEP );
- }
-}
-
-/*****************************************************************************
- * EndThread: end the input thread
- *****************************************************************************/
-static void EndThread( input_thread_t * p_input )
-{
- int * pi_status; /* threas status */
- int i_es_loop; /* es index */
-
- /* Store status */
- intf_DbgMsg("\n");
- pi_status = p_input->pi_status;
- *pi_status = THREAD_END;
-
-#ifdef STATS
- intf_Msg("input stats: Done %d loops\n", p_input->c_loops);
- intf_Msg("input stats: Read %d bytes (payload : %d)\n", p_input->c_bytes,
- p_input->c_payload_bytes);
- intf_Msg("input stats: Read %d packets (trashed : %d)\n",
- p_input->c_packets_read, p_input->c_packets_trashed);
-#endif
-
- /* Close input method */
- p_input->p_Close( p_input );
-
- /* Destroy all decoder threads */
- for( i_es_loop = 0;
- (i_es_loop < INPUT_MAX_ES) && (p_input->pp_selected_es[i_es_loop] != NULL) ;
- i_es_loop++ )
- {
- switch( p_input->pp_selected_es[i_es_loop]->i_type )
- {
- case MPEG1_VIDEO_ES:
- case MPEG2_VIDEO_ES:
- vpar_DestroyThread( (vpar_thread_t*)(p_input->pp_selected_es[i_es_loop]->p_dec) /*, NULL */ );
- break;
- case MPEG1_AUDIO_ES:
- case MPEG2_AUDIO_ES:
- adec_DestroyThread( (adec_thread_t*)(p_input->pp_selected_es[i_es_loop]->p_dec) );
- break;
- case AC3_AUDIO_ES:
- ac3dec_DestroyThread( (ac3dec_thread_t *)(p_input->pp_selected_es[i_es_loop]->p_dec) );
- break;
- case LPCM_AUDIO_ES:
- lpcmdec_DestroyThread((lpcmdec_thread_t *)(p_input->pp_selected_es[i_es_loop]->p_dec) );
- break;
- case DVD_SPU_ES:
- spudec_DestroyThread( (spudec_thread_t *)(p_input->pp_selected_es[i_es_loop]->p_dec) );
- break;
- case 0:
- /* Special streams for the PSI decoder, PID 0 and 1 */
- break;
-#ifdef DEBUG
- default:
- intf_DbgMsg("error: unknown decoder type %d\n", p_input->pp_selected_es[i_es_loop]->i_type );
- break;
-#endif
- }
+ intf_ErrMsg("Cannot open file (%s)", strerror(errno));
+ p_input->b_error = 1;
+ return;
}
- input_NetlistEnd( p_input ); /* clean netlist */
- input_PsiEnd( p_input ); /* clean PSI information */
- input_PcrEnd( p_input ); /* clean PCR information */
- free( p_input ); /* free input_thread structure */
-
- /* Update status */
- *pi_status = THREAD_OVER;
+#undef p_config
}
-
--- /dev/null
+/* Communication plugin -> input */
+
+#define INPUT_READ_ONCE 7 /* We live in a world dominated by Ethernet. *
+ * Ethernet MTU is 1500 bytes, so in a UDP *
+ * packet we can put : 1500/188 = 7 TS *
+ * packets. Have a nice day and merry Xmas. */
+
+/*****************************************************************************
+ * input_capabilities_t
+ *****************************************************************************
+ * This structure gives pointers to the useful methods of the plugin
+ *****************************************************************************/
+typedef struct input_capabilities_s
+{
+ /* Plugin properties */
+ int i_weight; /* for a given stream type, the plugin *
+ * with higher weight will be used */
+
+ /* Init/End */
+ int (* pf_probe)( struct input_thread_s * );
+ void (* pf_init)( struct input_thread_s * );
+ void (* pf_end)( struct input_thread_s * );
+
+ /* Read & Demultiplex */
+ void (* pf_read)( struct input_thread_s *,
+ struct data_packet_s * pp_packets[INPUT_READ_ONCE] );
+ void (* pf_demux)( struct input_thread_s *,
+ struct data_packet_s * );
+
+ /* Packet management facilities */
+ struct data_packet_s *(* pf_new_packet)( void *, size_t );
+ void (* pf_delete_packet)( void *,
+ struct data_packet_s * );
+ void (* pf_delete_pes)( void *, struct pes_packet_s * );
+
+ /* Stream control capabilities */
+ int (* pf_rewind)( struct input_thread_s * );
+ /* NULL if we don't support going *
+ * backwards (it's gonna be fun) */
+ int (* pf_seek)( struct input_thread_s *, off_t );
+} input_capabilities_t;
+
+/*****************************************************************************
+ * Prototypes from input_ext-dec.c
+ *****************************************************************************/
+void InitBitstream ( struct bit_stream_s *, struct decoder_fifo_s * );
+void NextDataPacket ( struct bit_stream_s * );
+++ /dev/null
-/*****************************************************************************
- * input_ctrl.c: Decoder control
- * Controls the extraction and the decoding of the programs elements carried
- * within a stream.
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * Authors: Christophe Massiot <massiot@via.ecp.fr>
- * Benoît Steiner <benny@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 "defs.h"
-
-#include <sys/types.h> /* on BSD, uio.h needs types.h */
-#include <sys/uio.h> /* "input.h" */
-#include <stdio.h>
-#include <netinet/in.h> /* ntohs */
-
-#include "config.h"
-#include "common.h"
-#include "threads.h"
-#include "mtime.h"
-#include "intf_msg.h"
-#include "plugins.h"
-#include "debug.h"
-
-#include "input.h"
-#include "input_netlist.h"
-#include "decoder_fifo.h"
-
-#include "audio_output.h" /* aout_thread_t */
-
-#include "audio_decoder.h" /* audiodec_t (for audio_decoder_thread.h) */
-#include "audio_decoder_thread.h" /* adec_thread_t */
-
-#include "ac3_decoder.h" /* ac3dec_t (for ac3_decoder_thread.h) */
-#include "ac3_decoder_thread.h" /* ac3dec_thread_t */
-
-#include "lpcm_decoder.h"
-#include "lpcm_decoder_thread.h"
-
-#include "video.h" /* picture_t (for video_output.h) */
-#include "video_output.h" /* vout_thread_t */
-
-#include "vdec_idct.h" /* dctelem_t (for video_parser.h) */
-#include "vdec_motion.h" /* f_motion_t (for video_parser.h) */
-#include "vpar_blocks.h" /* macroblock_t (for video_parser.h) */
-#include "vpar_headers.h" /* sequence_t (for video_parser.h) */
-#include "vpar_synchro.h" /* video_synchro_t (for video_parser.h) */
-#include "video_parser.h" /* vpar_thread_t */
-
-#include "spu_decoder.h" /* spudec_thread_t */
-
-/*****************************************************************************
- * input_AddPgrmElem: Start the extraction and the decoding of a program element
- *****************************************************************************
- * Add the element given by its PID in the list of PID to extract and spawn
- * the decoding thread.
- * This function only modifies the table of selected es, but must NOT modify
- * the table of ES itself.
- *****************************************************************************/
-int input_AddPgrmElem( input_thread_t *p_input, int i_current_id )
-{
- int i_es_loop, i_selected_es_loop;
-
- /* Since this function is intended to be called by interface, lock the
- * elementary stream structure. */
- vlc_mutex_lock( &p_input->es_lock );
-
- /* Find out which PID we need. */
- for( i_es_loop = 0; i_es_loop < INPUT_MAX_ES; i_es_loop++ )
- {
- if( p_input->p_es[i_es_loop].i_id == i_current_id )
- {
- if( p_input->p_es[i_es_loop].p_dec != NULL )
- {
- /* We already have a decoder for that PID. */
- vlc_mutex_unlock( &p_input->es_lock );
- intf_ErrMsg("input error: PID %d already selected\n",
- i_current_id);
- return( -1 );
- }
-
- intf_DbgMsg("Requesting selection of PID %d\n",
- i_current_id);
-
- /* Find a free spot in pp_selected_es. */
- for( i_selected_es_loop = 0; p_input->pp_selected_es[i_selected_es_loop] != NULL
- && i_selected_es_loop < INPUT_MAX_SELECTED_ES; i_selected_es_loop++ );
-
- if( i_selected_es_loop == INPUT_MAX_SELECTED_ES )
- {
- /* array full */
- vlc_mutex_unlock( &p_input->es_lock );
- intf_ErrMsg("input error: MAX_SELECTED_ES reached: try increasing it in config.h\n");
- return( -1 );
- }
-
- /* Don't decode PSI streams ! */
- if( p_input->p_es[i_es_loop].b_psi )
- {
- intf_ErrMsg("input_error: trying to decode PID %d which is the one of a PSI\n", i_current_id);
- vlc_mutex_unlock( &p_input->es_lock );
- return( -1 );
- }
- else
- {
- /* Spawn the decoder. */
- switch( p_input->p_es[i_es_loop].i_type )
- {
-
- case AC3_AUDIO_ES:
- /* Spawn ac3 thread */
- if ( ((ac3dec_thread_t *)(p_input->p_es[i_es_loop].p_dec) =
- ac3dec_CreateThread(p_input)) == NULL )
- {
- intf_ErrMsg( "Could not start ac3 decoder\n" );
- vlc_mutex_unlock( &p_input->es_lock );
- return( -1 );
- }
- break;
-
- case LPCM_AUDIO_ES:
- /* Spawn lpcm thread */
- if ( ((lpcmdec_thread_t *)
- (p_input->p_es[i_es_loop].p_dec) =
- lpcmdec_CreateThread(p_input)) == NULL )
- {
- intf_ErrMsg( "LPCM Debug: Could not start "
- "lpcm decoder\n" );
- vlc_mutex_unlock( &p_input->es_lock );
- return( -1 );
- }
- break;
-
-
- case DVD_SPU_ES:
- /* Spawn spu thread */
- if ( ((spudec_thread_t *)
- (p_input->p_es[i_es_loop].p_dec) =
- spudec_CreateThread(p_input)) == NULL )
- {
- intf_ErrMsg( "Could not start spu decoder\n" );
- vlc_mutex_unlock( &p_input->es_lock );
- return( -1 );
- }
- break;
-
- case MPEG1_AUDIO_ES:
- case MPEG2_AUDIO_ES:
- /* Spawn audio thread. */
- if( ((adec_thread_t*)(p_input->p_es[i_es_loop].p_dec) =
- adec_CreateThread( p_input )) == NULL )
- {
- intf_ErrMsg("Could not start audio decoder\n");
- vlc_mutex_unlock( &p_input->es_lock );
- return( -1 );
- }
- break;
-
- case MPEG1_VIDEO_ES:
- case MPEG2_VIDEO_ES:
- /* Spawn video thread. */
- if( ((vpar_thread_t*)(p_input->p_es[i_es_loop].p_dec) =
- vpar_CreateThread( p_input )) == NULL )
- {
- intf_ErrMsg("Could not start video parser\n");
- vlc_mutex_unlock( &p_input->es_lock );
- return( -1 );
- }
- break;
-
- default:
- /* That should never happen. */
- intf_DbgMsg( "input error: unknown stream (0x%.2x)\n",
- p_input->p_es[i_es_loop].i_type);
- vlc_mutex_unlock( &p_input->es_lock );
- return( -1 );
- break;
- }
-
- /* Initialise the demux */
- p_input->p_es[i_es_loop].p_pes_packet = NULL;
- p_input->p_es[i_es_loop].i_continuity_counter = 0xff;
- p_input->p_es[i_es_loop].b_random = 0;
-
- /* Mark stream to be demultiplexed. */
- intf_DbgMsg( "Stream %d added in %d\n",
- i_current_id, i_selected_es_loop);
- p_input->pp_selected_es[i_selected_es_loop] =
- &p_input->p_es[i_es_loop];
- vlc_mutex_unlock( &p_input->es_lock );
- return( 0 );
- }
- }
- }
-
- /* We haven't found this PID in the current stream. */
- vlc_mutex_unlock( &p_input->es_lock );
- intf_ErrMsg("input error: can't find PID %d\n", i_current_id);
- return( -1 );
-}
-
-/*****************************************************************************
- * input_DelPgrmElem: Stop the decoding of a program element
- *****************************************************************************
- * Stop the extraction of the element given by its PID and kill the associated
- * decoder thread
- * This function only modifies the table of selected es, but must NOT modify
- * the table of ES itself.
- *****************************************************************************/
-int input_DelPgrmElem( input_thread_t *p_input, int i_current_id )
-{
- int i_selected_es_loop, i_last_selected;
-
- /* Since this function is intended to be called by interface, lock the
- structure. */
- vlc_mutex_lock( &p_input->es_lock );
-
- /* Find out which PID we need. */
- for( i_selected_es_loop = 0; i_selected_es_loop < INPUT_MAX_SELECTED_ES;
- i_selected_es_loop++ )
- {
- if( p_input->pp_selected_es[i_selected_es_loop] )
- {
- if( p_input->pp_selected_es[i_selected_es_loop]->i_id == i_current_id )
- {
- if( !(p_input->pp_selected_es[i_selected_es_loop]->p_dec) )
- {
- /* We don't have a decoder for that PID. */
- vlc_mutex_unlock( &p_input->es_lock );
- intf_ErrMsg("input error: PID %d already deselected\n",
- i_current_id);
- return( -1 );
- }
-
- intf_DbgMsg("input debug: requesting termination of PID %d\n",
- i_current_id);
-
- /* Cancel the decoder. */
- switch( p_input->pp_selected_es[i_selected_es_loop]->i_type )
- {
- case AC3_AUDIO_ES:
- ac3dec_DestroyThread( (ac3dec_thread_t *)(p_input->pp_selected_es[i_selected_es_loop]->p_dec) );
- break;
-
- case LPCM_AUDIO_ES:
- lpcmdec_DestroyThread( (lpcmdec_thread_t *)(p_input->pp_selected_es[i_selected_es_loop]->p_dec) );
- break;
-
- case DVD_SPU_ES:
- spudec_DestroyThread( (spudec_thread_t *)(p_input->pp_selected_es[i_selected_es_loop]->p_dec) );
- break;
-
- case MPEG1_AUDIO_ES:
- case MPEG2_AUDIO_ES:
- adec_DestroyThread( (adec_thread_t*)(p_input->pp_selected_es[i_selected_es_loop]->p_dec) );
- break;
-
- case MPEG1_VIDEO_ES:
- case MPEG2_VIDEO_ES:
- vpar_DestroyThread( (vpar_thread_t*)(p_input->pp_selected_es[i_selected_es_loop]->p_dec) /*, NULL */ );
- break;
- }
-
- /* Unmark stream. */
- p_input->pp_selected_es[i_selected_es_loop]->p_dec = NULL;
-
- /* Find last selected stream. */
- for( i_last_selected = i_selected_es_loop;
- p_input->pp_selected_es[i_last_selected]
- && i_last_selected < INPUT_MAX_SELECTED_ES;
- i_last_selected++ );
-
- /* Exchange streams. */
- p_input->pp_selected_es[i_selected_es_loop] =
- p_input->pp_selected_es[i_last_selected];
- p_input->pp_selected_es[i_last_selected] = NULL;
-
- vlc_mutex_unlock( &p_input->es_lock );
- return( 0 );
- }
- }
- }
-
- /* We haven't found this PID in the current stream. */
- vlc_mutex_unlock( &p_input->es_lock );
- intf_ErrMsg("input error: can't find PID %d\n", i_current_id);
- return( -1 );
-}
-
-
-
-/*****************************************************************************
- * input_IsElemRecv: Test if an element given by its PID is currently received
- *****************************************************************************
- * Cannot return the position of the es in the pp_selected_es, for it can
- * change once we have released the lock
- *****************************************************************************/
-boolean_t input_IsElemRecv( input_thread_t *p_input, int i_id )
-{
- boolean_t b_is_recv = 0;
- int i_index = 0;
-
- /* Since this function is intended to be called by interface, lock the
- structure. */
- vlc_mutex_lock( &p_input->es_lock );
-
- /* Scan the table */
- while( i_index < INPUT_MAX_SELECTED_ES && !p_input->pp_selected_es[i_index] )
- {
- if( p_input->pp_selected_es[i_index]->i_id == i_id )
- {
- b_is_recv = 1;
- break;
- }
- }
-
- /* Unlock the structure */
- vlc_mutex_unlock( &p_input->es_lock );
-
- return( b_is_recv );
-}
+++ /dev/null
-/*****************************************************************************
- * input_ctrl.h: Decodeur control
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * 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.
- *****************************************************************************/
-
-/*****************************************************************************
- * Requires:
- * "config.h"
- * "common.h"
- * "mtime.h"
- *****************************************************************************/
-
-
-
-
-
-
-/*****************************************************************************
- * Prototypes
- *****************************************************************************/
-int input_AddPgrmElem( input_thread_t *p_input, int i_current_pid );
-int input_DelPgrmElem( input_thread_t *p_input, int i_current_pid );
-boolean_t input_IsElemRecv( input_thread_t *p_input, int i_pid );
--- /dev/null
+/*****************************************************************************
+ * input_ext-dec.c: services to the decoders
+ *****************************************************************************
+ * Copyright (C) 1998, 1999, 2000 VideoLAN
+ *
+ * Authors:
+ *
+ * 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 "defs.h"
+
+#include "config.h"
+#include "common.h"
+#include "threads.h"
+#include "mtime.h"
+
+#include "intf_msg.h"
+
+#include "stream_control.h"
+#include "input_ext-dec.h"
+#include "input.h"
+
+/*****************************************************************************
+ * InitBitstream: initialize a bit_stream_t structure
+ *****************************************************************************/
+void InitBitstream( bit_stream_t * p_bit_stream, decoder_fifo_t * p_fifo )
+{
+ p_bit_stream->p_decoder_fifo = p_fifo;
+ p_bit_stream->pf_next_data_packet = NextDataPacket;
+
+ /* Get the first data packet. */
+ vlc_mutex_lock( &p_fifo->data_lock );
+ while ( DECODER_FIFO_ISEMPTY( *p_fifo ) )
+ {
+ if ( p_fifo->b_die )
+ {
+ vlc_mutex_unlock( &p_fifo->data_lock );
+ return;
+ }
+ vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
+ }
+ p_bit_stream->p_data = DECODER_FIFO_START( *p_fifo )->p_first;
+ p_bit_stream->p_byte = p_bit_stream->p_data->p_payload_start;
+ p_bit_stream->p_end = p_bit_stream->p_data->p_payload_end;
+ p_bit_stream->fifo.buffer = 0;
+ p_bit_stream->fifo.i_available = 0;
+ vlc_mutex_unlock( &p_fifo->data_lock );
+}
+
+/*****************************************************************************
+ * NextDataPacket: go to the next data packet
+ *****************************************************************************/
+void NextDataPacket( bit_stream_t * p_bit_stream )
+{
+ WORD_TYPE buffer_left;
+ /* FIXME : not portable in a 64bit environment */
+ int i_bytes_left;
+ decoder_fifo_t * p_fifo = p_bit_stream->p_decoder_fifo;
+
+ /* Buffer used at the end of a decoder thread, to give it zero
+ * values if needed. */
+ static byte_t p_zero[64] = { 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0 };
+
+ /* Put the remaining bytes (not aligned on a word boundary) in a
+ * temporary buffer. */
+ i_bytes_left = p_bit_stream->p_end - p_bit_stream->p_byte;
+ buffer_left = *((WORD_TYPE *)p_bit_stream->p_end - 1);
+
+ /* We are looking for the next data packet that contains real data,
+ * and not just a PES header */
+ do
+ {
+ /* We were reading the last data packet of this PES packet... It's
+ * time to jump to the next PES packet */
+ if( p_bit_stream->p_data->p_next == NULL )
+ {
+ /* We are going to read/write the start and end indexes of the
+ * decoder fifo and to use the fifo's conditional variable,
+ * that's why we need to take the lock before. */
+ vlc_mutex_lock( &p_fifo->data_lock );
+
+ /* Is the input thread dying ? */
+ if( p_fifo->b_die )
+ {
+ vlc_mutex_unlock( &p_fifo->data_lock );
+ p_bit_stream->p_byte = p_zero;
+ p_bit_stream->p_end = &p_zero[sizeof(p_zero) - 1];
+ return;
+ }
+
+ /* We should increase the start index of the decoder fifo, but
+ * if we do this now, the input thread could overwrite the
+ * pointer to the current PES packet, and we weren't able to
+ * give it back to the netlist. That's why we free the PES
+ * packet first. */
+ p_fifo->pf_delete_pes( p_fifo->p_packets_mgt,
+ DECODER_FIFO_START( *p_fifo ) );
+ DECODER_FIFO_INCSTART( *p_fifo );
+
+ while( DECODER_FIFO_ISEMPTY( *p_fifo ) )
+ {
+ vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
+ if( p_fifo->b_die )
+ {
+ vlc_mutex_unlock( &p_fifo->data_lock );
+ p_bit_stream->p_byte = p_zero;
+ p_bit_stream->p_end = &p_zero[sizeof(p_zero) - 1];
+ return;
+ }
+ }
+
+ /* The next byte could be found in the next PES packet */
+ p_bit_stream->p_data = DECODER_FIFO_START( *p_fifo )->p_first;
+
+ /* We can release the fifo's data lock */
+ vlc_mutex_unlock( &p_fifo->data_lock );
+ }
+ else
+ {
+ /* Perhaps the next data packet of the current PES packet contains
+ * real data (ie its payload's size is greater than 0). */
+ p_bit_stream->p_data = p_bit_stream->p_data->p_next;
+ }
+ } while ( p_bit_stream->p_data->p_payload_start
+ == p_bit_stream->p_data->p_payload_end );
+
+ /* We've found a data packet which contains interesting data... */
+ p_bit_stream->p_byte = p_bit_stream->p_data->p_payload_start;
+ p_bit_stream->p_end = p_bit_stream->p_data->p_payload_end;
+
+ /* Copy remaining bits of the previous packet */
+ *((WORD_TYPE *)p_bit_stream->p_byte - 1) = buffer_left;
+ p_bit_stream->p_byte -= i_bytes_left;
+}
+++ /dev/null
-/*****************************************************************************
- * input_file.c: functions to read from a file
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
- * Samuel Hocevar <sam@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 "defs.h"
-
-#include <stdio.h>
-#include <unistd.h> /* close() */
-#include <sys/types.h> /* on BSD, uio.h needs types.h */
-#include <sys/uio.h> /* "input.h" */
-#include <sys/stat.h> /* fstat, off_t ... */
-#include <netinet/in.h> /* ntohl() */
-#include <fcntl.h> /* open() */
-#include <malloc.h> /* malloc, read ... */
-#include <string.h>
-
-#include "config.h"
-#include "common.h"
-#include "threads.h"
-#include "mtime.h"
-#include "plugins.h"
-#include "playlist.h"
-#include "intf_msg.h"
-
-#include "main.h"
-
-#include "input.h"
-#include "input_ps.h"
-#include "input_file.h"
-
-#define BUF_SIZE (797*3)
-
-#define PS_METHOD 1
-#define TS_METHOD 2
-
-#define TS_PACKET_SIZE 188
-#define TS_IN_UDP 7
-
-#define MAX_AUDIO_CHANNEL 15
-#define MAX_SUBTITLES_CHANNEL 31
-#define NO_SUBTITLES 255
-
-#define PS_BUFFER_SIZE 16384
-
-#define NO_PES 0x00
-#define AUDIO_PES 0x01
-#define VIDEO_PES 0x02
-#define AC3_PES 0x03
-#define SUBTITLE_PES 0x04
-#define LPCM_PES 0x05
-#define PRIVATE_PES 0x06
-#define UNKNOWN_PES 0x12
-
-#define PCR_PID 0x20 /* 0x20 == first video stream
- * 0x40 == first audio stream */
-
-typedef u8 file_ts_packet[TS_PACKET_SIZE];
-typedef file_ts_packet udp_packet[TS_IN_UDP];
-
-typedef struct synchro_struct
-{
- mtime_t delta_clock;
- mtime_t slope;
- mtime_t last_pcr_time;
-
- file_ts_packet *last_pcr;
-} synchro_t;
-
-typedef struct in_data_s
-{
- int start, end;
- vlc_mutex_t lock;
- vlc_cond_t notfull;
- vlc_cond_t notempty;
- udp_packet buf[BUF_SIZE+1];
-} in_data_t;
-
-typedef struct own_pcr_s
-{
- int start, end;
- vlc_mutex_t lock;
- file_ts_packet *buf[(BUF_SIZE+1)*TS_IN_UDP+1];
-} own_pcr_t;
-
-typedef struct options_s
-{
- unsigned int pcr_pid;
- u8 i_file_type;
- int in;
-} options_t;
-
-typedef struct s_ps
-{
- unsigned int pat_counter;
- unsigned int pmt_counter;
-
- /*
- * These 3 parameters are passed
- * as command line arguments
- */
- unsigned int audio_channel;
- unsigned int subtitles_channel;
- unsigned int audio_type;
-
- /*
- * 16 audio mpeg streams
- * 16 audio AV3 streams
- * 16 video mpeg streams
- * 32 subtitle streams
- */
- unsigned int media_counter[0x100];
- unsigned int association_table[0x100];
- unsigned int found_streams;
-
- unsigned int found_pts;
-
- unsigned int ts_to_write;
- unsigned int ts_written;
- unsigned int sent_ts;
-
- unsigned char *ps_data;
- unsigned char *ps_end;
- unsigned char *ps_buffer;
-
- unsigned int pes_id;
- unsigned int private_id;
- unsigned int has_pts;
- unsigned int pcr_pid;
-
- unsigned int pes_type;
- unsigned int pes_size;
- unsigned int to_skip;
- unsigned int offset;
-} ps_t;
-
-typedef struct input_file_s
-{
- boolean_t b_die; /* b_die flag for the disk thread */
- vlc_thread_t disk_thread;
-
- synchro_t synchro;
- ps_t ps;
- in_data_t in_data;
- options_t options;
- own_pcr_t own_pcr;
-} input_file_t;
-
-/* local prototypes */
-void ps_fill( input_file_t * p_if, boolean_t wait );
-ssize_t safe_read(options_t *p_options, unsigned char *buf, int count);
-void input_DiskThread( input_file_t * p_if );
-int init_synchro( input_file_t * p_if );
-
-input_file_t input_file;
-
-/******************************************************************************
- * ConvertPCRTime : extracts and converts the PCR time in microseconds
- ******************************************************************************/
-
-s64 ConvertPCRTime(file_ts_packet *pcr_buff)
-{
- return( (((((s64)U32_AT(((u8*)pcr_buff)+6)) << 1) | (((u8*)pcr_buff)[10] >> 7)) * 300) / 27 );
-}
-
-/******************************************************************************
- * wait_a_moment : Compute how long we must wait before sending a TS packet
- ******************************************************************************/
-
-static void wait_a_moment( input_file_t * p_if, file_ts_packet *ts)
-{
- synchro_t * p_synchro = &input_file.synchro;
-
- static int retard_count = 0;
- static s64 wait_max = 0;
- s64 sendtime; /* the date at which the TS packet should be sent */
- s64 wait;
-
- sendtime = p_synchro->last_pcr_time + p_synchro->delta_clock +
- p_synchro->slope * ((ts - p_synchro->last_pcr + (BUF_SIZE+1)*TS_IN_UDP) % ((BUF_SIZE+1)*TS_IN_UDP));
- wait = sendtime - mdate();
- if( wait > 0 )
- {
- retard_count = 0;
- if(wait > 100000)
- {
- intf_DbgMsg( "input warning: wait time may be too long : %Ld\n", wait );
- return;
- }
- msleep( wait );
- }
- else
- {
- if( wait < wait_max )
- {
- wait_max = wait;
- }
- retard_count++;
- if( retard_count == 16 )
- {
- retard_count = 0;
- }
- }
-}
-
-/******************************************************************************
- * adjust : Adjust the encoder clock & remove the PCR from own_pcr
- ******************************************************************************/
-
-static void adjust( input_file_t * p_if, file_ts_packet *ts )
-{
- synchro_t * p_synchro = &p_if->synchro;
- own_pcr_t * p_own_pcr = &p_if->own_pcr;
- file_ts_packet *next_pcr;
- int no_discontinuity = 1;
-
- if( ((u8*)ts)[5] & 0x80 )
- {
- /* There is a discontinuity - I recalculate the delta */
- p_synchro->delta_clock = mdate() - ConvertPCRTime(ts);
- intf_DbgMsg( "input warning: clock discontinuity\n" );
- no_discontinuity = 0;
- }
- else
- {
- p_synchro->last_pcr = ts;
- p_synchro->last_pcr_time = ConvertPCRTime( ts );
- }
-
- vlc_mutex_lock(&p_own_pcr->lock);
- p_own_pcr->start++;
- p_own_pcr->start %= (BUF_SIZE+1)*TS_IN_UDP+1;
-
- /* If we have 2 consecutiv PCR, we can reevaluate slope */
- if( (p_own_pcr->start != p_own_pcr->end) &&
- no_discontinuity &&
- !((((u8*) next_pcr = p_own_pcr->buf[p_own_pcr->start]))[5] & 0x80))
- {
- s64 current_pcr_time = ConvertPCRTime(ts);
- s64 next_pcr_time = ConvertPCRTime(next_pcr);
-
- if( (next_pcr_time - current_pcr_time < 0) || (next_pcr_time - current_pcr_time > 700000))
- {
- intf_DbgMsg( "input warning: possible discontinuity\n" );
- p_synchro->delta_clock = mdate() - next_pcr_time;
- }
- else
- {
- p_synchro->slope = (next_pcr_time - current_pcr_time) /
- ((next_pcr - ts + (BUF_SIZE+1)*TS_IN_UDP) % ((BUF_SIZE+1)*TS_IN_UDP));
- }
- }
-
- vlc_mutex_unlock(&p_own_pcr->lock);
-}
-
-/*****************************************************************************
- * file_next : Opens the next available file
- *****************************************************************************/
-
-int file_next( options_t *options )
-{
- p_playlist_t p_playlist = p_main->p_playlist;
-
- /* the check for index == 0 has to be done _before_ */
- p_playlist->i_index--;
-
- /* close the file we just finished */
- if( options->in != -1 )
- {
- close( options->in );
- }
-
- /* open the next file */
- if( !strcmp( p_playlist->p_list[ p_playlist->i_index ], "-" ) )
- {
- /* read stdin */
- return ( options->in = 0 );
- }
- else
- {
- /* read the actual file */
- intf_Msg( "Playing file %s\n",
- p_playlist->p_list[ p_playlist->i_index ] );
-
- options->in =
- open( p_playlist->p_list[ p_playlist->i_index ],
- O_RDONLY | O_NONBLOCK );
-
- return ( options->in );
- }
-}
-
-/*****************************************************************************
- * safe_read : Buffered reading method
- *****************************************************************************/
-
-ssize_t safe_read( options_t *options, unsigned char *buf, int count )
-{
- int ret, cnt=0;
-
- while( cnt < count )
- {
- ret = read( options->in, buf + cnt, count - cnt );
-
- if( ret < 0 )
- return ret;
-
- if( ret == 0 )
- {
- /* zero means end of file */
- if( p_main->p_playlist->i_index )
- {
- file_next( options );
- }
- else
- {
- break;
- }
- }
-
- cnt += ret;
- }
-
- return cnt;
-}
-
-/******************************************************************************
- * keep_pcr : Put a TS packet in the fifo if it owns a PCR
- ******************************************************************************/
-
-int keep_pcr(int pcr_pid, file_ts_packet *ts)
-{
- own_pcr_t * p_own_pcr = &input_file.own_pcr;
-
-#define p ((u8 *)ts)
- if ((p[3] & 0x20) && p[4] && (p[5] & 0x10)
- && ((((p[1]<<8)+p[2]) & 0x1FFF) == pcr_pid))
- {
- /* adaptation_field_control is set, adaptation_field_lenght is not 0,
- * PCR_flag is set, pid == pcr_pid */
- vlc_mutex_lock(&p_own_pcr->lock);
- p_own_pcr->buf[p_own_pcr->end++] = ts;
- p_own_pcr->end %= (BUF_SIZE+1)*TS_IN_UDP+1;
- vlc_mutex_unlock(&p_own_pcr->lock);
- return 1;
- }
- else
- return 0;
-#undef p
-}
-
-/******************************************************************************
- * get_pid : gets a pid from a PES type
- ******************************************************************************/
-
-int get_pid (ps_t *p_ps)
-{
- int i, tofind, delta;
- char* type;
-
- switch( p_ps->pes_type )
- {
- case VIDEO_PES:
- delta = 0x20; /* 0x20 - 0x2f */
- type = "MPEG video";
- tofind = p_ps->pes_id;
- break;
- case AUDIO_PES:
- delta = 0x40; /* 0x40 - 0x5f */
- type = "MPEG audio";
- tofind = p_ps->pes_id;
- break;
- /* XXX: 0x64 is for the PMT, so don't take it !!! */
- case AC3_PES:
- delta = 0x80; /* 0x80 - 0x8f */
- type = "MPEG private (AC3 audio)";
- tofind = p_ps->private_id;
- break;
- case LPCM_PES:
- delta = 0x90; /* 0x90 - 0x9f */
- type = "MPEG private (LPCM audio)";
- tofind = p_ps->private_id;
- break;
- case SUBTITLE_PES:
- delta = 0xa0; /* 0xa0 - 0xbf */
- type = "MPEG private (DVD subtitle)";
- tofind = p_ps->private_id;
- break;
- default:
- return(-1);
-
- }
-
- i = delta + (tofind & 0x1f);
-
- if( p_ps->association_table[i] == 0)
- {
- intf_Msg( "Found %s stream at 0x%.2x, allocating PID 0x%.2x\n",
- type, tofind, i );
- p_ps->association_table[i] = 1;
- }
-
- return ( i );
-
-}
-
-/******************************************************************************
- * write_media_ts : writes a ts packet from a ps stream
- ******************************************************************************/
-
-void write_media_ts(ps_t *ps, unsigned char *ts, unsigned int pid)
-{
- int i,j;
- s64 clock;
- long int extclock;
-
- /* if offset == 0, it means we haven't examined the PS yet */
- if (ps->offset == 0)
- {
- if (ps->pes_size < 184) {
-
- ts[0] = 0x47; /* sync_byte */
- ts[1] = 0x40; /* payload_unit_start_indicator si début de PES */
- ts[2] = pid;
-
- ts[3] = 0x30 + (ps->media_counter[pid] & 0x0f);
- ts[4] = 184 - ps->pes_size - 1;
- ts[5] = 0x00;
- for (i=6 ; i < 188 - ps->pes_size ; i++) ts[i]=0xFF; /* facultatif ? */
- memcpy(ts + 188 - ps->pes_size, ps->ps_data, ps->pes_size);
-
- /* this PS is finished, next time we'll pick a new one */
- ps->pes_type = NO_PES;
- ps->ps_data += ps->pes_size;
- ps->offset += ps->pes_size;
- return;
-
- }
- }
-
- /* now we still can have offset == 0, but size is initialized */
-
- ts[0] = 0x47; /* sync_byte */
- ts[1] = (ps->offset == 0) ? 0x40 : 0x00; /* payload_unit_start_indicator si début de PES */
- ts[2] = pid;
-
- if ( (ps->offset == 0) && (ps->has_pts == 0xc0) && (ps->pcr_pid == pid) )
- {
-
- ts[3] = 0x30 + (ps->media_counter[pid] & 0x0f);
- ts[4] = 0x07; /* taille de l'adaptation field */
- ts[5] = 0x50; /* rtfm */
-
- /* on va lire le PTS */
- clock = ( ((s64)(ps->ps_data[9] & 0x0E) << 29) |
- (((s64)U16_AT(ps->ps_data + 10) << 14) - (1 << 14)) |
- ((s64)U16_AT(ps->ps_data + 12) >> 1) );
-
- ps->has_pts = 0;
-
- extclock = 0x000;
- ts[6] = (clock & 0x1fe000000) >> 25; /* ---111111110000000000000000000000000 */
- ts[7] = (clock & 0x001fe0000) >> 17; /* ---000000001111111100000000000000000 */
- ts[8] = (clock & 0x00001fe00) >> 9; /* ---000000000000000011111111000000000 */
- ts[9] = (clock & 0x0000001fe) >> 1; /* ---000000000000000000000000111111110 */
-
- ts[10] = 0x7e + ((clock & 0x01) << 7) + ((extclock & 0x100) >> 8);
- ts[11] = extclock & 0xff;
-
- memcpy(ts + 4 + 8, ps->ps_data, 184 - 8);
-
- ts[15] = 0xe0; /* FIXME : we don't know how to choose program yet */
-
- ps->offset += 184 - 8;
- ps->ps_data += 184 - 8;
- }
- else if (ps->offset <= ps->pes_size - 184)
- {
-
- ts[3] = 0x10 + (ps->media_counter[pid] & 0x0f);
- memcpy(ts + 4, ps->ps_data, 184);
-
- ps->offset += 184;
- ps->ps_data += 184;
-
- }
- else
- {
-
- j = ps->pes_size - ps->offset;
- ts[3] = 0x30 + (ps->media_counter[pid] & 0x0f);
- ts[4] = 184 - j - 1;
- ts[5] = 0x00;
- for (i=6 ; i < 188 - j ; i++) ts[i]=0xFF; /* facultatif ? */
- memcpy(ts + 4 + 184 - j, ps->ps_data, j);
- ps->offset += j; /* offset = size */
- ps->ps_data += j; /* offset = size */
-
- /* the PES is finished */
- ps->pes_type = NO_PES;
- ps->sent_ts++;
-
- }
-
-}
-
-/******************************************************************************
- * write_pat : writes a program association table
- ******************************************************************************/
-
-void write_pat(ps_t *ps, unsigned char *ts)
-{
- int i;
-
- ts[0] = 0x47; /* sync_byte */
- ts[1] = 0x40;
- ts[2] = 0x00; /* PID = 0x0000 */
- ts[3] = 0x10 + (ps->pat_counter & 0x0f);
- ts[4] = ts[5] = 0x00;
-
- ts[6] = 0xb0; /* */
- ts[7] = 0x11; /* section_length = 0x011 */
-
- ts[8] = 0x00;
- ts[9] = 0xb0; /* TS id = 0x00b0 */
-
- ts[10] = 0xc1;
- /* section # and last section # */
- ts[11] = ts[12] = 0x00;
-
- /* Network PID (useless) */
- ts[13] = ts[14] = 0x00; ts[15] = 0xe0; ts[16] = 0x10;
-
- /* Program Map PID */
- ts[17] = 0x03; ts[18] = 0xe8; ts[19] = 0xe0; ts[20] = 0x64;
-
- /* CRC */
- ts[21] = 0x4d; ts[22] = 0x6a; ts[23] = 0x8b; ts[24] = 0x0f;
-
- for (i=25 ; i < 188 ; i++) ts[i]=0xFF; /* facultatif ? */
-
- ps->sent_ts++;
-}
-
-/******************************************************************************
- * write_pmt : writes a program map table
- ******************************************************************************/
-
-void write_pmt(ps_t *ps, unsigned char *ts)
-{
- int i;
-
- ts[0] = 0x47; /* sync_byte */
- ts[1] = 0x40;
- ts[2] = 0x0064; /* PID = 0x0064 */
- ts[3] = 0x10 + (ps->pmt_counter & 0x0f);
-
- ts[4] = 0x00;
- ts[5] = 0x02;
-
- ts[6] = 0xb0; /* */
- ts[7] = 0x34; /* section_length = 0x034 */
-
- ts[8] = 0x03;
- ts[9] = 0xe8; /* prog number */
-
- ts[10] = 0xc1;
- /* section # and last section # */
- ts[11] = ts[12] = 0x00;
-
- /* PCR PID */
- ts[13] = 0xe0;
- ts[14] = 0x20;
-
- /* program_info_length == 0 */
- ts[15] = 0xf0; ts[16] = 0x00;
-
- /* Program Map / Video PID */
- ts[17] = 0x02; /* stream type = video */
- ts[18] = 0xe0; ts[19] = 0x20;
- ts[20] = 0xf0; ts[21] = 0x09; /* es info length */
-
- /* useless info */
- ts[22] = 0x07; ts[23] = 0x04; ts[24] = 0x08; ts[25] = 0x80; ts[26] = 0x24;
- ts[27] = 0x02; ts[28] = 0x11; ts[29] = 0x01; ts[30] = 0xfe;
-
- switch ( ps->audio_type )
- {
- case 12 :
- case REQUESTED_AC3 :
- /* ac3 */
- ts[31] = 0x81; /* stream type = audio */
- ts[32] = 0xe0; ts[33] = 0x80 + ps->audio_channel;
- ts[34] = 0xf0; ts[35] = 0x00; /* es info length */
- break;
-
- case REQUESTED_MPEG :
- /* mpeg */
- ts[31] = 0x04; /* stream type = audio */
- ts[32] = 0xe0; ts[33] = 0x40 + ps->audio_channel;
- ts[34] = 0xf0; ts[35] = 0x00; /* es info length */
- break;
-
- case REQUESTED_LPCM :
- /* LPCM audio */
- ts[31] = 0x81;
- ts[32] = 0xe0; ts[33] = 0xa0 + ps->audio_channel;
- ts[34] = 0xf0; ts[35] = 0x00; /* es info length */
- break;
-
- default :
- /* No audio */
- ts[31] = 0x00;
- ts[35] = 0x00; /* es info length */
- }
-
- /* Subtitles */
- if( ps->subtitles_channel == NO_SUBTITLES )
- {
- ts[36] = 0x00;
- ts[37] = 0x00; ts[38] = 0x00;
- ts[39] = 0xf0; ts[40] = 0x00; /* es info length */
- }
- else
- {
- ts[36] = 0x82;
- ts[37] = 0xe0; ts[38] = 0xa0 + ( ps->subtitles_channel );
- ts[39] = 0xf0; ts[40] = 0x00; /* es info length */
- }
-
- /* CRC FIXME: not calculated yet*/
- ts[41] = 0x96; ts[42] = 0x70; ts[43] = 0x0b; ts[44] = 0x7c;
-
- /* stuffing bytes */
- for (i=45 ; i < 188 ; i++) ts[i]=0xff; /* facultatif ? */
-
- ps->sent_ts++;
-}
-
-
-/******************************************************************************
- * ps_thread
- ******************************************************************************
- * We use threading to allow cool non-blocking read from the disk. This
- * implicit thread is the disk (producer) thread, it reads packets from
- * the PS file on the disk, and stores them in a FIFO.
- ******************************************************************************/
-
-void ps_thread( input_file_t * p_if )
-{
- int i;
- ps_t * p_ps = &p_if->ps;
- own_pcr_t * p_own_pcr = &p_if->own_pcr;
- in_data_t * p_in_data = &p_if->in_data;
-
- /* Initialize the structures */
- p_own_pcr->start = p_own_pcr->end = 0; /* empty FIFO */
- vlc_mutex_init( &p_own_pcr->lock );
- p_in_data->start = p_in_data->end = 0; /* empty FIFO */
- vlc_mutex_init( &p_in_data->lock );
- vlc_cond_init( &p_in_data->notfull );
- vlc_cond_init( &p_in_data->notempty );
-
- p_ps->audio_type = main_GetIntVariable( INPUT_DVD_AUDIO_VAR, REQUESTED_AC3 );
- p_ps->audio_channel = main_GetIntVariable( INPUT_DVD_CHANNEL_VAR, 0 );
- p_ps->subtitles_channel = main_GetIntVariable( INPUT_DVD_SUBTITLE_VAR, 0 );
-
- p_ps->pes_type = NO_PES;
- p_ps->pes_id = 0;
- p_ps->private_id = 0;
- p_ps->pes_size = 0;
- p_ps->to_skip = 0;
- p_ps->pmt_counter = 0;
- p_ps->pat_counter = 0;
- for( i=0; i<256; i++ )
- p_ps->association_table[i] = 0;
- p_ps->offset = 0;
- p_ps->found_pts = 0;
- p_ps->found_streams = 0;
- p_ps->pcr_pid = p_if->options.pcr_pid;
-
- p_ps->ps_buffer = malloc(PS_BUFFER_SIZE);
- /* those 2 addresses are initialized so that a new packet is read */
- p_ps->ps_data = p_ps->ps_buffer + PS_BUFFER_SIZE - 1;
- /* fix the first byte stuff */
- p_ps->ps_data[0] = 0x00;
- p_ps->ps_end = p_ps->ps_buffer + PS_BUFFER_SIZE;
-
- /* Fill the fifo until it is full */
- ps_fill( p_if, 0 );
- /* Launch the thread which fills the fifo */
- vlc_thread_create( &p_if->disk_thread, "disk thread",
- (vlc_thread_func_t)input_DiskThread, p_if );
- /* Init the synchronization XXX add error detection !!! */
- init_synchro( p_if );
-}
-
-/******************************************************************************
- * ps_read : ps reading method
- ******************************************************************************/
-
-ssize_t ps_read( options_t *p_options, ps_t * p_ps, void *ts )
-{
- int pid, readbytes = 0;
- int datasize;
- p_ps->ts_written = 0;
-
- while(p_ps->ts_to_write)
- {
-
- /* if there's not enough data to send */
- if((datasize = p_ps->ps_end - p_ps->ps_data) <= TS_PACKET_SIZE)
- {
- /* copy the remaining bits at the beginning of the PS buffer */
- memmove ( p_ps->ps_buffer, p_ps->ps_data, datasize);
- /* read some bytes */
- readbytes = safe_read( p_options, p_ps->ps_buffer + datasize, PS_BUFFER_SIZE - datasize);
-
- if(readbytes <= 0)
- {
- input_file.b_die = 1;
- return -1;
- }
- p_ps->ps_data = p_ps->ps_buffer;
- p_ps->ps_end = p_ps->ps_data + datasize + readbytes;
- }
-
- //printf("offset is %x, pes total size is %x, to skip is %x\n", p_ps->offset, p_ps->pes_size, p_ps->to_skip );
- if( p_ps->to_skip == 0 && p_ps->offset == p_ps->pes_size )
- {
- if( p_ps->ps_data[0] || p_ps->ps_data[1] || (p_ps->ps_data[2] != 0x01) )
- {
- intf_ErrMsg ( "input error: not a startcode (0x%.2x%.2x%.2x instead of 0x000001)\n", p_ps->ps_data[0], p_ps->ps_data[1], p_ps->ps_data[2] );
- return -1;
- }
-
- p_ps->pes_type = NO_PES;
- p_ps->offset = 0;
- p_ps->pes_size = (p_ps->ps_data[4] << 8) + p_ps->ps_data[5] + 6;
- p_ps->has_pts = p_ps->ps_data[7] & 0xc0;
- }
-
- /* if the actual data we have in pes_data is not a PES, then
- * we read the next one. */
- if( (p_ps->pes_type == NO_PES) && !p_ps->to_skip )
- {
- p_ps->pes_id = p_ps->ps_data[3];
-
- if (p_ps->pes_id == 0xbd)
- {
- p_ps->private_id = p_ps->ps_data[ 9 + p_ps->ps_data[8] ];
- if ((p_ps->private_id & 0xf0) == 0x80)
- {
- /* flux audio ac3 */
- p_ps->pes_type = AC3_PES;
- }
- else if ((p_ps->private_id & 0xf0) == 0x20)
- {
- /* subtitles */
- p_ps->pes_type = SUBTITLE_PES;
- }
- else
- {
- /* unknown private data */
- p_ps->pes_type = PRIVATE_PES;
- }
- }
- else if ((p_ps->pes_id & 0xe0) == 0xc0)
- {
- /* flux audio */
- p_ps->pes_type = AUDIO_PES;
- //write (1, p_ps->ps_data + 9 + p_ps->ps_data[8], 2048 - (9 + p_ps->ps_data[8]));
- }
- else if ((p_ps->pes_id & 0xf0) == 0xe0)
- {
- /* flux video */
- p_ps->pes_type = VIDEO_PES;
- }
- else if (p_ps->pes_id == 0xba)
- {
- p_ps->pes_type = NO_PES;
- p_ps->pes_size = 14; /* 8 extra characters after 0x000001ba**** */
- p_ps->to_skip = 14;
- }
- else
- {
- p_ps->pes_type = UNKNOWN_PES;
- p_ps->to_skip = p_ps->pes_size;
- }
- }
-
- if( p_ps->to_skip )
- {
- if( p_ps->to_skip < TS_PACKET_SIZE )
- {
- p_ps->ps_data += p_ps->to_skip;
- p_ps->offset += p_ps->to_skip;
- p_ps->to_skip = 0;
- }
- else
- {
- p_ps->ps_data += TS_PACKET_SIZE;
- p_ps->offset += TS_PACKET_SIZE;
- p_ps->to_skip -= TS_PACKET_SIZE;
- }
- }
-
- /* now that we know what we have, we can either
- * write this packet's data in the buffer, skip it,
- * or write a PMT or PAT table and wait for the next
- * turn before writing the packet. */
- switch (p_ps->sent_ts & 0xff)
- {
- case 0x80:
- write_pmt(p_ps,ts);
- p_ps->pmt_counter++;
- p_ps->ts_to_write--; p_ps->ts_written++; ts+=188;
- break;
- case 0x00:
- write_pat(p_ps,ts);
- p_ps->pat_counter++;
- p_ps->ts_to_write--; p_ps->ts_written++; ts+=188;
- break;
- }
-
- /* if there's still no found PCR_PID, and no PTS in this PES, we trash it */
- if (!p_ps->found_pts)
- {
- if (p_ps->has_pts)
- {
- intf_Msg( "input: found a PTS, at last ...\n" );
- p_ps->found_pts = 1;
- }
- else
- p_ps->pes_type = NO_PES;
- }
-
- if (p_ps->ts_to_write)
- {
- switch(p_ps->pes_type)
- {
- case VIDEO_PES:
- case AUDIO_PES:
- case SUBTITLE_PES:
- case AC3_PES:
- pid = get_pid (p_ps);
- write_media_ts(p_ps, ts, pid);
- p_ps->ts_to_write--; p_ps->ts_written++; ts+=188;
- p_ps->media_counter[pid]++;
- break;
- case UNKNOWN_PES:
- default:
- p_ps->pes_type = NO_PES;
- break;
- }
- }
- }
-
- //p_ps->ps_data += TS_PACKET_SIZE;
-
- return p_ps->ts_written;
-}
-
-/******************************************************************************
- * ps_fill : Fill the data buffer with TS created from a PS file
- ******************************************************************************/
-
-void ps_fill( input_file_t * p_if, boolean_t wait )
-{
- in_data_t * p_in_data = &p_if->in_data;
- ps_t * p_ps = &p_if->ps;
- int i, howmany;
- int pcr_flag;
- file_ts_packet *ts;
-
- /* How many TS packet for the next UDP packet */
- howmany = TS_IN_UDP;
-
- pcr_flag = 0;
- /* for every single TS packet */
- while( !p_if->b_die )
- {
- /* wait until we have one free item to store the UDP packet read */
- vlc_mutex_lock(&p_in_data->lock);
- while((p_in_data->end+BUF_SIZE+1-p_in_data->start)%(BUF_SIZE+1) == BUF_SIZE )
- {
- /* The buffer is full */
- if(wait)
- {
- vlc_cond_wait(&p_in_data->notfull, &p_in_data->lock);
- if( p_if->b_die )
- return;
- }
- else
- {
- vlc_mutex_unlock(&p_in_data->lock);
- if (!pcr_flag)
- {
- intf_ErrMsg( "input error: bad PCR PID\n" );
- }
- return;
- }
- }
- vlc_mutex_unlock(&p_in_data->lock);
-
- /* read a whole UDP packet from the file */
- p_ps->ts_to_write = howmany;
- if( ps_read( &p_if->options, p_ps, ts = (file_ts_packet *)(p_in_data->buf + p_in_data->end) ) != howmany )
- {
- msleep( 50000 ); /* XXX we need an INPUT_IDLE */
- return;
- }
-
- /* Scan to mark TS packets containing a PCR */
- for( i = 0 ; i < howmany ; i++ , ts++ )
- {
- pcr_flag |= keep_pcr( p_ps->pcr_pid, ts );
- }
-
- vlc_mutex_lock( &p_in_data->lock );
- p_in_data->end++;
- p_in_data->end %= BUF_SIZE + 1;
- vlc_cond_signal( &p_in_data->notempty );
- vlc_mutex_unlock( &p_in_data->lock );
- }
-}
-
-int init_synchro( input_file_t * p_if )
-{
- int i, pcr_count;
- int howmany = TS_IN_UDP;
- file_ts_packet * ts;
- synchro_t * p_synchro = &p_if->synchro;
- in_data_t * p_in_data = &p_if->in_data;
- own_pcr_t * p_own_pcr = &p_if->own_pcr;
-
- p_synchro->slope = 0;
- pcr_count = 0;
-
- /*
- * Initialisation of the synchro mecanism : wait for 1 PCR
- * to evaluate delta_clock
- */
-
- while( 1 )
- {
- vlc_mutex_lock( &p_in_data->lock );
-
- while( p_in_data->end == p_in_data->start )
- {
- vlc_cond_wait(&p_in_data->notempty, &p_in_data->lock);
- }
-
- vlc_mutex_unlock( &p_in_data->lock );
-
- ts = (file_ts_packet*)(p_in_data->buf + p_in_data->start);
- for( i=0 ; i < howmany ; i++, ts++ )
- {
- if( ts == p_own_pcr->buf[p_own_pcr->start] && !(((u8*)ts)[5] & 0x80) )
- {
- p_synchro->last_pcr = ts;
- p_synchro->last_pcr_time = ConvertPCRTime( ts );
- p_synchro->delta_clock = mdate() - ConvertPCRTime(ts);
- adjust( p_if, ts );
- pcr_count++;
- }
- }
-
- vlc_mutex_lock( &p_in_data->lock );
- p_in_data->start++;
- p_in_data->start %= BUF_SIZE + 1;
- vlc_cond_signal( &p_in_data->notfull );
- vlc_mutex_unlock( &p_in_data->lock );
-
- if(pcr_count)
- break;
- }
- return( 0 );
-}
-
-/*****************************************************************************
- * input_DiskThread : main thread
- *****************************************************************************/
-
-void input_DiskThread( input_file_t * p_if )
-{
- ps_fill( p_if, 1 );
- vlc_thread_exit();
-}
-
-/*****************************************************************************
- * input_FileOpen : open a file descriptor
- *****************************************************************************/
-int input_FileOpen( input_thread_t *p_input )
-{
- options_t * p_options = &input_file.options;
-
- p_options->in = -1;
-
- if( file_next( p_options ) < 0 )
- {
- intf_ErrMsg( "input error: cannot open the file %s\n",
- p_input->p_source );
- return( 1 );
- }
-
- input_file.b_die = 0;
- if( safe_read( p_options, &p_options->i_file_type, 1 ) <= 0 )
- {
- intf_ErrMsg( "input error: cannot read file type\n");
- close( p_options->in );
- return( 1 );
- }
-
- switch( p_options->i_file_type )
- {
- case 0x00:
- p_options->pcr_pid = PCR_PID;
- ps_thread( &input_file );
- break;
- case 0x47:
- intf_ErrMsg( "input error: ts files are not currently supported\n" );
- close( p_options->in );
- return( 1 );
- default:
- intf_ErrMsg( "input error: cannot determine stream type\n" );
- close( p_options->in );
- return( 1 );
- }
-
- return( 0 );
-}
-
-/*****************************************************************************
- * input_FileRead : read from a file
- *****************************************************************************/
-int input_FileRead( input_thread_t *p_input, const struct iovec *p_vector,
- size_t i_count )
-{
- in_data_t * p_in_data = &input_file.in_data;
- synchro_t * p_synchro = &input_file.synchro;
- own_pcr_t * p_own_pcr = &input_file.own_pcr;
- int i, howmany;
- file_ts_packet * ts;
-
- /* XXX XXX XXX
- * End condition not verified, should put a flag in ps_fill
- */
- howmany = TS_IN_UDP;
-
- vlc_mutex_lock( &p_in_data->lock );
- while( p_in_data->end == p_in_data->start )
- {
- if( input_file.b_die )
- {
- vlc_mutex_unlock( &p_in_data->lock );
- /* wait 1 second, like the network input */
- msleep( 1000000 );
- return( 0 );
- }
-
- vlc_cond_wait( &p_in_data->notempty, &p_in_data->lock );
- }
- vlc_mutex_unlock( &p_in_data->lock );
-
- ts = (file_ts_packet*)(p_in_data->buf + p_in_data->start);
- for( i=0 ; i < howmany ; i++, ts++ )
- {
- if( p_synchro->slope && (i == howmany-1) )
- {
- wait_a_moment( &input_file, ts );
- }
- if( ts == p_own_pcr->buf[p_own_pcr->start] )
- {
- /* the TS packet contains a PCR, so we try to adjust the clock */
- adjust( &input_file, ts );
- }
- }
-
- for( i=0 ; i<howmany ; i++ )
- {
- memcpy( p_vector[i].iov_base, (char*)(ts - howmany + i), p_vector[i].iov_len );
- }
-
- vlc_mutex_lock(&p_in_data->lock);
- p_in_data->start++;
- p_in_data->start %= BUF_SIZE + 1;
- vlc_cond_signal(&p_in_data->notfull);
- vlc_mutex_unlock(&p_in_data->lock);
-
- return( 188 * howmany );
-}
-
-/*****************************************************************************
- * input_FileClose : close a file descriptor
- *****************************************************************************/
-void input_FileClose( input_thread_t *p_input )
-{
- input_file.b_die = 1;
- vlc_cond_signal( &input_file.in_data.notfull );
- vlc_thread_join( input_file.disk_thread );
-
- close( input_file.options.in );
-}
-
+++ /dev/null
-/*****************************************************************************
- * input_file.h: file streams functions interface
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * 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.
- *****************************************************************************/
-
-/*****************************************************************************
- * Prototypes
- *****************************************************************************/
-int input_FileOpen ( input_thread_t *p_input );
-int input_FileRead ( input_thread_t *p_input, const struct iovec *p_vector,
- size_t i_count );
-void input_FileClose ( input_thread_t *p_input );
+++ /dev/null
-/*****************************************************************************
- * netlist.c: input thread
- * Manages the TS and PES netlists (see netlist.h).
- *****************************************************************************
- * Copyright (C) 1998, 1999, 2000 VideoLAN
- *
- * Authors: Christophe Massiot <massiot@via.ecp.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#include "defs.h"
-
-#include <sys/types.h> /* on BSD, uio.h needs types.h */
-#include <sys/uio.h> /* "input.h" */
-
-#include <stdlib.h> /* free() */
-#include <string.h> /* strerror() */
-#include <errno.h> /* errno */
-
-#include "config.h"
-#include "common.h"
-#include "threads.h"
-#include "mtime.h"
-#include "intf_msg.h"
-#include "debug.h"
-#include "input.h"
-#include "input_netlist.h"
-
-/*****************************************************************************
- * Local prototypes
- *****************************************************************************/
-
-/*****************************************************************************
- * input_NetlistOpen: initialize the netlists buffers
- *****************************************************************************/
-int input_NetlistInit( input_thread_t *p_input )
-{
- int i_base, i_packets, i_iovec;
-
- /* Initialize running indexes. */
-#ifdef INPUT_LIFO_TS_NETLIST
- p_input->netlist.i_ts_index = INPUT_TS_READ_ONCE;
-#else
- p_input->netlist.i_ts_start = 0;
- p_input->netlist.i_ts_end = 0;
-#endif
-#ifdef INPUT_LIFO_PES_NETLIST
- p_input->netlist.i_pes_index = 1; /* We allocate one PES at a time */
-#else
- p_input->netlist.i_pes_start = 0;
- p_input->netlist.i_pes_end = 0;
-#endif
-
- /* Initialize all iovec from the TS netlist with the length of a packet */
- for( i_iovec = 0; i_iovec < INPUT_MAX_TS + INPUT_TS_READ_ONCE; i_iovec++ )
- {
- p_input->netlist.p_ts_free[i_iovec].iov_len = TS_PACKET_SIZE;
- }
-
- /* Allocate a big piece of memory to contain the INPUT_MAX_TS TS packets */
- if( ( p_input->netlist.p_ts_packets = malloc( (INPUT_MAX_TS + 1)
- * sizeof(ts_packet_t) ) ) == NULL )
- {
- intf_ErrMsg("input error: can't allocate TS netlist buffer (%s)\n",
- strerror(errno) );
- return( -1 );
- }
-
- /* Allocate a big piece of memory to contain the INPUT_MAX_PES PES packets */
- if( !( p_input->netlist.p_pes_packets = malloc( (INPUT_MAX_PES + 1)
- * sizeof(pes_packet_t) ) ) )
- {
- intf_ErrMsg("input error: can't allocate PES netlist buffer (%s)\n",
- strerror(errno) );
- free( p_input->netlist.p_ts_packets );
- return( -1 );
- }
-
- /* Insert TS packets into the TS netlist */
-#ifdef INPUT_LIFO_TS_NETLIST
- i_base = p_input->netlist.i_ts_index;
-#else
- i_base = p_input->netlist.i_ts_start;
-#endif
- /* i_base is now the base address to locate free packets in the netlist */
-
- for( i_packets = 0; i_packets < INPUT_MAX_TS + 1; i_packets++ )
- {
- p_input->netlist.p_ts_free[i_base + i_packets].iov_base
- = (void *)(p_input->netlist.p_ts_packets + i_packets);
- /* Initialize TS length. */
- (p_input->netlist.p_ts_packets[i_packets]).i_payload_end = TS_PACKET_SIZE;
- }
-
- /* Insert PES packets into the netlist */
-#ifdef INPUT_LIFO_PES_NETLIST
- i_base = p_input->netlist.i_pes_index;
-#else
- i_base = p_input->netlist.i_pes_start;
-#endif
- /* i_base is now the base address to locate free packets in the netlist */
-
- for( i_packets = 0; i_packets < INPUT_MAX_PES + 1; i_packets++ )
- {
- p_input->netlist.p_pes_free[i_base + i_packets]
- = p_input->netlist.p_pes_packets + i_packets;
- }
-
- /* the p_pes_header_save buffer is allocated on the fly by the PES
- demux if needed, and freed with the PES packet when the netlist
- is destroyed. We initialise the field to NULL so that the demux
- can determine if it has already allocated this buffer or not. */
- for( i_packets = 0; i_packets < INPUT_MAX_PES + 1; i_packets++ )
- {
- p_input->netlist.p_pes_packets[i_packets].p_pes_header_save = NULL;
- }
-
- return( 0 );
-}
-
-/*****************************************************************************
- * input_NetlistClean: clean the netlists buffers
- *****************************************************************************/
-void input_NetlistEnd( input_thread_t *p_input )
-{
- int i;
-
- /* free TS netlist */
- free( p_input->netlist.p_ts_packets );
-
- /* free the pes_buffer_save buffers of the PES packets if they have
- been allocated */
- for( i = 0; i < INPUT_MAX_PES + 1; i++ )
- {
- byte_t* p_buffer = p_input->netlist.p_pes_packets[i].p_pes_header_save;
- if(p_buffer)
- free(p_buffer);
- }
-
- /* free PES netlist */
- free( p_input->netlist.p_pes_packets );
-}
-
+++ /dev/null
-/*****************************************************************************
- * network.c: functions to read from the network
- * Manages a socket.
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * Authors: Christophe Massiot <massiot@via.ecp.fr>
- * Benoît Steiner <benny@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 "defs.h"
-
-#include <sys/types.h> /* on BSD, uio.h needs types.h */
-#include <sys/uio.h> /* "input.h" */
-#include <string.h> /* strerror() */
-#include <unistd.h> /* close() */
-#include <errno.h> /* errno */
-#include <sys/time.h> /* "input_network.h" */
-
-#if defined(SYS_BSD) || defined(SYS_BEOS)
-#include <sys/socket.h> /* struct sockaddr */
-#endif
-
-#include <netdb.h> /* servent, getservbyname(), hostent, gethostbyname() */
-#include <netinet/in.h> /* sockaddr_in, htons(), htonl() */
-
-#include "config.h"
-#include "common.h"
-#include "threads.h"
-#include "mtime.h"
-#include "netutils.h"
-
-#include "input.h"
-#include "input_network.h"
-#include "input_vlan.h"
-
-#include "intf_msg.h"
-#include "plugins.h"
-#include "main.h"
-
-/*****************************************************************************
- * input_NetworkOpen: initialize a network stream
- *****************************************************************************/
-int input_NetworkOpen( input_thread_t *p_input )
-{
- int i_socket_option;
- struct sockaddr_in sa_in;
- char psz_hostname[INPUT_MAX_SOURCE_LENGTH];
-
- /* First and foremost, in the VLAN method, join the desired VLAN. */
- if( p_input->i_method == INPUT_METHOD_TS_VLAN_BCAST )
- {
- if( input_VlanJoin( p_input->i_vlan ) )
- {
- intf_ErrMsg("error: can't join vlan %d\n", p_input->i_vlan);
- return( 1 );
- }
- }
-
- /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0)
- * protocol */
- if( (p_input->i_handle = socket( AF_INET, SOCK_DGRAM, 0 )) == (-1) )
- {
- intf_ErrMsg("error: can't create socket (%s)\n", strerror(errno));
- return( 1 );
- }
-
- /*
- * Set up the options of the socket
- */
-
- /* Set SO_REUSEADDR option which allows to re-bind() a busy port */
- i_socket_option = 1;
- if( setsockopt( p_input->i_handle,
- SOL_SOCKET,
- SO_REUSEADDR,
- &i_socket_option,
- sizeof( i_socket_option ) ) == (-1) )
- {
- intf_ErrMsg("error: can't configure socket (SO_REUSEADDR: %s)\n", strerror(errno));
- close( p_input->i_handle );
- return( 1 );
- }
-
-#ifndef SYS_BEOS
- /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
- * packet loss caused by scheduling problems */
- i_socket_option = 524288;
- if( setsockopt( p_input->i_handle,
- SOL_SOCKET,
- SO_RCVBUF,
- &i_socket_option,
- sizeof( i_socket_option ) ) == (-1) )
- {
- intf_ErrMsg("error: can't configure socket (SO_RCVBUF: %s)\n", strerror(errno));
- close( p_input->i_handle );
- return( 1 );
- }
-#endif /* SYS_BEOS */
-
- /*
- * Bind the socket
- */
-
- /* Use default port if not specified */
- if( p_input->i_port == 0 )
- {
- p_input->i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );
- }
-
- /* See if the user requested broadcast method */
- if( main_GetIntVariable( INPUT_BROADCAST_VAR, INPUT_BROADCAST_DEFAULT ) )
- {
- p_input->i_method = INPUT_METHOD_TS_BCAST;
- }
-
- /* Find the address. */
- switch( p_input->i_method )
- {
- case INPUT_METHOD_TS_BCAST:
- case INPUT_METHOD_TS_VLAN_BCAST:
- /* In that case, we have to bind with the broadcast address.
- * broadcast addresses are very hard to find and depends on
- * implementation, so we thought using a #define would be much
- * simpler. */
-#ifdef INPUT_BCAST_ADDR
- if( BuildInetAddr( &sa_in, INPUT_BCAST_ADDR, p_input->i_port ) == (-1) )
- {
- close( p_input->i_handle );
- return( 1 );
- }
-#else
- /* We bind with any address. Security problem ! */
- if( BuildInetAddr( &sa_in, NULL, p_input->i_port ) == (-1) )
- {
- close( p_input->i_handle );
- return( -1 );
- }
-#endif
- break;
-
- case INPUT_METHOD_TS_UCAST:
- /* Unicast: bind with the local address. */
- if( gethostname( psz_hostname, sizeof( psz_hostname ) ) == (-1) )
- {
- intf_ErrMsg("error: can't get hostname (%s)\n", strerror(errno));
- close( p_input->i_handle );
- return( 1 );
- }
- if( BuildInetAddr( &sa_in, psz_hostname, p_input->i_port ) == (-1) )
- {
- close( p_input->i_handle );
- return( 1 );
- }
- break;
-
- case INPUT_METHOD_TS_MCAST:
- /* Multicast: bind with 239.0.0.1. */
- if( BuildInetAddr( &sa_in, "239.0.0.1", p_input->i_port ) == (-1) )
- {
- close( p_input->i_handle );
- return( 1 );
- }
- break;
- }
-
- /* Effectively bind the socket. */
- if( bind( p_input->i_handle, (struct sockaddr *) &sa_in, sizeof( sa_in ) ) < 0 )
- {
- intf_ErrMsg("error: can't bind socket (%s)\n", strerror(errno));
- close( p_input->i_handle );
- return( 1 );
- }
-
- /*
- * Connect the socket to the remote server
- */
-
- /* Use default host if not specified */
- if( p_input->p_source == NULL )
- {
- p_input->p_source = main_GetPszVariable( INPUT_SERVER_VAR, INPUT_SERVER_DEFAULT );
- }
-
- if( BuildInetAddr( &sa_in, p_input->p_source, htons(0) ) == (-1) )
- {
- close( p_input->i_handle );
- return( -1 );
- }
-
- /* Connect the socket. */
- if( connect( p_input->i_handle, (struct sockaddr *) &sa_in,
- sizeof( sa_in ) ) == (-1) )
- {
- intf_ErrMsg("error: can't connect socket\n" );
- close( p_input->i_handle );
- return( 1 );
- }
- return( 0 );
-}
-
-/*****************************************************************************
- * input_NetworkRead: read a stream from the network
- *****************************************************************************
- * Wait for data during up to 1 second and then abort if none is arrived. The
- * number of bytes read is returned or -1 if an error occurs (so 0 is returned
- * after a timeout)
- * We don't have to make any test on presentation times, since we suppose
- * the network server sends us data when we need it.
- *****************************************************************************/
-int input_NetworkRead( input_thread_t *p_input, const struct iovec *p_vector,
- size_t i_count )
-{
- fd_set rfds;
- struct timeval tv;
- int i_rc;
-
- /* Watch the given fd to see when it has input */
- FD_ZERO(&rfds);
- FD_SET(p_input->i_handle, &rfds);
-
- /* Wait up to 1 second */
- tv.tv_sec = 1;
- tv.tv_usec = 0;
-
- i_rc = select(p_input->i_handle+1, &rfds, NULL, NULL, &tv);
-
- if( i_rc > 0 )
- {
- /* Data were received before timeout */
- i_rc = readv( p_input->i_handle, p_vector, i_count );
- }
-
- return( i_rc );
-}
-
-/*****************************************************************************
- * input_NetworkClose: close a network stream
- *****************************************************************************/
-void input_NetworkClose( input_thread_t *p_input )
-{
- /* Close local socket. */
- if( p_input->i_handle )
- {
- close( p_input->i_handle );
- }
-
- /* Leave vlan if required */
- if( p_input->i_method == INPUT_METHOD_TS_VLAN_BCAST )
- {
- input_VlanLeave( p_input->i_vlan );
- }
-}
-
+++ /dev/null
-/*****************************************************************************
- * input_network.h: network functions interface
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * Authors: Christophe Massiot <massot@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.
- *****************************************************************************/
-
-/*****************************************************************************
- * Prototypes
- *****************************************************************************/
-int input_NetworkOpen ( input_thread_t *p_input );
-int input_NetworkRead ( input_thread_t *p_input, const struct iovec *p_vector,
- size_t i_count );
-void input_NetworkClose ( input_thread_t *p_input );
+++ /dev/null
-/*****************************************************************************
- * pcr.c: PCR management
- * Manages structures containing PCR information.
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * Authors: Jean-Marc Dressler <polux@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 "defs.h"
-
-#include <sys/types.h> /* on BSD, uio.h needs types.h */
-#include <sys/uio.h> /* "input.h" */
-#include <stdlib.h> /* atoi(), malloc(), free() */
-#include <netinet/in.h> /* ntohl() */
-
-#include "config.h"
-#include "common.h"
-#include "threads.h"
-#include "mtime.h"
-#include "debug.h"
-#include "input.h"
-#include "intf_msg.h"
-#include "input_pcr.h"
-
-/* Note:
- *
- * SYNCHRONIZATION METHOD
- *
- * We compute an average for the pcr because we want to eliminate the
- * network jitter and keep the low frequency variations. The average is
- * in fact a low pass filter and the jitter is a high frequency signal
- * that is why it is eliminated by the filter/average.
- *
- * The low frequency variations enable us to synchronize the client clock
- * with the server clock because they represent the time variation between
- * the 2 clocks. Those variations (ie the filtered pcr) are used to compute
- * the presentation dates for the audio and video frames. With those dates
- * we can decoding (or trashing) the MPEG2 stream at "exactly" the same rate
- * as it is sent by the server and so we keep the synchronization between
- * the server and the client.
- *
- * It is a very important matter if you want to avoid underflow or overflow
- * in all the FIFOs, but it may be not enough.
- *
- */
-
-/*****************************************************************************
- * input_PcrReInit : Reinitialize the pcr_descriptor
- *****************************************************************************/
-void input_PcrReInit( input_thread_t *p_input )
-{
- ASSERT( p_input );
-
- p_input->p_pcr->delta_pcr = 0;
- p_input->p_pcr->last_pcr = 0;
- p_input->p_pcr->c_average_count = 0;
-}
-
-/*****************************************************************************
- * input_PcrInit : Initialize PCR decoder
- *****************************************************************************/
-int input_PcrInit( input_thread_t *p_input )
-{
- ASSERT( p_input );
-
- if( (p_input->p_pcr = malloc(sizeof(pcr_descriptor_t))) == NULL )
- {
- return( -1 );
- }
- input_PcrReInit(p_input);
- p_input->p_pcr->i_synchro_state = SYNCHRO_NOT_STARTED;
-
- return( 0 );
-}
-
-/*****************************************************************************
- * input_PcrDecode : Decode a PCR frame
- *****************************************************************************/
-void input_PcrDecode( input_thread_t *p_input, es_descriptor_t *p_es,
- u8* p_pcr_data )
-{
- mtime_t pcr_time, sys_time, delta_pcr;
- pcr_descriptor_t *p_pcr;
-
- ASSERT( p_pcr_data );
- ASSERT( p_input );
- ASSERT( p_es );
-
- p_pcr = p_input->p_pcr;
-
- /* Convert the PCR in microseconde
- * WARNING: do not remove the casts in the following calculation ! */
- pcr_time = ( (( (mtime_t)U32_AT((u32*)p_pcr_data) << 1 ) | ( p_pcr_data[4] >> 7 )) * 300 ) / 27;
- sys_time = mdate();
- delta_pcr = sys_time - pcr_time;
-
- if( p_es->b_discontinuity ||
- ( p_pcr->last_pcr != 0 &&
- ( (p_pcr->last_pcr - pcr_time) > PCR_MAX_GAP
- || (p_pcr->last_pcr - pcr_time) < - PCR_MAX_GAP ) ) )
- {
- intf_DbgMsg("input debug: input_PcrReInit()\n");
- input_PcrReInit(p_input);
- p_pcr->i_synchro_state = SYNCHRO_REINIT;
- p_es->b_discontinuity = 0;
- }
- p_pcr->last_pcr = pcr_time;
-
- if( p_pcr->c_average_count == PCR_MAX_AVERAGE_COUNTER )
- {
- p_pcr->delta_pcr =
- ( delta_pcr + (p_pcr->delta_pcr * (PCR_MAX_AVERAGE_COUNTER-1)) )
- / PCR_MAX_AVERAGE_COUNTER;
- }
- else
- {
- p_pcr->delta_pcr =
- ( delta_pcr + (p_pcr->delta_pcr * p_pcr->c_average_count) )
- / ( p_pcr->c_average_count + 1 );
- p_pcr->c_average_count++;
- }
-
- if( p_pcr->i_synchro_state == SYNCHRO_NOT_STARTED )
- {
- p_pcr->i_synchro_state = SYNCHRO_START;
- }
-}
-
-/*****************************************************************************
- * input_PcrEnd : Clean PCR structures before dying
- *****************************************************************************/
-void input_PcrEnd( input_thread_t *p_input )
-{
- ASSERT( p_input );
-
- free( p_input->p_pcr );
-}
+++ /dev/null
-/*****************************************************************************
- * input_pcr.h: PCR management interface
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * Authors: Jean-Marc Dressler <polux@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.
- *****************************************************************************/
-
-/* Maximum number of samples used to compute the dynamic average value,
- * it is also the maximum of c_average in the pcr_descriptor_struct.
- * We use the following formula :
- * new_average = (old_average * c_average + new_sample_value) / (c_average +1) */
-#define PCR_MAX_AVERAGE_COUNTER 40
-
-/* Maximum gap allowed between two PCRs. */
-#define PCR_MAX_GAP 1000000
-
-/* synchro states */
-#define SYNCHRO_NOT_STARTED 1
-#define SYNCHRO_START 2
-#define SYNCHRO_REINIT 3
-
-/*****************************************************************************
- * Prototypes
- *****************************************************************************/
-int input_PcrInit ( input_thread_t *p_input );
-void input_PcrDecode ( input_thread_t *p_input, es_descriptor_t* p_es,
- u8* p_pcr_data );
-void input_PcrEnd ( input_thread_t *p_input );
--- /dev/null
+/*****************************************************************************
+ * input_ps.c: PS demux and packet management
+ *****************************************************************************
+ * Copyright (C) 1998, 1999, 2000 VideoLAN
+ *
+ * Authors:
+ *
+ * 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 "defs.h"
+
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <errno.h>
+
+#include "config.h"
+#include "common.h"
+#include "threads.h"
+#include "mtime.h"
+
+#include "intf_msg.h"
+
+#include "stream_control.h"
+#include "input_ext-intf.h"
+#include "input_ext-dec.h"
+
+#include "input.h"
+
+#include "input_ps.h"
+#include "mpeg_system.h"
+
+#include "debug.h"
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int PSProbe ( struct input_thread_s * );
+static void PSRead ( struct input_thread_s *,
+ data_packet_t * p_packets[INPUT_READ_ONCE] );
+static void PSInit ( struct input_thread_s * );
+static void PSEnd ( struct input_thread_s * );
+static struct data_packet_s * NewPacket ( void *, size_t );
+static void DeletePacket( void *, struct data_packet_s * );
+static void DeletePES ( void *, struct pes_packet_s * );
+
+/*
+ * Data reading functions
+ */
+
+/*****************************************************************************
+ * PSProbe: verifies that the stream is a PS stream
+ *****************************************************************************/
+static int PSProbe( input_thread_t * p_input )
+{
+ /* verify that the first three bytes are 0x000001, or unscramble and
+ * re-do. */
+ return 1;
+}
+
+/*****************************************************************************
+ * PSInit: initializes PS structures
+ *****************************************************************************/
+static void PSInit( input_thread_t * p_input )
+{
+ thread_ps_data_t * p_method;
+ stream_ps_data_t * p_demux;
+
+ if( (p_method =
+ (thread_ps_data_t *)malloc( sizeof(thread_ps_data_t) )) == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_input->b_error = 1;
+ return;
+ }
+
+ p_input->p_method_data = (void *)p_method;
+
+ /* Re-open the socket as a buffered FILE stream */
+ if( (p_method->stream = fdopen( p_input->i_handle, "r" )) == NULL )
+ {
+ intf_ErrMsg( "Cannot open file (%s)", strerror(errno) );
+ p_input->b_error = 1;
+ return;
+ }
+ fseek( p_method->stream, 0, SEEK_SET );
+
+ /* Pre-parse the stream to gather stream_descriptor_t. */
+
+ /* FIXME */
+ p_input->stream.pp_programs =
+ (pgrm_descriptor_t **)malloc( sizeof(pgrm_descriptor_t *) );
+ p_input->stream.pp_programs[0] =
+ (pgrm_descriptor_t *)malloc( sizeof(pgrm_descriptor_t) );
+ p_input->stream.pp_programs[0]->i_synchro_state = SYNCHRO_START;
+ p_input->stream.pp_programs[0]->delta_cr = 0;
+ p_input->stream.pp_programs[0]->last_cr = 0;
+ p_input->stream.pp_programs[0]->c_average_count = 0;
+
+ p_demux = (stream_ps_data_t *)malloc( sizeof( stream_ps_data_t) );
+ p_input->stream.p_demux_data = (void *)p_demux;
+ p_demux->b_is_PSM_complete = 0;
+}
+
+/*****************************************************************************
+ * PSEnd: frees unused data
+ *****************************************************************************/
+static void PSEnd( input_thread_t * p_input )
+{
+ free( p_input->stream.p_demux_data );
+ free( p_input->p_method_data );
+}
+
+/*****************************************************************************
+ * PSRead: reads a data packet
+ *****************************************************************************/
+/* FIXME: read INPUT_READ_ONCE packet at once */
+static void PSRead( input_thread_t * p_input,
+ data_packet_t * p_packets[INPUT_READ_ONCE] )
+{
+ byte_t p_header[6];
+ data_packet_t * p_data;
+ int i_packet_size;
+ thread_ps_data_t * p_method;
+
+ p_method = (thread_ps_data_t *)p_input->p_method_data;
+
+ while( fread( p_header, 6, 1, p_method->stream ) != 1 )
+ {
+ int i_error;
+ if( (i_error = ferror( p_method->stream )) )
+ {
+ intf_ErrMsg( "Read 1 failed (%s)", strerror(i_error) );
+ p_input->b_error = 1;
+ return;
+ }
+
+ if( feof( p_method->stream ) )
+ {
+ intf_ErrMsg( "EOF reached" );
+ p_input->b_error = 1;
+ return;
+ }
+ }
+
+ if( (U32_AT(p_header) & 0xFFFFFF00) != 0x100L )
+ {
+ u32 i_buffer = U32_AT(p_header);
+ intf_ErrMsg( "Garbage at input (%x)\n", i_buffer );
+ while( (i_buffer & 0xFFFFFF00) != 0x100L )
+ {
+ i_buffer <<= 8;
+ i_buffer |= getc( p_method->stream );
+ if( feof(p_method->stream) || ferror(p_method->stream) )
+ {
+ p_input->b_error = 1;
+ return;
+ }
+ }
+ *(u32 *)p_header = i_buffer;
+ fread( p_header + 4, 2, 1, p_method->stream );
+ }
+
+ if( U32_AT(p_header) != 0x1BA )
+ {
+ i_packet_size = U16_AT(&p_header[4]);
+ }
+ else
+ {
+ i_packet_size = 8;
+ }
+
+ if( (p_data = NewPacket( p_input, i_packet_size + 6 )) == NULL )
+ {
+ p_input->b_error = 1;
+ intf_ErrMsg( "Out of memory" );
+ return;
+ }
+
+ memcpy( p_data->p_buffer, p_header, 6 );
+
+ /* FIXME: catch EINTR ! */
+ while( fread( p_data->p_buffer + 6, i_packet_size,
+ 1, p_method->stream ) != 1 )
+ {
+ int i_error;
+ if( (i_error = ferror( p_method->stream)) )
+ {
+ intf_ErrMsg( "Read 1 failed (%s)", strerror(i_error) );
+ p_input->b_error = 1;
+ return;
+ }
+
+ if( feof( p_method->stream ) )
+ {
+ intf_ErrMsg( "EOF reached" );
+ p_input->b_error = 1;
+ return;
+ }
+ }
+
+ if( U32_AT(p_header) == 0x1BA )
+ {
+ /* stuffing_bytes */
+ byte_t p_garbage[8];
+ /* FIXME: catch EINTR ! */
+ if( (p_data->p_buffer[13] & 0x3) != 0 )
+ {
+ fread( p_garbage, p_garbage[0] & 0x3, 1,
+ p_method->stream );
+ }
+ }
+
+ memset( p_packets, 0, sizeof(p_packets) );
+ p_packets[0] = p_data;
+}
+
+
+/*
+ * Packet management utilities
+ */
+
+/*****************************************************************************
+ * NewPacket: allocates a data packet
+ *****************************************************************************/
+static struct data_packet_s * NewPacket( void * p_garbage,
+ size_t i_size )
+{
+ data_packet_t * p_data;
+
+ if( (p_data = (data_packet_t *)malloc( sizeof(data_packet_t) )) == NULL )
+ {
+ intf_DbgMsg( "Out of memory" );
+ return NULL;
+ }
+
+ if( (p_data->p_buffer = (byte_t *)malloc( i_size )) == NULL )
+ {
+ intf_DbgMsg( "Out of memory" );
+ free( p_data );
+ return NULL;
+ }
+
+ p_data->p_payload_start = p_data->p_buffer;
+ p_data->p_payload_end = p_data->p_buffer + i_size;
+
+ return( p_data );
+}
+
+/*****************************************************************************
+ * DeletePacket: deletes a data packet
+ *****************************************************************************/
+static void DeletePacket( void * p_garbage,
+ data_packet_t * p_data )
+{
+ ASSERT(p_data);
+ ASSERT(p_data->p_buffer);
+ free( p_data->p_buffer );
+ free( p_data );
+}
+
+/*****************************************************************************
+ * DeletePES: deletes a PES packet and associated data packets
+ *****************************************************************************/
+static void DeletePES( void * p_garbage, pes_packet_t * p_pes )
+{
+ data_packet_t * p_data;
+ data_packet_t * p_next;
+
+ p_data = p_pes->p_first;
+
+ while( p_data != NULL )
+ {
+ p_next = p_data->p_next;
+ free( p_data->p_buffer );
+ free( p_data );
+ p_data = p_next;
+ }
+
+ free( p_pes );
+}
+
+/*****************************************************************************
+ * PSKludge: fakes a PS plugin (FIXME)
+ *****************************************************************************/
+input_capabilities_t * PSKludge( void )
+{
+ input_capabilities_t * p_plugin;
+
+ p_plugin = (input_capabilities_t *)malloc( sizeof(input_capabilities_t) );
+ p_plugin->pf_init = PSInit;
+ p_plugin->pf_read = PSRead;
+ p_plugin->pf_demux = input_DemuxPS; /* FIXME: use i_p_config_t ! */
+ p_plugin->pf_new_packet = NewPacket;
+ p_plugin->pf_delete_packet = DeletePacket;
+ p_plugin->pf_delete_pes = DeletePES;
+ p_plugin->pf_rewind = NULL;
+ p_plugin->pf_seek = NULL;
+
+ return( p_plugin );
+}
--- /dev/null
+/*****************************************************************************
+ * Constants
+ *****************************************************************************/
+
+/*****************************************************************************
+ * thread_ps_data_t: extension of input_thread_t
+ *****************************************************************************/
+typedef struct thread_ps_data_s
+{
+ /* We're necessarily reading a file. */
+ FILE * stream;
+} thread_ps_data_t;
+++ /dev/null
-/*****************************************************************************
- * psi.c: PSI management
- * Manages structures containing PSI information, and affiliated decoders.
- * TODO: Fonctions d'init des structures
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * Authors: Benoît Steiner <benny@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 "defs.h"
-
-#include <sys/types.h> /* on BSD, uio.h needs types.h */
-#include <sys/uio.h> /* "input.h" */
-#include <stdlib.h> /* free(), realloc() */
-#include <string.h> /* bzero() */
-#include <netinet/in.h> /* ntohs() */
-
-#include "config.h"
-#include "common.h"
-#include "threads.h"
-#include "mtime.h"
-#include "intf_msg.h"
-#include "plugins.h"
-#include "debug.h"
-
-#include "input.h"
-#include "input_ctrl.h"
-#include "input_psi.h"
-
-#include "main.h"
-
-/*
- * Precalculated 32-bits CRC table, shared by all instances of the PSI decoder
- */
-boolean_t b_crc_initialised = 0;
-u32 i_crc_32_table[256];
-
-/*
- * Global configuration variable, need by AUTO_SPAWN to determine
- * the option (audio and video) passed to the VideoLAN client.
- */
-#ifdef AUTO_SPAWN
-//XXX?? extern program_data_t *p_main;
-#endif
-
-/*
- * Locale type definitions
- */
-#define PSI_VIDEO_STREAM_DESCRIPTOR 0x02
-#define PSI_AUDIO_STREAM_DESCRIPTOR 0x03
-#define PSI_TARGET_BACKGROUND_GRID_DESCRIPTOR 0x07
-#define PSI_VIDEO_WINDOW_DESCRIPTOR 0x08
-
-#ifdef DVB_EXTENSIONS
-#define PSI_SERVICE_DESCRIPTOR 0x48
-#endif
-
-/* That info must be stored in the version field since it contains
- unused bits */
-#define PSI_UNINITIALISED 0xFF
-
-/*
- * Local prototypes
- */
-static int input_AddPsiPID( input_thread_t *p_input, int i_pid );
-static int input_DelPsiPID( input_thread_t *p_input, int i_pid );
-static void DecodePgrmAssocSection( byte_t* p_pas, input_thread_t *p_input );
-static void DecodePgrmMapSection( byte_t* p_pms, input_thread_t *p_input );
-static void DecodeSrvDescrSection( byte_t* p_sdt, input_thread_t *p_input );
-static void DecodePgrmDescriptor( byte_t* p_descr, pgrm_descriptor_t* p_pgrm );
-static void DecodeESDescriptor( byte_t* p_descriptor, es_descriptor_t* p_es );
-
-static stream_descriptor_t* AddStreamDescr( input_thread_t* p_input,
- u16 i_stream_id );
-static void DestroyStreamDescr( input_thread_t* p_input, u16 i_stream_id );
-static pgrm_descriptor_t* AddPgrmDescr( stream_descriptor_t* p_stream,
- u16 i_pgrm_id );
-static void DestroyPgrmDescr( input_thread_t* p_input,
- stream_descriptor_t* p_stream, u16 i_pgrm_id );
-static es_descriptor_t* AddESDescr( input_thread_t* p_input,
- pgrm_descriptor_t* p_pgrm, u16 i_es_pid );
-static void DestroyESDescr( input_thread_t* p_input, pgrm_descriptor_t* p_pgrm,
- u16 i_es_pid);
-
-static void BuildCrc32Table();
-static int CheckCRC32( u8* p_pms, int i_size);
-static boolean_t Is_known( byte_t* a_known_section, u8 i_section );
-static void Set_known( byte_t* a_known_section, u8 i_section );
-static void Unset_known( byte_t* a_known_section, u8 i_section );
-
-/*****************************************************************************
- * input_PsiInit: Initialize PSI decoder
- *****************************************************************************
- * Init the structures in which the PSI decoder will put the informations it
- * got from PSI tables and request for the reception of the PAT.
- *****************************************************************************/
-int input_PsiInit( input_thread_t *p_input )
-{
- ASSERT(p_input);
-
- /* Precalculate the 32-bit CRC table if not already done ?
- FIXME: Put a lock or do that at pgrm init ?? */
- if( !b_crc_initialised )
- {
- BuildCrc32Table();
- b_crc_initialised = 1;
- }
-
- /* Init the structure that describes the stream we are receiving */
- AddStreamDescr( p_input, PSI_UNINITIALISED );
-
- /* Request for reception of the program association table */
- input_AddPsiPID( p_input, 0 );
-
-#ifdef DVB_EXTENSIONS
- /* Request for reception of the service description table */
- input_AddPsiPID( p_input, 17 );
-#endif
-
- return( 0 );
-}
-
-/*****************************************************************************
- * input_PsiClean: Clean PSI structures before dying
- *****************************************************************************/
-int input_PsiEnd( input_thread_t *p_input )
-{
- ASSERT(p_input);
-
- /* Stop to receive all the PSI tables associated with that program */
- /* FIXME: Not really useful ??*/
-
- /* Clean also descriptors for programs associated with that stream */
- /* FIXME: -> Not really useful and maybe buggy ??*/
-
- /* Destroy the stream description */
- DestroyStreamDescr( p_input, p_input->p_stream->i_stream_id );
-
- return( 0 );
-}
-
-/*****************************************************************************
- * input_PsiRead: Read the table of programs
- *****************************************************************************
- * Ugly debugging function at that time ? XXX??
- *****************************************************************************/
-void input_PsiRead( input_thread_t *p_input /* XXX?? */ )
-{
- int i_index;
- int i_index2;
- pgrm_descriptor_t* p_pgrm;
-
- ASSERT( p_input );
-
- /* Lock the tables, since this method can be called from any thread */
- //vlc_mutex_lock()
-
- /* Check if the table is complete or not */
- if( !p_input->p_stream->b_is_PMT_complete )
- {
- intf_IntfMsg( "Warning: PMT not yet complete\n" );
- }
-
- /* Read the table */
- for( i_index = 0; i_index < p_input->p_stream->i_pgrm_number; i_index++ )
- {
- p_pgrm = p_input->p_stream->ap_programs[i_index];
- intf_DbgMsg("Printing info for program %d\n", p_pgrm->i_number );
- intf_IntfMsg("Printing info for program %d\n", p_pgrm->i_number );
-
- for( i_index2 = 0; i_index2 < p_pgrm->i_es_number; i_index2++ )
- {
- intf_DbgMsg( " ->Pid %d: type %d, PCR: %d, PSI: %d\n",
- p_pgrm->ap_es[i_index2]->i_id,
- p_pgrm->ap_es[i_index2]->i_type,
- p_pgrm->ap_es[i_index2]->b_pcr,
- p_pgrm->ap_es[i_index2]->b_psi);
-
- intf_IntfMsg( " ->Pid %d: type %d, PCR: %d, PSI: %d\n",
- p_pgrm->ap_es[i_index2]->i_id,
- p_pgrm->ap_es[i_index2]->i_type,
- p_pgrm->ap_es[i_index2]->b_pcr,
- p_pgrm->ap_es[i_index2]->b_psi);
- }
- }
-
- /* Unock the tables */
- //vlc_mutex_unlock()
-}
-
-/*****************************************************************************
- * input_PsiDecode: Decode a PSI section
- *****************************************************************************
- * This funtion is essentially a wrapper that will perform basic checks on
- * the section and then call the right function according to its type.
- *****************************************************************************/
-void input_PsiDecode( input_thread_t *p_input, psi_section_t* p_psi_section )
-{
- ASSERT(p_input);
- ASSERT(p_psi_section);
-
- /* Hexa dump of the beginning of the section (for real men) */
- //intf_DbgMsg( "Section: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", (u8)p_psi_section->buffer[0], (u8)p_psi_section->buffer[1], (u8)p_psi_section->buffer[2], (u8)p_psi_section->buffer[3], (u8)p_psi_section->buffer[4], (u8)p_psi_section->buffer[5], (u8)p_psi_section->buffer[6], (u8)p_psi_section->buffer[7], (u8)p_psi_section->buffer[8], (u8)p_psi_section->buffer[9], (u8)p_psi_section->buffer[10], (u8)p_psi_section->buffer[11], (u8)p_psi_section->buffer[12], (u8)p_psi_section->buffer[13], (u8)p_psi_section->buffer[14], (u8)p_psi_section->buffer[15], (u8)p_psi_section->buffer[16], (u8)p_psi_section->buffer[17], (u8)p_psi_section->buffer[18], (u8)p_psi_section->buffer[19] );
-
- /* Check the CRC validity if any CRC is carried */
-#if 0
- if( p_psi_section->buffer[1] & 0x80 )
- {
- if( CheckCRC32 (p_psi_section->buffer, p_psi_section->i_length) )
- {
- intf_DbgMsg("iSize: %d, CRC: %d\n", p_psi_section->i_length,
- U32_AT(&p_psi_section->buffer[p_psi_section->i_length-4]));
- intf_DbgMsg( "Invalid CRC for PSI\n" );
- return;
- }
- }
-#endif
-
- /* If the section is not immediatly applicable, trash it (DVB drafts disallow
- transmission of such sections, so we didn't implement it) */
- if( !p_psi_section->buffer[5] & 0x01 )
- {
- intf_DbgMsg( "PSI not yet applicable: trash it\n" );
- return;
- }
-
- /* Handle the packet according to it's type given it the table_id */
- switch ( p_psi_section->buffer[0] )
- {
- case 0x00:
- //intf_DbgMsg("Program association section received\n");
- DecodePgrmAssocSection(p_psi_section->buffer, p_input);
- break;
- case 0x01:
- //intf_DbgMsg("Conditional access section received\n");
- break;
- case 0x02:
- //intf_DbgMsg("Program map section received\n");
- DecodePgrmMapSection(p_psi_section->buffer, p_input);
- break;
- case 0x42:
- //intf_DbgMsg("Service description section received\n");
- DecodeSrvDescrSection(p_psi_section->buffer, p_input);
- break;
- default:
- //intf_DbgMsg("Private PSI data received (type %x), ignoring it\n",
- // p_psi_section->buffer[0]);
- }
-}
-
-/*****************************************************************************
- * DecodeAssocSection: Decode a PAS
- *****************************************************************************
- * No check is made to known if the table is currently applicable or not, so
- * that unapplicable sections must be filtered before calling this function
- * The Program Association Table can be segmented to occupy multiple sections
- * so that we have to know which sections we have already received (IsKnown() /
- * SetKnown() calls)
- *****************************************************************************/
-static void DecodePgrmAssocSection(u8* p_pas, input_thread_t *p_input )
-{
- u8 i_stream_id; /* Id of the stream described in that section */
- u8 i_version; /* Version of the table carried in the section */
-
- u16 i_pgrm_id; /* Id of the current described pgrm */
- u16 i_pgrm_map_pid; /* PID of the associated program map table */
- int i_pgrm_number; /* Number of programs described in the section */
-
- boolean_t b_is_invalid = 0;
-
- u8 i_current_section;
- u8 i_last_section;
-
- int i_pgrm_index;
- int i_es_index;
-
- ASSERT(p_pas);
- ASSERT(p_input);
-
-#define p_descr (p_input->p_stream)
-
- /* Read stream id and version number immediately, to be sure they will be
- initialised in all cases we will need it */
- i_stream_id = U16_AT(&p_pas[3]);
- i_version = (p_pas[5] >> 1) & 0x1F;
- //intf_DbgMsg("TS Id: %d, version: %d\n", U16_AT(&p_pas[3]),(p_pas[5] >> 1) & 0x1F);
-
- /* Test if the stream has not changed by looking at the stream_id */
- if( p_descr->i_stream_id != i_stream_id )
- {
- /* This can either mean that the PSI decoder has just started or that
- the stream has changed */
- if( p_descr->i_PAT_version== PSI_UNINITIALISED )
- intf_DbgMsg("Building Program Association table\n");
- else
- intf_ErrMsg( "Stream Id has suddenly changed ! Rebuilding PAT\n" );
-
- /* Whatever it is, ask the PSI decoder to rebuild the table */
- b_is_invalid = 1;
- }
- else
- {
- /* Stream has not changed, test if the PMT is up to date */
- if( p_descr->i_PAT_version != i_version )
- {
- intf_DbgMsg("PAT has been updated, rebuilding it\n");
- /* Ask the PSI decoder to rebuild the table */
- b_is_invalid = 1;
- }
- }
-
- /* Clear the table if needed */
- if( b_is_invalid )
- {
- intf_DbgMsg("Updating PAT table\n");
-
- /* Any program in the stream may have disapeared, or a new one
- can have been added. The good way to handle such a case would be
- to build a temporary table and to make a diff */
-
- /* Stop the reception of all programs and PSI informations
- associated with this stream, excepted the PAT on PID 0 and the SDT
- on PID 17 */
- for( i_es_index = 0; i_es_index < INPUT_MAX_SELECTED_ES &&
- p_input->pp_selected_es[i_es_index]; i_es_index++ )
- {
- if( p_input->pp_selected_es[i_es_index]->b_psi )
- {
- if( p_input->pp_selected_es[i_es_index]->i_id != 0
-#ifdef DVB_EXTENSIONS
- && p_input->pp_selected_es[i_es_index]->i_id != 17
-#endif
- )
- input_DelPsiPID( p_input,
- p_input->pp_selected_es[i_es_index]->i_id );
- }
- else
- input_DelPgrmElem( p_input,
- p_input->pp_selected_es[i_es_index]->i_id );
- }
-
- /* Recreate a new stream description. Since it is virgin, the decoder
- will rebuild it entirely on is own */
- DestroyStreamDescr(p_input, p_descr->i_stream_id);
- AddStreamDescr(p_input, i_stream_id);
-
- /* Record the new version for that table */
- p_descr->i_PAT_version = i_version;
- }
-
- /* Build the table if not already complete or if it was cleared */
- if( p_descr->b_is_PAT_complete )
- {
- /* Nothing to do */
- if( b_is_invalid )
- intf_DbgMsg("Bug: table invalid but PAT said to be complete\n");
- }
- else
- {
- /* Check if we already heard about that section */
- i_last_section = p_pas[7];
- i_current_section = p_pas[6];
-
-// intf_DbgMsg( "Section %d (last section %d)\n",
-// i_current_section, i_last_section );
-
- if( Is_known(p_descr->a_known_PAT_sections, i_current_section) )
- {
- /* Nothing to do */
-// intf_DbgMsg("Section already received, skipping\n");
- }
- else
- {
- /* Compute the number of program_map PID carried in this section */
- i_pgrm_number = ((U16_AT(&p_pas[1]) & 0xFFF) - 9) / 4;
- intf_DbgMsg("Number of Pgrm in that section: %d\n", i_pgrm_number);
-
- /* Start the reception of those program map PID */
- for( i_pgrm_index = 0; i_pgrm_index < i_pgrm_number; i_pgrm_index++ )
- {
- i_pgrm_id = U16_AT(&p_pas[8+4*i_pgrm_index]);
- i_pgrm_map_pid = U16_AT(&p_pas[8+4*i_pgrm_index+2]) & 0x1fff;
- intf_DbgMsg("Pgrm %d described on pid %d\n", i_pgrm_id,
- i_pgrm_map_pid);
-
- /* Check we are not already receiving that pid because it carries
- info for another program */
- for( i_es_index = 0; i_es_index < INPUT_MAX_ES; i_es_index++ )
- {
- if( p_input->p_es[i_es_index].i_id == i_pgrm_map_pid)
- {
- intf_DbgMsg("Already receiving pid %d", i_pgrm_map_pid);
- i_es_index = INPUT_MAX_ES+1;
- break;
- }
- }
- /* Start to receive that PID if we're not already doing it */
- if( i_es_index <= INPUT_MAX_ES )
- input_AddPsiPID( p_input, i_pgrm_map_pid );
-
- /* Append an entry to the pgrm_descriptor table to later store
- the description of this program, unless program number is 0
- (Network information table) */
- if( i_pgrm_id != 0 )
- {
- intf_DbgMsg("Adding program %d to the PMT\n", i_pgrm_id);
- AddPgrmDescr(p_descr, i_pgrm_id);
- }
- }
-
- /* We now know the info carried in this section */
- Set_known(p_descr->a_known_PAT_sections, i_current_section);
-
- /* Check if the table is now complete */
- p_descr->i_known_PAT_sections++;
- if( p_descr->i_known_PAT_sections >= i_last_section)
- p_descr->b_is_PAT_complete = 1;
- }
- }
-
-#undef p_descr
-}
-
-/*****************************************************************************
- * DecodePgrmMapSection: Decode a PMS
- *****************************************************************************
- * No check is made to known if the table is currently applicable or not, so
- * that unapplicable sections must be filtered before calling this function
- * The Program Map Table can be segmented to occupy multiple sections so that
- * we have to know which sections we have already received (IsKnown() /
- * SetKnown() calls)
- * Note that the processing of those sections is different from the one of the
- * others since here a section refers to a single program, and a program cannot
- * be segmented into multiple sections
- *****************************************************************************/
-static void DecodePgrmMapSection( u8* p_pms, input_thread_t* p_input )
-{
- u16 i_pgrm_number; /* Id of the program described in that section */
- u8 i_version; /* Version of the description for that program */
-
- u16 i_offset;
- u16 i_section_length;
- u16 i_descr_end;
-
- u8 i_last_section;
- u8 i_current_section;
-
- u16 i_es_pid;
-
- int i_index = 0;
-#ifdef AUTO_SPAWN
- int i_es_loop;
-#endif
- pgrm_descriptor_t* p_pgrm;
- es_descriptor_t* p_es;
-
-#define p_descr (p_input->p_stream)
-
- /* Read the id of the program described in that section */
- i_pgrm_number = U16_AT(&p_pms[3]);
-// intf_DbgMsg( "PMT section received for program %d\n", i_pgrm_number );
-
- /* Find where is stored the description of this program */
- for( i_index = 0; i_index < p_descr->i_pgrm_number &&
- i_pgrm_number != p_descr->ap_programs[i_index]->i_number; i_index++ );
-
- if( i_index >= p_descr->i_pgrm_number )
- {
- /* If none entry exists, this simply means that the PAT is not complete,
- so skip this section since it is the responsability of the PAT decoder
- to add pgrm_descriptor slots to the table of known pgrms */
- intf_DbgMsg( "Unknown pgrm %d: skipping its description\n", i_pgrm_number );
- return;
- }
-
- /* We now have the slot which is the program described: we can begin with
- the decoding of its description */
- p_pgrm = p_descr->ap_programs[i_index];
-
- /* Which section of the description of that program did we receive ? */
- i_last_section = p_pms[7];
- i_current_section = p_pms[6];
-// intf_DbgMsg("Section %d (last section %d)\n", i_current_section, i_last_section);
-
- /* Is this an update of the description for this program ? */
- i_version = (p_pms[5] >> 1) & 0x1F;
- if( p_pgrm->i_version != i_version )
- {
- intf_DbgMsg("Updating PMT for program %d\n", i_pgrm_number);
-
- for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
- {
- /* Stop the reception of the ES if needed by calling the function
- normally used by the interface to manage this */
- if( input_IsElemRecv(p_input, p_pgrm->ap_es[i_index]->i_id) )
- {
- intf_DbgMsg( "PID %d is no more valid: stopping its reception\n",
- p_pgrm->ap_es[i_index]->i_id );
- input_DelPgrmElem( p_input, p_pgrm->ap_es[i_index]->i_id );
- }
-
- /* Remove the descriptor associated to the es of this programs */
- intf_DbgMsg( "Invalidating PID %d\n", p_pgrm->ap_es[i_index]->i_id );
- DestroyESDescr(p_input, p_pgrm, p_pgrm->ap_es[i_index]->i_id);
- }
-
- /* Update version number */
- p_pgrm->i_version = i_version;
-
- /* Ask the decoder to update the description of that program */
- p_descr->i_known_PMT_sections--;
- Unset_known( p_descr->a_known_PMT_sections, i_current_section );
- p_pgrm->b_is_ok = 0;
- }
-
- /* Read the info for that pgrm is the one we have is not up to date or
- if we don't have any */
- if( p_pgrm->b_is_ok )
- {
- /* Nothing to do */
-// intf_DbgMsg("Program description OK, nothing to do\n");
- }
- else
- {
- /* Check if we already heard about that section */
- if( Is_known(p_descr->a_known_PMT_sections, i_current_section) )
- {
- /* Nothing to do */
-// intf_DbgMsg("Section already received, skipping\n");
- }
- else
- {
- /* Read the corresponding PCR */
- p_pgrm->i_pcr_pid = U16_AT(&p_pms[8]) & 0x1fff;
- intf_DbgMsg("PCR at PID: %d\n", p_pgrm->i_pcr_pid);
-
- /* Compute the length of the section minus the final CRC */
- i_section_length = (U16_AT(&p_pms[1]) & 0xfff) + 3 - 4;
- intf_DbgMsg("Section length (without CRC): %d\n", i_section_length);
-
- /* Read additional info stored in the descriptors if any */
- intf_DbgMsg("Description length for program %d: %d\n",
- p_pgrm->i_number, (U16_AT(&p_pms[10]) & 0x0fff));
- i_descr_end = (U16_AT(&p_pms[10]) & 0x0fff) + 12;
- intf_DbgMsg("description ends at offset: %d\n", i_descr_end);
-
- i_offset = 12;
- while( i_offset < i_descr_end )
- {
- DecodePgrmDescriptor(&p_pms[i_offset], p_pgrm);
- i_offset += p_pms[i_offset+1] + 2;
- }
-
- /* Read all the ES descriptions */
- while( i_offset < i_section_length )
- {
- /* Read type of that ES */
- intf_DbgMsg("ES Type: %d\n", p_pms[i_offset]);
-
- /* Read PID of that ES */
- i_es_pid = U16_AT(&p_pms[i_offset+1]) & 0x1fff;
- intf_DbgMsg("ES PID: %d\n", i_es_pid);
-
- /* Add the ES to the program description and reserve a slot in the
- table of ES to store its description */
- p_es = AddESDescr(p_input, p_pgrm, i_es_pid);
- if (!p_es)
- {
- intf_ErrMsg("Warning: definition for pgrm %d won't be complete\n",
- p_pgrm->i_number);
- /* The best way to handle this is to stop decoding the info for
- that section but do as if everything is ok. Thus we will
- eventually have an uncomplete ES table marked as being
- complete and some error msgs */
- break;
- }
- else
- {
- /* Store the description of that PID in the slot */
- p_es->i_type = p_pms[i_offset];
- p_es->b_psi = 0;
- if( i_es_pid == p_pgrm->i_pcr_pid )
- p_es->b_pcr = 1;
- else
- p_es->b_pcr = 0;
-
- /* Read additional info given by the descriptors */
- i_offset += 5;
- intf_DbgMsg("description length for PID %d: %d\n", p_es->i_id,
- (U16_AT(&p_pms[i_offset-2]) & 0x0fff));
- i_descr_end = (U16_AT(&p_pms[i_offset-2]) & 0x0fff) + i_offset;
- intf_DbgMsg("description ends at offset: %d\n", i_descr_end);
- while( i_offset < i_descr_end )
- {
- DecodeESDescriptor(&p_pms[i_offset], p_es);
- i_offset += p_pms[i_offset+1] + 2;
- }
- }
-
- /* Jump to next ES description */
- }
-
- /* We now know the info carried in this section */
- intf_DbgMsg("Description of program %d complete\n", p_pgrm->i_number);
- p_pgrm->b_is_ok = 1;
- Set_known(p_descr->a_known_PMT_sections, i_current_section);
-
- /* Check if the PMT is now complete */
- p_descr->i_known_PMT_sections++;
- if( p_descr->i_known_PMT_sections >= i_last_section)
- {
- p_descr->b_is_PMT_complete = 1;
-
-#ifdef AUTO_SPAWN
- /* Spawn an audio and a video thread, if possible. */
- for( i_es_loop = 0; i_es_loop < INPUT_MAX_ES; i_es_loop++ )
- {
- switch( p_input->p_es[i_es_loop].i_type )
- {
- case MPEG1_VIDEO_ES:
- case MPEG2_VIDEO_ES:
- if( p_main->b_video )
- {
- /* Spawn a video thread */
- input_AddPgrmElem( p_input,
- p_input->p_es[i_es_loop].i_id );
- }
- break;
-
- case AC3_AUDIO_ES:
- if ( p_main->b_audio )
- {
- /* Spawn an ac3 thread */
- input_AddPgrmElem( p_input,
- p_input->p_es[i_es_loop].i_id );
- }
- break;
-
- case LPCM_AUDIO_ES:
- if ( p_main->b_audio )
- {
- /* Spawn an lpcm thread */
- input_AddPgrmElem( p_input,
- p_input->p_es[i_es_loop].i_id );
- }
- break;
-
- case DVD_SPU_ES:
- if ( p_main->b_video )
- {
- /* Spawn a spu decoder thread */
- input_AddPgrmElem( p_input,
- p_input->p_es[i_es_loop].i_id );
- }
- break;
-
- case MPEG1_AUDIO_ES:
- case MPEG2_AUDIO_ES:
- if( p_main->b_audio )
- {
- /* Spawn an audio thread */
- input_AddPgrmElem( p_input,
- p_input->p_es[i_es_loop].i_id );
- }
- break;
-
- default:
- break;
- }
- }
-#endif
- }
- }
- }
-
-#undef p_descr
-}
-
-/*****************************************************************************
- * DecodeSrvDescrSection
- *****************************************************************************
- * FIXME: A finir et a refaire proprement ??
- *****************************************************************************/
-void DecodeSrvDescrSection( byte_t* p_sdt, input_thread_t *p_input )
-{
- u16 i_stream_id;
- u8 i_version;
- u16 i_length;
-
- int i_index;
- int i_offset;
- boolean_t b_must_update = 0;
-
- int i_descr_end;
-
- ASSERT(p_sdt);
- ASSERT(p_input);
-
-#define p_stream (p_input->p_stream)
-
- /* Read stream id and version number immediately, to be sure they will be
- initialised in all the cases in which we will need them */
- i_stream_id = U16_AT(&p_sdt[3]);
- i_version = (p_sdt[5] >> 1) & 0x1F;
- intf_DbgMsg("TS Id: %d, version: %d\n", i_stream_id, i_version);
-
- /* Take the descriptor into account only if it describes the streams we are
- receiving */
- if( p_stream->i_stream_id != i_stream_id )
- {
- intf_DbgMsg("SDT doen't apply to our TS but to %s: aborting\n",
- U16_AT(&p_sdt[3]));
- }
- else
- {
- /* Section applyies to our TS, test if the SDT is up to date */
- if( p_stream->i_SDT_version != i_version )
- {
- intf_DbgMsg("SDT has been updated, NOT YET IMPLEMENTED\n");
-
- /* Ask the PSI decoder to rebuild the table */
- b_must_update = 1;
- }
- }
-
- /* Rebuild the table if needed */
- if( b_must_update )
- {
- intf_DbgMsg("Updating SDT table\n");
-
- i_length = p_sdt[1] & 0x0FFF;
- i_offset = 11;
-
- while(i_offset < i_length)
- {
-
- /* Find the program to which the description applies */
- for( i_index = 0; i_index < p_stream->i_pgrm_number; i_index++ )
- {
- if( p_stream->ap_programs[i_index]->i_number ==
- U16_AT(&p_sdt[i_offset]) )
- {
- /* Here we are */
- intf_DbgMsg("FOUND: %d\n", p_stream->ap_programs[i_index]->i_number);
- break;
- }
- }
-
- /* Copy the info to the description of that program */
- i_offset += 5;
- intf_DbgMsg("description length for SDT: %d\n",
- (U16_AT(&p_sdt[i_offset-2]) & 0x0FFF));
- i_descr_end = (U16_AT(&p_sdt[i_offset-2]) & 0x0FFF) + i_offset;
- intf_DbgMsg("description ends at offset: %d\n", i_descr_end);
- while( i_offset < i_descr_end )
- {
- DecodePgrmDescriptor(&p_sdt[i_offset], p_stream->ap_programs[i_index]);
- i_offset += p_sdt[i_offset+1] + 2;
- }
- }
- }
-#undef p_stream
-}
-
-/*****************************************************************************
- * DecodePgrmDescr
- *****************************************************************************
- * Decode any descriptor applying to the definition of a program
- *****************************************************************************/
-static void DecodePgrmDescriptor( byte_t* p_descriptor,
- pgrm_descriptor_t* p_pgrm )
-{
- u8 i_type; /* Type of the descriptor */
- u8 i_length; /* Length of the descriptor */
-#ifdef DVB_EXTENSIONS
- int i_offset; /* Current position in the descriptor */
-#endif
-
- ASSERT(p_descriptor);
- ASSERT(p_pgrm);
-
- /* Read type and length of the descriptor */
- i_type = p_descriptor[0];
- i_length = p_descriptor[1];
-
- /* Handle specific descriptor info */
- switch(i_type)
- {
-#ifdef DVB_EXTENSIONS
- case PSI_SERVICE_DESCRIPTOR:
- {
- /* Store service type */
- p_pgrm->i_srv_type = p_descriptor[2];
-
- /* Jump to the beginning of the service name */
- i_offset = p_descriptor[3] + 5;
-
- /* Check that the charset used is the normal one (latin) by testing the
- first byte of the name */
- if( p_descriptor[i_offset] >= 0x20 )
- {
- /* The charset is the one of our computer: just dup the string */
- p_pgrm->psz_srv_name = malloc(i_length - i_offset +1);
- memcpy(p_pgrm->psz_srv_name, &p_descriptor[i_offset],
- i_length - i_offset);
- p_pgrm->psz_srv_name[i_length - i_offset + 1] = '\0';
- }
- else
- {
- /* Indicate that the name couldn't be printed */
- p_pgrm->psz_srv_name = "Ununderstandable :)";
- }
- break;
- }
-#endif
- default:
-// intf_DbgMsg("Unhandled program descriptor received (type: %d)\n", i_type);
-// intf_DbgMsg("Unhandled ES descriptor received (type: %d)\n", i_type);
- }
-}
-
-/*****************************************************************************
- * DecodeESDescriptor
- *****************************************************************************
- * Decode any descriptor applying to the definition of an ES
- *****************************************************************************/
-static void DecodeESDescriptor( byte_t* p_descriptor, es_descriptor_t* p_es )
-{
- u8 i_type; /* Type of the descriptor */
- u8 i_length; /* Length of the descriptor */
-// int i_offset; /* Current position in the descriptor */
-
- ASSERT(p_descriptor);
- ASSERT(p_es);
-
- /* Read type and length of the descriptor */
- i_type = p_descriptor[0];
- i_length = p_descriptor[1];
-
- switch( i_type )
- {
- case PSI_VIDEO_STREAM_DESCRIPTOR:
- {
- intf_DbgMsg("Video stream descriptor received\n");
- break;
- }
- case PSI_AUDIO_STREAM_DESCRIPTOR:
- {
- intf_DbgMsg("Audio stream descriptor received\n");
- break;
- }
- case PSI_TARGET_BACKGROUND_GRID_DESCRIPTOR:
- {
- intf_DbgMsg("Target background descriptor received\n");
- break;
- }
- case PSI_VIDEO_WINDOW_DESCRIPTOR:
- {
- intf_DbgMsg("Video window descriptor received\n");
- break;
- }
- default:
-// intf_DbgMsg("Unhandled ES descriptor received (type: %d)\n", i_type);
-// intf_DbgMsg("Unhandled ES descriptor received (type: %d)\n", i_type);
- }
-}
-
-/*****************************************************************************
- * input_AddPsiPID: Start to receive the PSI info contained in a PID
- *****************************************************************************
- * Add a descriptor to the table of es descriptor for that es and mark the es
- * as being to be received by the input (since all PSI must be received to
- * build the description of the program)
- *****************************************************************************/
-static int input_AddPsiPID( input_thread_t *p_input, int i_pid )
-{
- int i_index;
- es_descriptor_t* p_psi_es;
- int i_rc = 0;
-
- /* Store the description of this stream in the input thread */
- p_psi_es = AddESDescr(p_input, NULL, i_pid);
-
- if(p_psi_es)
- {
- /* Precise this ES carries PSI */
- p_psi_es->b_psi = 1;
-
- /* Create the buffer needed by the PSI decoder */
- p_psi_es->p_psi_section = malloc( sizeof( psi_section_t) );
- if( !p_psi_es->p_psi_section )
- {
- intf_ErrMsg( "Malloc error\n" );
- i_rc = -1;
- }
- else
- {
- /* Init the reception for that PID */
- p_psi_es->p_psi_section->b_running_section = 0;
-// p_psi_es->p_psi_section->b_discard_payload = 0;
-
- /* Ask the input thread to demultiplex it: since the interface
- can also access the table of selected es, lock the elementary
- stream structure */
- vlc_mutex_lock( &p_input->es_lock );
- for( i_index = 0; i_index < INPUT_MAX_SELECTED_ES; i_index++ )
- {
- if( !p_input->pp_selected_es[i_index] )
- {
- intf_DbgMsg( "Free Selected ES slot found at offset %d for PID %d\n",
- i_index, i_pid );
- p_input->pp_selected_es[i_index] = p_psi_es;
- break;
- }
- }
- vlc_mutex_unlock( &p_input->es_lock );
-
- if( i_index >= INPUT_MAX_SELECTED_ES )
- {
- intf_ErrMsg( "Stream carries to many PID for our decoder\n" );
- i_rc = -1;
- }
- }
- }
-
- return( i_rc );
-}
-
-/*****************************************************************************
- * input_DelPsiPID: Stop to receive the PSI info contained in a PID
- *****************************************************************************
- * Remove the PID from the list of ES descriptors and from the list of ES that
- * the input must receive.
- * Known PID for PSI should always be received, so that their description
- * should be pointed out by a member of pp_selected_es. But as INPUT_MAX_ES
- * can be different of INPUT_MAX_SELECTED_ES, this may happen, so that we must
- * do 2 loops.
- *****************************************************************************/
-static int input_DelPsiPID( input_thread_t *p_input, int i_pid )
-{
- int i_es_index, i_last_sel;
-
- intf_DbgMsg( "Deleting PSI PID %d\n", i_pid );
-
- /* Stop to receive the ES. Since the interface can also access the table
- of selected es, lock the elementary stream structure */
- vlc_mutex_lock( &p_input->es_lock );
-
- for( i_es_index = 0; i_es_index < INPUT_MAX_SELECTED_ES; i_es_index++ )
- {
- if( p_input->pp_selected_es[i_es_index] &&
- p_input->pp_selected_es[i_es_index]->i_id == i_pid )
- {
- /* Unmark the stream */
- p_input->pp_selected_es[i_es_index] = NULL;
-
- /* There must not be any gap in the pp_selected_es, so move the last
- selected stream to this slot */
- for( i_last_sel = i_es_index; p_input->pp_selected_es[i_last_sel] &&
- i_last_sel < INPUT_MAX_SELECTED_ES; i_last_sel++ );
- p_input->pp_selected_es[i_es_index] = p_input->pp_selected_es[i_last_sel];
- p_input->pp_selected_es[i_last_sel] = NULL;
- break;
- }
- }
-
- vlc_mutex_unlock( &p_input->es_lock );
-
-#ifdef DEBUG
- /* Check if the pp_selected_es table may be corrupted */
- if( i_es_index >= INPUT_MAX_PROGRAM_ES )
- {
- intf_ErrMsg( "DelPsiPID error: PID %d is not currently received\n", i_pid );
- }
-#endif
-
- /* Remove the desription of that ES from the table of ES */
- DestroyESDescr(p_input, NULL, i_pid);
-
- return( 0 );
-}
-
-/*****************************************************************************
- * Precalculate the 32-bit CRC table
- *****************************************************************************
- * This table is a global variable shared by all decoders, so it has to be
- * initialised only once
- *****************************************************************************/
-void BuildCrc32Table( )
-{
- u32 i, j, k;
- for( i = 0 ; i < 256 ; i++ )
- {
- k = 0;
- for (j = (i << 24) | 0x800000 ; j != 0x80000000 ; j <<= 1)
- k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0);
- i_crc_32_table[i] = k;
- }
-}
-
-/*****************************************************************************
- * Test the validity of a checksum
- *****************************************************************************
- * The checksum must be stored at the end of the data, and the given size must
- * include the 32 bits of the CRC.
- * Return 0 if the checksum is OK, any other value if the data are corrupted
- *****************************************************************************/
-int CheckCRC32(byte_t* p_data, int i_data_size)
-{
- int i;
- u32 i_crc = 0xffffffff;
-
- ASSERT(p_data);
-
- for (i = 0; i < i_data_size; i++)
- i_crc = (i_crc << 8) ^ i_crc_32_table[(i_crc >> 24) ^ p_data[i]];
-
- return i_crc;
-}
-
-/*****************************************************************************
- * Is_known: check if a given section has already been received
- *****************************************************************************
- * As a table cannot be segmented into more than 256 sections, we store a 256
- * bits long table, each bit set to one indicating that the corresponding
- * saction has been received
- *****************************************************************************/
-boolean_t Is_known( byte_t* a_known_section, u8 i_section )
-{
- byte_t mask;
- boolean_t b_is_known;
-
- /* Where to get the information ? */
- int i_bit_in_byte = i_section % 8;
- int i_byte_in_table = (i_section - i_bit_in_byte) / 8;
-
- /* Build mask to read the Is_known flag */
- mask = 0x01 << i_bit_in_byte;
-
- /* Read the flag */
- b_is_known = a_known_section[i_byte_in_table] & mask;
-
- return b_is_known;
-}
-
-/*****************************************************************************
- * Set_known: mark a given section has having been received
- *****************************************************************************
- *
- *****************************************************************************/
-static void Set_known( byte_t* a_known_section, u8 i_section )
-{
- byte_t mask;
-
- /* Where to get the information ? */
- int i_bit_in_byte = i_section % 8;
- int i_byte_in_table = (i_section - i_bit_in_byte) / 8;
-
- /* Build mask to read the Is_known flag */
- mask = 0x01 << i_bit_in_byte;
-
- /* Set the flag */
- a_known_section[i_byte_in_table] |= mask;
-}
-
-/*****************************************************************************
- * Unset_known: remove the 'received' mark for a given section
- *****************************************************************************
- *
- *****************************************************************************/
-static void Unset_known( byte_t* a_known_section, u8 i_section )
-{
- byte_t mask;
-
- /* Where to get the information ? */
- int i_bit_in_byte = i_section % 8;
- int i_byte_in_table = (i_section - i_bit_in_byte) / 8;
-
- /* Build mask to read the Is_known flag */
- mask = 0x01 << i_bit_in_byte;
- mask = ~mask;
-
- /* Unset the flag */
- a_known_section[i_byte_in_table] &= mask;
-}
-
-/*****************************************************************************
- * AddStreamDescr: add and init the stream descriptor of the given input
- *****************************************************************************
- *
- *****************************************************************************/
-static stream_descriptor_t* AddStreamDescr(input_thread_t* p_input,
- u16 i_stream_id)
-{
- ASSERT(p_input);
-
- intf_DbgMsg("Adding description for stream %d\n", i_stream_id);
-
- p_input->p_stream = malloc( sizeof(stream_descriptor_t) );
-
- p_input->p_stream->i_stream_id = i_stream_id;
-
- p_input->p_stream->i_PAT_version = PSI_UNINITIALISED;
- p_input->p_stream->i_known_PAT_sections = 0;
- memset( p_input->p_stream->a_known_PAT_sections, 0,
- sizeof(*p_input->p_stream->a_known_PAT_sections) );
- p_input->p_stream->b_is_PAT_complete = 0;
-
- p_input->p_stream->i_known_PMT_sections = 0;
- memset( p_input->p_stream->a_known_PMT_sections, 0,
- sizeof(*p_input->p_stream->a_known_PMT_sections) );
- p_input->p_stream->b_is_PMT_complete = 0;
-
-#ifdef DVB_EXTENSIONS
- p_input->p_stream->i_SDT_version = PSI_UNINITIALISED;
- p_input->p_stream->i_known_SDT_sections = 0;
- memset( p_input->p_stream->a_known_SDT_sections, 0,
- sizeof(*p_input->p_stream->a_known_SDT_sections) );
- p_input->p_stream->b_is_SDT_complete = 0;
-#endif
-
- p_input->p_stream->i_pgrm_number = 0;
- p_input->p_stream->ap_programs = NULL;
-
- return p_input->p_stream;
-}
-
-/*****************************************************************************
- * DestroyStreamDescr: destroy the stream desciptor of the given input
- *****************************************************************************
- *
- *****************************************************************************/
-static void DestroyStreamDescr(input_thread_t* p_input, u16 i_stream_id)
-{
- int i_index;
-
- ASSERT(p_input);
-
- /* Free the structures that describes the programs of that stream */
- for( i_index = 0; i_index < p_input->p_stream->i_pgrm_number; i_index++ )
- {
- DestroyPgrmDescr( p_input, p_input->p_stream,
- p_input->p_stream->ap_programs[i_index]->i_number );
- }
-
- /* Free the table of pgrm descriptors */
- free( p_input->p_stream->ap_programs );
-
- /* Free the structure that describes the stream itself */
- free( p_input->p_stream );
-
- /* Input thread has no more stream descriptor */
- p_input->p_stream = NULL;
-}
-
-/*****************************************************************************
- * AddPgrmDescr: add and init a program descriptor
- *****************************************************************************
- * This program descriptor will be referenced in the given stream descriptor
- *****************************************************************************/
-static pgrm_descriptor_t* AddPgrmDescr( stream_descriptor_t* p_stream,
- u16 i_pgrm_id)
-{
- int i_pgrm_index = p_stream->i_pgrm_number; /* Where to add the pgrm */
-
- ASSERT(p_stream);
-
- intf_DbgMsg("Adding description for pgrm %d\n", i_pgrm_id);
-
- /* Add an entry to the list of program associated with the stream */
- p_stream->i_pgrm_number++;
- p_stream->ap_programs = realloc( p_stream->ap_programs,
- p_stream->i_pgrm_number*sizeof(pgrm_descriptor_t*) );
-
- /* Allocate the structure to store this description */
- p_stream->ap_programs[i_pgrm_index] = malloc(sizeof(pgrm_descriptor_t));
-
- /* Init this entry */
- p_stream->ap_programs[i_pgrm_index]->i_number = i_pgrm_id;
- p_stream->ap_programs[i_pgrm_index]->i_version = PSI_UNINITIALISED;
- p_stream->ap_programs[i_pgrm_index]->b_is_ok = 0;
-
- p_stream->ap_programs[i_pgrm_index]->i_es_number = 0;
- p_stream->ap_programs[i_pgrm_index]->ap_es = NULL;
-
- /* descriptors ? XXX?? */
-
- return p_stream->ap_programs[i_pgrm_index];
-}
-
-/*****************************************************************************
- * AddPgrmDescr: destroy a program descriptor
- *****************************************************************************
- * All ES descriptions referenced in the descriptor will be deleted.
- *****************************************************************************/
-static void DestroyPgrmDescr( input_thread_t * p_input,
- stream_descriptor_t * p_stream, u16 i_pgrm_id )
-{
- int i_index, i_pgrm_index = -1;
- pgrm_descriptor_t* p_pgrm = NULL;
-
- ASSERT( p_stream );
-
- intf_DbgMsg("Deleting description for pgrm %d\n", i_pgrm_id);
-
- /* Find where this program is described */
- for( i_index = 0; i_index < p_stream->i_pgrm_number; i_index++ )
- {
- if( p_stream->ap_programs[i_index]->i_number == i_pgrm_id )
- {
- i_pgrm_index = i_index;
- p_pgrm = p_stream->ap_programs[ i_pgrm_index ];
- break;
- }
- }
-
- /* Make sure that the pgrm exists */
- ASSERT(i_pgrm_index >= 0);
- ASSERT(p_pgrm);
-
- /* Free the structures that describe the es that belongs to that program */
- for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
- {
- DestroyESDescr( p_input, p_pgrm, p_pgrm->ap_es[i_index]->i_id );
- }
-
- /* Free the table of es descriptors */
- free( p_pgrm->ap_es );
-
- /* Free the description of this stream */
- free( p_pgrm );
-
- /* Remove this program from the stream's list of programs */
- p_stream->i_pgrm_number--;
- p_stream->ap_programs[i_pgrm_index] =
- p_stream->ap_programs[p_stream->i_pgrm_number];
- p_stream->ap_programs = realloc( p_stream->ap_programs,
- p_stream->i_pgrm_number*sizeof(pgrm_descriptor_t *) );
-}
-
-/*****************************************************************************
- * AddESDescr:
- *****************************************************************************
- * Reserve a slot in the table of ES descritors for the ES and add it to the
- * list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
- * alone (PSI ?)
- *****************************************************************************/
-static es_descriptor_t* AddESDescr(input_thread_t* p_input,
- pgrm_descriptor_t* p_pgrm, u16 i_es_pid)
-{
- int i_index;
- es_descriptor_t* p_es = NULL;
-
- ASSERT(p_input);
-
- intf_DbgMsg("Adding description for ES %d\n", i_es_pid);
-
- /* Find an empty slot to store the description of that es */
- for( i_index = 0; i_index < INPUT_MAX_ES &&
- p_input->p_es[i_index].i_id != EMPTY_PID; i_index++ );
-
- if( i_index >= INPUT_MAX_ES )
- {
- /* No slot is empty */
- intf_ErrMsg("Stream carries to many PID for our decoder\n");
- }
- else
- {
- /* Reserve the slot for that ES */
- p_es = &p_input->p_es[i_index];
- p_es->i_id = i_es_pid;
- intf_DbgMsg("Slot %d in p_es table assigned to ES %d\n", i_index, i_es_pid);
-
- /* Init its values */
- p_es->i_type = 0; /* XXX?? */
- p_es->b_psi = 0;
- p_es->b_pcr = 0;
- p_es->i_continuity_counter = 0xFF;
-
- p_es->p_pes_packet = NULL;
-// p_es->p_next_pes_packet = NULL;
- p_es->p_dec = NULL;
-
- /* Add this ES to the program definition if one is given */
- if( p_pgrm )
- {
- p_pgrm->i_es_number++;
- p_pgrm->ap_es = realloc( p_pgrm->ap_es,
- p_pgrm->i_es_number*sizeof(es_descriptor_t *) );
- p_pgrm->ap_es[p_pgrm->i_es_number-1] = p_es;
- intf_DbgMsg( "Added ES %d to definition of pgrm %d\n",
- i_es_pid, p_pgrm->i_number );
- }
- else
- intf_DbgMsg( "Added ES %d not added to the definition of any pgrm\n",
- i_es_pid );
- }
-
- return p_es;
-}
-
-/*****************************************************************************
- * DestroyESDescr:
- *****************************************************************************
- *
- *****************************************************************************/
-static void DestroyESDescr(input_thread_t* p_input,
- pgrm_descriptor_t* p_pgrm, u16 i_pid)
-{
- int i_index;
-
- /* Look for the description of the ES */
- for(i_index = 0; i_index < INPUT_MAX_ES; i_index++)
- {
- if( p_input->p_es[i_index].i_id == i_pid )
- {
- /* The table of stream descriptors is static, so don't free memory
- but just mark the slot as unused */
- p_input->p_es[i_index].i_id = EMPTY_PID;
- break;
- }
- }
-
- /* Remove this ES from the description of the program if it is associated to
- one */
- if( p_pgrm )
- {
- for( i_index = 0; i_index < INPUT_MAX_ES; i_index++ )
- {
- if( p_input->p_es[i_index].i_id == i_pid )
- {
- p_pgrm->i_es_number--;
- p_pgrm->ap_es[i_index] = p_pgrm->ap_es[p_pgrm->i_es_number];
- p_pgrm->ap_es = realloc(p_pgrm->ap_es, p_pgrm->i_es_number);
- break;
- }
- }
- }
-}
+++ /dev/null
-/*****************************************************************************
- * psi.h: PSI management interface
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * Authors: Benoît Steiner <benny@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.
- *****************************************************************************/
-
-/*****************************************************************************
- * Prototypes
- *****************************************************************************/
-int input_PsiInit ( input_thread_t *p_input );
-void input_PsiDecode ( input_thread_t *p_input, psi_section_t* p_psi_section );
-void input_PsiRead ( input_thread_t *p_input );
-int input_PsiEnd ( input_thread_t *p_input );
/*****************************************************************************
- * input_vlan.h: vlan input method
+ * input_ts.c: TS demux and netlist management
*****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
+ * Copyright (C) 1998, 1999, 2000 VideoLAN
*
- * Authors: Vincent Seguin <seguin@via.ecp.fr>
+ * Authors:
*
* 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
*****************************************************************************/
/*****************************************************************************
- * Required headers:
- * <netinet/in.h>
- * "threads.h"
+ * Preamble
*****************************************************************************/
+#include "time_control.h"
+#include "input_ext-intf.h"
+#include "input_ext-dec.h"
/*****************************************************************************
- * Prototypes
+ * Local prototypes
*****************************************************************************/
-int input_VlanCreate ( void );
-void input_VlanDestroy ( void );
-int input_VlanJoin ( int i_vlan_id );
-void input_VlanLeave ( int i_vlan_id );
-
+static int TSProbe ( struct input_thread_s * );
+static void TSRead ( struct input_thread_s * );
+static int TSInit ( struct input_thread_s * );
+static void TSEnd ( struct input_thread_s * );
+static struct data_packet_s * NewPacket ( struct input_thread_s *,
+ size_t );
+static void DeletePacket( struct input_thread_s *,
+ struct data_packet_s * );
+static void DeletePES ( struct input_thread_s *,
+ struct pes_packet_s * );
+/*****************************************************************************
+ * TSProbe: verifies that the stream is a TS stream
+ *****************************************************************************/
+static int TSProbe( input_thread_t * p_input )
+{
+ /* verify that the first byte is 0x47 */
+}
+static void TSInit( input_thread_t * p_input )
+{
+ /* Initialize netlist and TS structures */
+}
--- /dev/null
+/*****************************************************************************
+ * thread_ts_data_t: extension of input_thread_t
+ *****************************************************************************/
+typedef struct thread_ts_data_s
+{
+ /* To use the efficiency of the scatter/gather IO operations without
+ * malloc'ing all the time, we implemented a FIFO of free data packets.
+ */
+ vlc_mutex_lock lock;
+ struct iovec p_free_iovec[INPUT_MAX_TS + INPUT_TS_READ_ONCE];
+ data_packet_t * p_free_ts[INPUT_MAX_TS + INPUT_TS_READ_ONCE];
+ int i_free_start, i_free_end;
+
+ /* The free data packets are stored here : */
+ data_packet_t * p_data_packets;
+ byte_t * p_buffers;
+} thread_ts_data_t;
+++ /dev/null
-/*****************************************************************************
- * input_vlan.c: vlan management library
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * Authors: Vincent Seguin <seguin@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 "defs.h"
-
-#include <errno.h> /* ENOMEM */
-#include <stdio.h> /* sprintf() */
-#include <unistd.h> /* close() */
-#include <string.h> /* strerror(), bzero() */
-#include <stdlib.h> /* free() */
-#include <sys/time.h> /* timeval */
-
-#if defined(SYS_BSD) || defined(SYS_BEOS)
-#include <netinet/in.h> /* struct in_addr */
-#include <sys/socket.h> /* struct sockaddr */
-#endif
-
-#if defined(SYS_LINUX) || defined(SYS_BSD) || defined(SYS_GNU)
-#include <arpa/inet.h> /* inet_ntoa(), inet_aton() */
-#endif
-
-#ifdef SYS_LINUX
-#include <sys/ioctl.h> /* ioctl() */
-#include <net/if.h> /* interface (arch-dependent) */
-#endif
-
-#include "config.h"
-#include "common.h"
-#include "threads.h"
-#include "mtime.h"
-#include "plugins.h"
-#include "netutils.h"
-#include "input_vlan.h"
-#include "intf_msg.h"
-
-#include "main.h"
-
-/*****************************************************************************
- * input_vlan_t: vlan library data
- *****************************************************************************
- * Store global vlan library data.
- *****************************************************************************/
-typedef struct input_vlan_s
-{
- int i_vlan_id; /* current vlan number */
- mtime_t last_change; /* last change date */
-} input_vlan_t;
-
-/*****************************************************************************
- * Local prototypes
- *****************************************************************************/
-
-/*****************************************************************************
- * input_VlanCreate: initialize global vlan method data
- *****************************************************************************
- * Initialize vlan input method global data. This function should be called
- * once before any input thread is created or any call to other input_Vlan*()
- * function is attempted.
- *****************************************************************************/
-int input_VlanCreate( void )
-{
-#ifdef SYS_BEOS
- intf_ErrMsg( "error: vlans are not supported under beos\n" );
- return( 1 );
-#else
- /* Allocate structure */
- p_main->p_vlan = malloc( sizeof( input_vlan_t ) );
- if( p_main->p_vlan == NULL )
- {
- intf_ErrMsg("error: %s\n", strerror(ENOMEM));
- return( 1 );
- }
-
- /* Initialize structure */
- p_main->p_vlan->i_vlan_id = 0;
- p_main->p_vlan->last_change = 0;
-
- intf_Msg("VLANs initialized\n");
- return( 0 );
-#endif /* SYS_BEOS */
-}
-
-/*****************************************************************************
- * input_VlanDestroy: free global vlan method data
- *****************************************************************************
- * Free resources allocated by input_VlanMethodInit. This function should be
- * called at the end of the program.
- *****************************************************************************/
-void input_VlanDestroy( void )
-{
- /* Return to default vlan */
- if( p_main->p_vlan->i_vlan_id != 0 )
- {
- input_VlanJoin( 0 );
- }
-
- /* Free structure */
- free( p_main->p_vlan );
-}
-
-/*****************************************************************************
- * input_VlanLeave: leave a vlan
- *****************************************************************************
- * This function tells the vlan library that the designed interface is no more
- * locked and than vlan changes can occur.
- *****************************************************************************/
-void input_VlanLeave( int i_vlan_id )
-{
- /* XXX?? */
-}
-
-/*****************************************************************************
- * input_VlanJoin: join a vlan
- *****************************************************************************
- * This function will try to join a vlan. If the relevant interface is already
- * on the good vlan, nothing will be done. Else, and if possible (if the
- * interface is not locked), the vlan server will be contacted and a change will
- * be requested. The function will block until the change is effective. Note
- * that once a vlan is no more used, it's interface should be unlocked using
- * input_VlanLeave().
- * Non 0 will be returned in case of error.
- *****************************************************************************/
-int input_VlanJoin( int i_vlan_id )
-{
-#ifdef SYS_BEOS
- return( -1 );
-#else
-
-#define SERVER "138.195.130.90"
-#define INTERFACE "eth0"
-/* default server port */
-#define VLANSERVER_PORT 6010
-
- int socket_cl;
- int fromlen;
- struct ifreq interface;
- struct sockaddr_in sa_server;
- struct sockaddr_in sa_client;
- unsigned int version = 12;
- char mess[80];
- struct timeval *date_cl;
- struct timeval time;
- long unsigned int date;
- int nbanswer;
- char answer;
- fd_set rfds;
-
- /* If last change is too recent, wait a while */
- if( mdate() - p_main->p_vlan->last_change < INPUT_VLAN_CHANGE_DELAY )
- {
- intf_Msg("Waiting before changing VLAN...\n");
- mwait( p_main->p_vlan->last_change + INPUT_VLAN_CHANGE_DELAY );
- }
- p_main->p_vlan->last_change = mdate();
- p_main->p_vlan->i_vlan_id = i_vlan_id;
-
- intf_Msg("Joining VLAN %d (channel %d)\n", i_vlan_id + 2, i_vlan_id );
-
- /*
- *Looking for informations about the eth0 interface
- */
- interface.ifr_addr.sa_family = AF_INET;
- strcpy( interface.ifr_name, INTERFACE );
-
-
- /*
- * Initialysing the socket
- */
- socket_cl = socket( AF_INET, SOCK_DGRAM, 0 );
- intf_DbgMsg( "socket %d\n", socket_cl );
-
-
- /*
- * Getting the server's information
- */
- bzero (&sa_server, sizeof (struct sockaddr_in));
- sa_server.sin_family = AF_INET;
- sa_server.sin_port = htons (VLANSERVER_PORT);
- inet_aton (SERVER, &(sa_server.sin_addr));
-
- /*
- * Looking for the interface MAC address
- */
- ioctl( socket_cl, SIOCGIFHWADDR, &interface );
- intf_DbgMsg( "macaddr == %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
- interface.ifr_hwaddr.sa_data[0] & 0xff,
- interface.ifr_hwaddr.sa_data[1] & 0xff,
- interface.ifr_hwaddr.sa_data[2] & 0xff,
- interface.ifr_hwaddr.sa_data[3] & 0xff,
- interface.ifr_hwaddr.sa_data[4] & 0xff,
- interface.ifr_hwaddr.sa_data[5] & 0xff );
-
- /*
- * Getting date of the client
- */
- date_cl = malloc (sizeof (struct timeval));
- if (gettimeofday (date_cl, 0) == -1)
- {
- return -1;
- }
- date = date_cl->tv_sec;
- intf_DbgMsg ("date %lu\n", date);
-
-
- /*
- * Build of the message
- */
- sprintf (mess, "%d %u %lu %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x \n",
- i_vlan_id, version, date,
- interface.ifr_hwaddr.sa_data[0] & 0xff,
- interface.ifr_hwaddr.sa_data[1] & 0xff,
- interface.ifr_hwaddr.sa_data[2] & 0xff,
- interface.ifr_hwaddr.sa_data[3] & 0xff,
- interface.ifr_hwaddr.sa_data[4] & 0xff,
- interface.ifr_hwaddr.sa_data[5] & 0xff);
- intf_DbgMsg ("The message is %s\n", mess);
-
-
- /*
- * Open the socket 2
- */
- bzero (&sa_client, sizeof (struct sockaddr_in));
- sa_client.sin_family = AF_INET;
- sa_client.sin_port = htons( 4312 );
- sa_client.sin_addr.s_addr = INADDR_ANY;
- intf_DbgMsg ("socket %d\n", socket_cl = socket( AF_INET, SOCK_DGRAM, 0 ));
- fromlen = sizeof (struct sockaddr);
- intf_DbgMsg( "bind %i\n", bind( socket_cl, (struct sockaddr *)(&sa_client), sizeof( struct sockaddr )));
-
-
- /*
- * Send the message
- */
- sendto (socket_cl, mess, 80, 0, (struct sockaddr *)(&sa_server), sizeof (struct sockaddr ));
- {
- unsigned z;
- printf("BBP\n");
- z=0;
- do {z++;} while (mess[z]!=':');
- do {z++;} while (mess[z]!='e');
- printf("meuuh %d %d\n",(unsigned)mess[z+3],(unsigned)mess[z+4]);
- }
- printf("BBP2\n");
-
-
- /*
- * Waiting 5 sec for one answer from the server
- */
- time.tv_sec = 5;
- time.tv_usec = 0;
- FD_ZERO( &rfds );
- FD_SET( socket_cl, &rfds );
- nbanswer = select( socket_cl + 1, &rfds, NULL, NULL, &time);
- if( nbanswer == 0 )
- {
- intf_DbgMsg( "no answer\n" );
- }
- else if( nbanswer == -1 )
- {
- intf_DbgMsg( "I couldn't recieve the answer\n" );
- }
- else
- {
- recvfrom (socket_cl, &answer, sizeof( char ), 0, (struct sockaddr *)(&sa_client), &fromlen);
- intf_DbgMsg( "the answer : %hhd\n", answer );
- if( answer == -1 )
- {
- intf_DbgMsg( "The server doesn't succed to create the thread\n" );
- }
- else if( answer == 0 )
- {
- intf_DbgMsg( "The server try to change the channel\n" );
- }
- else
- {
- intf_DbgMsg( "I don't know what is this answer !\n" );
- }
- }
-
-
- /*
- * Close the socket
- */
- close( socket_cl);
-
- return 0;
-#endif
-}
--- /dev/null
+/*****************************************************************************
+ * mpeg_system.c: TS, PS and PES management
+ *****************************************************************************
+ * Copyright (C) 1998, 1999, 2000 VideoLAN
+ *
+ * Authors:
+ *
+ * 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 "defs.h"
+
+#include <stdlib.h>
+#include <netinet/in.h>
+
+#include "config.h"
+#include "common.h"
+#include "threads.h"
+#include "mtime.h"
+
+#include "intf_msg.h"
+
+#include "stream_control.h"
+#include "input_ext-intf.h"
+#include "input_ext-dec.h"
+
+#include "input.h"
+
+#include "mpeg_system.h"
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+
+
+/*
+ * PES Packet management
+ */
+
+/*****************************************************************************
+ * input_DecodePES
+ *****************************************************************************
+ * Put a PES in the decoder's fifo.
+ *****************************************************************************/
+void input_DecodePES( input_thread_t * p_input, es_descriptor_t * p_es )
+{
+#define p_pes (p_es->p_pes)
+
+ /* FIXME: since we don't check the type of the stream anymore, we don't
+ * do the following : p_data->p_payload_start++; for DVD_SPU_ES, and
+ * DVD SPU support is BROKEN ! */
+
+ if( p_es->p_decoder_fifo != NULL )
+ {
+ vlc_mutex_lock( &p_es->p_decoder_fifo->data_lock );
+ if( !DECODER_FIFO_ISFULL( *p_es->p_decoder_fifo ) )
+ {
+ //intf_DbgMsg("Putting %p into fifo %p/%d\n",
+ // p_pes, p_fifo, p_fifo->i_end);
+ p_es->p_decoder_fifo->buffer[p_es->p_decoder_fifo->i_end] = p_pes;
+ DECODER_FIFO_INCEND( *p_es->p_decoder_fifo );
+
+ /* Warn the decoder that it's got work to do. */
+ vlc_cond_signal( &p_es->p_decoder_fifo->data_wait );
+ }
+ else
+ {
+ /* The FIFO is full !!! This should not happen. */
+ p_input->p_plugin->pf_delete_pes( p_input->p_method_data, p_pes );
+ intf_ErrMsg( "PES trashed - fifo full ! (%d, %d)",
+ p_es->i_id, p_es->i_type);
+ }
+ vlc_mutex_unlock( &p_es->p_decoder_fifo->data_lock );
+ }
+ else
+ {
+ intf_ErrMsg("No fifo to receive PES %p (who wrote this damn code ?)",
+ p_pes);
+ p_input->p_plugin->pf_delete_pes( p_input->p_method_data, p_pes );
+ }
+ p_pes = NULL;
+
+#undef p_pes
+}
+
+/*****************************************************************************
+ * input_ParsePES
+ *****************************************************************************
+ * Parse a finished PES packet and analyze its header.
+ *****************************************************************************/
+#define PES_HEADER_SIZE 14
+void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
+{
+ data_packet_t * p_header_data;
+ byte_t p_header[PES_HEADER_SIZE];
+ int i_done, i_todo;
+
+#define p_pes (p_es->p_pes)
+
+ //intf_DbgMsg("End of PES packet %p\n", 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_header_data = p_pes->p_first;
+ i_done = 0;
+
+ for( ; ; )
+ {
+ i_todo = p_header_data->p_payload_end
+ - p_header_data->p_payload_start;
+ if( i_todo > PES_HEADER_SIZE - i_done )
+ i_todo = PES_HEADER_SIZE - i_done;
+
+ memcpy( p_header + i_done, p_header_data->p_payload_start,
+ i_todo );
+ i_done += i_todo;
+
+ if( i_done < PES_HEADER_SIZE && p_header_data->p_next != NULL )
+ {
+ p_header_data = p_header_data->p_next;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if( i_done != PES_HEADER_SIZE )
+ {
+ intf_WarnMsg( 3, "PES packet too short to have a header" );
+ p_input->p_plugin->pf_delete_pes( 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) + 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 */
+ intf_ErrMsg( "PES packet doesn't start with 0x000001 : data loss" );
+ p_input->p_plugin->pf_delete_pes( 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. */
+ intf_WarnMsg( 3, "PES sizes do not match : packet corrupted" );
+ p_pes->b_messed_up = 1;
+ }
+
+ 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:
+ /* The PES header contains at least 3 more bytes. */
+ p_pes->b_data_alignment = p_header[6] & 0x04;
+ p_pes->b_has_pts = p_header[7] & 0x80;
+ i_pes_header_size = p_header[8] + 9;
+
+ /* Now parse the optional header extensions (in the limit of
+ * the 14 bytes). */
+ if( p_pes->b_has_pts )
+ {
+ p_pes->i_pts =
+ ( ((mtime_t)(p_header[9] & 0x0E) << 29) |
+ (((mtime_t)U16_AT(p_header + 10) << 14) - (1 << 14)) |
+ ((mtime_t)U16_AT(p_header + 12) >> 1) ) * 300;
+ p_pes->i_pts /= 27;
+
+ switch( p_es->p_pgrm->i_synchro_state )
+ {
+ case SYNCHRO_NOT_STARTED:
+ p_pes->b_has_pts = 0;
+ break;
+
+ case SYNCHRO_START:
+ p_pes->i_pts += p_es->p_pgrm->delta_cr;
+ p_es->p_pgrm->delta_absolute = mdate()
+ - p_pes->i_pts + DEFAULT_PTS_DELAY;
+ p_pes->i_pts += p_es->p_pgrm->delta_absolute;
+ p_es->p_pgrm->i_synchro_state = SYNCHRO_OK;
+ break;
+
+ case SYNCHRO_REINIT: /* We skip a PES | Why ?? --Meuuh */
+ p_pes->b_has_pts = 0;
+ p_es->p_pgrm->i_synchro_state = SYNCHRO_START;
+ break;
+
+ case SYNCHRO_OK:
+ p_pes->i_pts += p_es->p_pgrm->delta_cr
+ + p_es->p_pgrm->delta_absolute;
+ break;
+ }
+ }
+ break;
+ }
+
+ /* 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_header_data = p_pes->p_first;
+ i_payload_size = p_header_data->p_payload_end
+ - p_header_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_header_data->p_payload_start = p_header_data->p_payload_end;
+ /* Go to the next data packet. */
+ if( (p_header_data = p_header_data->p_next) == NULL )
+ {
+ intf_ErrMsg( "PES header bigger than payload" );
+ p_input->p_plugin->pf_delete_pes( p_input->p_method_data,
+ p_pes );
+ p_pes = NULL;
+ return;
+ }
+ i_payload_size = p_header_data->p_payload_end
+ - p_header_data->p_payload_start;
+ }
+ /* This last packet is partly header, partly payload. */
+ if( i_payload_size < i_pes_header_size )
+ {
+ intf_ErrMsg( "PES header bigger than payload" );
+ p_input->p_plugin->pf_delete_pes( p_input->p_method_data, p_pes );
+ p_pes = NULL;
+ return;
+ }
+ p_header_data->p_payload_start += i_pes_header_size;
+
+ /* Now we can eventually put the PES packet in the decoder's
+ * PES fifo */
+ input_DecodePES( p_input, p_es );
+ }
+#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,
+ boolean_t b_unit_start, boolean_t b_packet_lost )
+{
+#define p_pes (p_es->p_pes)
+
+ //intf_DbgMsg("PES-demultiplexing %p (%p)\n", p_ts_packet, p_pes);
+
+ /* If we lost data, insert an 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 && p_pes != NULL )
+ {
+ data_packet_t * p_pad_data;
+ if( (p_pad_data = p_input->p_plugin->pf_new_packet( p_input,
+ PADDING_PACKET_SIZE )) == NULL )
+ {
+ intf_ErrMsg("Out of memory\n");
+ p_input->b_error = 1;
+ return;
+ }
+ memset( p_data->p_buffer, 0, PADDING_PACKET_SIZE );
+ p_pad_data->b_discard_payload = 1;
+ p_pes->b_messed_up = 1;
+ input_GatherPES( p_input, p_pad_data, p_es, 0, 0 );
+ }
+
+ if( b_unit_start && p_pes != NULL )
+ {
+ /* If the TS 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... */
+ p_input->p_plugin->pf_delete_packet( 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 = (pes_packet_t *)malloc( sizeof(pes_packet_t) )) == NULL )
+ {
+ intf_ErrMsg("Out of memory");
+ p_input->b_error = 1;
+ return;
+ }
+ //intf_DbgMsg("New PES packet %p (first data: %p)\n", p_pes, p_data);
+
+ /* Init the PES fields so that the first data packet could be
+ * correctly added to the PES packet (see below). */
+ p_pes->p_first = p_data;
+ p_pes->b_messed_up = p_pes->b_discontinuity = 0;
+ p_pes->i_pes_size = 0;
+
+ /* 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_AT(p_data->p_payload_start + 4) + 6;
+ }
+ else
+ {
+ p_es->i_pes_real_size = 0;
+ }
+ }
+ else
+ {
+ /* Update the relations between the data packets */
+ p_es->p_last->p_next = p_data;
+ }
+
+ p_data->p_next = NULL;
+ p_es->p_last = p_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
+}
+
+
+/*
+ * Pace control
+ */
+
+/*
+ * DISCUSSION : SYNCHRONIZATION METHOD
+ *
+ * In some cases we can impose the pace of reading (when reading from a
+ * file or a pipe), and for the synchronization we simply sleep() until
+ * it is time to deliver the packet to the decoders. When reading from
+ * the network, we must be read at the same pace as the server writes,
+ * otherwise the kernel's buffer will trash packets. The risk is now to
+ * overflow the input buffers in case the server goes too fast, that is
+ * why we do these calculations :
+ *
+ * We compute an average for the pcr because we want to eliminate the
+ * network jitter and keep the low frequency variations. The average is
+ * in fact a low pass filter and the jitter is a high frequency signal
+ * that is why it is eliminated by the filter/average.
+ *
+ * The low frequency variations enable us to synchronize the client clock
+ * with the server clock because they represent the time variation between
+ * the 2 clocks. Those variations (ie the filtered pcr) are used to compute
+ * the presentation dates for the audio and video frames. With those dates
+ * we can decode (or trash) the MPEG2 stream at "exactly" the same rate
+ * as it is sent by the server and so we keep the synchronization between
+ * the server and the client.
+ *
+ * It is a very important matter if you want to avoid underflow or overflow
+ * in all the FIFOs, but it may be not enough.
+ */
+
+/*****************************************************************************
+ * Constants
+ *****************************************************************************/
+
+/* Maximum number of samples used to compute the dynamic average value,
+ * it is also the maximum of c_average_count in pgrm_ts_data_t.
+ * We use the following formula :
+ * new_average = (old_average * c_average + new_sample_value) / (c_average +1) */
+#define CR_MAX_AVERAGE_COUNTER 40
+
+/* Maximum gap allowed between two CRs. */
+#define CR_MAX_GAP 1000000
+
+/*****************************************************************************
+ * CRReInit : Reinitialize the clock reference
+ *****************************************************************************/
+static void CRReInit( pgrm_descriptor_t * p_pgrm )
+{
+ p_pgrm->delta_cr = 0;
+ p_pgrm->last_cr = 0;
+ p_pgrm->c_average_count = 0;
+}
+
+/* FIXME: find a better name */
+/*****************************************************************************
+ * CRDecode : Decode a clock reference
+ *****************************************************************************/
+static void CRDecode( input_thread_t * p_input, es_descriptor_t * p_es,
+ mtime_t cr_time )
+{
+ pgrm_descriptor_t * p_pgrm;
+ if( p_es != NULL )
+ {
+ p_pgrm = p_es->p_pgrm;
+ }
+ else
+ {
+ p_pgrm = p_input->stream.pp_programs[0];
+ }
+
+ if( p_input->stream.b_pace_control )
+ {
+ /* Wait a while before delivering the packets to the decoder. */
+ mwait( cr_time + p_pgrm->delta_absolute );
+ }
+ else
+ {
+ mtime_t sys_time, delta_cr;
+
+ sys_time = mdate();
+ delta_cr = sys_time - cr_time;
+
+ if( (p_es != NULL && p_es->b_discontinuity) ||
+ ( p_pgrm->last_cr != 0 &&
+ ( (p_pgrm->last_cr - cr_time) > CR_MAX_GAP
+ || (p_pgrm->last_cr - cr_time) < - CR_MAX_GAP ) ) )
+ {
+ intf_WarnMsg( 3, "CR re-initialiazed" );
+ CRReInit( p_pgrm );
+ p_pgrm->i_synchro_state = SYNCHRO_REINIT;
+ if( p_es != NULL )
+ {
+ p_es->b_discontinuity = 0;
+ }
+ }
+ p_pgrm->last_cr = cr_time;
+
+ if( p_pgrm->c_average_count == CR_MAX_AVERAGE_COUNTER )
+ {
+ p_pgrm->delta_cr = ( delta_cr + (p_pgrm->delta_cr
+ * (CR_MAX_AVERAGE_COUNTER - 1)) )
+ / CR_MAX_AVERAGE_COUNTER;
+ }
+ else
+ {
+ p_pgrm->delta_cr = ( delta_cr + (p_pgrm->delta_cr
+ * p_pgrm->c_average_count) )
+ / ( p_pgrm->c_average_count + 1 );
+ p_pgrm->c_average_count++;
+ }
+
+ if( p_pgrm->i_synchro_state == SYNCHRO_NOT_STARTED )
+ {
+ p_pgrm->i_synchro_state = SYNCHRO_START;
+ }
+ }
+}
+
+
+/*
+ * PS Demultiplexing
+ */
+
+/*****************************************************************************
+ * DecodePSM: Decode the Program Stream Map information
+ *****************************************************************************/
+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;
+
+ if( !p_demux->b_is_PSM_complete )
+ {
+ byte_t * p_byte;
+ byte_t * p_end;
+ int i_es = 0;
+
+ intf_DbgMsg( "Building PSM" );
+ if( p_data->p_payload_start + 10 > p_data->p_payload_end )
+ {
+ intf_ErrMsg( "PSM too short : packet corrupt" );
+ return;
+ }
+ /* Go to elementary_stream_map_length, jumping over
+ * program_stream_info. */
+ p_byte = p_data->p_payload_start + 10
+ + U16_AT(&p_data->p_payload_start[8]);
+ if( p_byte > p_data->p_payload_end )
+ {
+ intf_ErrMsg( "PSM too short : packet corrupt" );
+ return;
+ }
+ /* This is the full size of the elementary_stream_map.
+ * 2 == elementary_stream_map_length
+ * 4 == CRC_32 */
+ p_end = p_byte + 2 + U16_AT(p_byte) - 4;
+ p_byte += 2;
+ if( p_end > p_data->p_payload_end )
+ {
+ intf_ErrMsg( "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 )
+ {
+ p_input->p_es[i_es].i_id
+ = p_input->p_es[i_es].i_stream_id
+ = p_byte[1];
+ p_input->p_es[i_es].i_type = p_byte[0];
+ p_input->p_es[i_es].p_pgrm = p_input->stream.pp_programs[0];
+ p_input->p_es[i_es].b_discontinuity = 0;
+ p_input->p_es[i_es].p_pes = NULL;
+ p_byte += 4 + U16_AT(&p_byte[2]);
+
+#ifdef AUTO_SPAWN
+ switch( p_input->p_es[i_es].i_type )
+ {
+ case MPEG1_AUDIO_ES:
+ case MPEG2_AUDIO_ES:
+ /* Spawn audio thread. */
+ intf_DbgMsg( "Starting an MPEG-audio decoder" );
+ break;
+
+ case MPEG1_VIDEO_ES:
+ case MPEG2_VIDEO_ES:
+ /* Spawn video thread. */
+ intf_DbgMsg( "Starting an MPEG-video decoder" );
+ break;
+ }
+#endif
+
+ i_es++;
+ }
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ p_demux->i_PSM_version = p_data->p_buffer[6] & 0x1F;
+ p_demux->b_is_PSM_complete = 1;
+ }
+ else if( p_demux->i_PSM_version != (p_data->p_buffer[6] & 0x1F) )
+ {
+ /* FIXME */
+ intf_ErrMsg( "PSM changed, this is not supported yet !" );
+ p_demux->i_PSM_version = p_data->p_buffer[6] & 0x1F;
+ }
+}
+
+/*****************************************************************************
+ * 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;
+ boolean_t b_trash = 0;
+ es_descriptor_t * p_es = NULL;
+
+ i_code = U32_AT( p_data->p_buffer );
+ if( i_code >= 0x1B9 && i_code <= 0x1BC )
+ {
+ switch( i_code )
+ {
+ case 0x1BA: /* PACK_START_CODE */
+ if( p_input->stream.pp_programs[0]->i_synchro_state == SYNCHRO_OK )
+ {
+ /* Convert the SCR in microseconds. */
+ mtime_t scr_time;
+ scr_time = (( ((mtime_t)(p_data->p_buffer[4] & 0x38) << 27) |
+ ((mtime_t)(p_data->p_buffer[4] & 0x3) << 26) |
+ ((mtime_t)(p_data->p_buffer[5]) << 20) |
+ ((mtime_t)(p_data->p_buffer[6] & 0xF8) << 12) |
+ ((mtime_t)(p_data->p_buffer[6] & 0x3) << 13) |
+ ((mtime_t)(p_data->p_buffer[7]) << 5) |
+ ((mtime_t)(p_data->p_buffer[8] & 0xF8) >> 3)
+ ) * 300) / 27;
+
+ /* Call the pace control. */
+ CRDecode( p_input, NULL, scr_time );
+ }
+ b_trash = 1;
+ break;
+
+ case 0x1BB: /* SYSTEM_START_CODE */
+ b_trash = 1; /* Nothing interesting */
+ break;
+
+ case 0x1BC: /* PROGRAM_STREAM_MAP_CODE */
+ intf_ErrMsg("meuuuuh\n");
+ 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;
+ intf_WarnMsg( 1, "Unwanted packet received with start code %x",
+ i_code );
+ }
+ }
+ else
+ {
+ u16 i_id;
+ int i_dummy;
+
+ /* This is a PES packet. Find out if we want it or not. */
+ i_id = p_data->p_buffer[3]; /* ID of the stream. */
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ for( i_dummy = 0; i_dummy < INPUT_MAX_ES; i_dummy++ )
+ {
+ if( p_input->p_es[i_dummy].i_id == i_id )
+ {
+ p_es = &p_input->p_es[i_dummy];
+ break;
+ }
+ }
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ if( p_es == NULL )
+ {
+#if 1
+ /* FIXME ! */
+ if( (i_id & 0xC0L) == 0xC0L )
+ {
+ /* MPEG video and audio */
+ for( i_dummy = 0; i_dummy < INPUT_MAX_ES; i_dummy++ )
+ {
+ if( p_input->p_es[i_dummy].i_id == EMPTY_ID )
+ {
+ p_es = &p_input->p_es[i_dummy];
+ break;
+ }
+ }
+
+ if( p_es != NULL && (i_id & 0xF0L) == 0xE0L )
+ {
+ /* MPEG video */
+ vdec_config_t * p_config;
+ p_es->i_id = p_es->i_stream_id = i_id;
+ p_es->i_type = MPEG2_VIDEO_ES;
+ p_es->p_pgrm = p_input->stream.pp_programs[0];
+ p_es->b_discontinuity = 0;
+ p_es->p_pes = NULL;
+
+#ifdef AUTO_SPAWN
+ p_config = (vdec_config_t *)malloc( sizeof(vdec_config_t) );
+ p_config->p_vout = p_input->p_default_vout;
+ /* FIXME ! */
+ p_config->decoder_config.i_stream_id = i_id;
+ p_config->decoder_config.i_type = MPEG2_VIDEO_ES;
+ p_config->decoder_config.p_stream_ctrl =
+ &p_input->stream.control;
+ p_config->decoder_config.p_decoder_fifo =
+ (decoder_fifo_t *)malloc( sizeof(decoder_fifo_t) );
+ vlc_mutex_init(&p_config->decoder_config.p_decoder_fifo->data_lock);
+ vlc_cond_init(&p_config->decoder_config.p_decoder_fifo->data_wait);
+ p_config->decoder_config.p_decoder_fifo->i_start =
+ p_config->decoder_config.p_decoder_fifo->i_end = 0;
+ p_config->decoder_config.p_decoder_fifo->b_die = 0;
+ p_config->decoder_config.p_decoder_fifo->p_packets_mgt =
+ p_input->p_method_data;
+ p_config->decoder_config.p_decoder_fifo->pf_delete_pes =
+ p_input->p_plugin->pf_delete_pes;
+ p_es->p_decoder_fifo = p_config->decoder_config.p_decoder_fifo;
+ p_config->decoder_config.pf_init_bit_stream =
+ InitBitstream;
+ for( i_dummy = 0; i_dummy < INPUT_MAX_SELECTED_ES; i_dummy++ )
+ {
+ if( p_input->pp_selected_es[i_dummy] == NULL )
+ {
+ p_input->pp_selected_es[i_dummy] = p_es;
+ break;
+ }
+ }
+
+ p_es->thread_id = vpar_CreateThread( p_config );
+#endif
+ }
+ else if( p_es != NULL && (i_id & 0xE0) == 0xC0 )
+ {
+ /* MPEG audio */
+ adec_config_t * p_config;
+ p_es->i_id = p_es->i_stream_id = i_id;
+ p_es->i_type = MPEG2_AUDIO_ES;
+ p_es->p_pgrm = p_input->stream.pp_programs[0];
+ p_es->b_discontinuity = 0;
+ p_es->p_pes = NULL;
+
+#ifdef AUTO_SPAWN
+ p_config = (adec_config_t *)malloc( sizeof(adec_config_t) );
+ p_config->p_aout = p_input->p_default_aout;
+ /* FIXME ! */
+ p_config->decoder_config.i_stream_id = i_id;
+ p_config->decoder_config.i_type = MPEG2_AUDIO_ES;
+ p_config->decoder_config.p_stream_ctrl =
+ &p_input->stream.control;
+ p_config->decoder_config.p_decoder_fifo =
+ (decoder_fifo_t *)malloc( sizeof(decoder_fifo_t) );
+ vlc_mutex_init(&p_config->decoder_config.p_decoder_fifo->data_lock);
+ vlc_cond_init(&p_config->decoder_config.p_decoder_fifo->data_wait);
+ p_config->decoder_config.p_decoder_fifo->i_start =
+ p_config->decoder_config.p_decoder_fifo->i_end = 0;
+ p_config->decoder_config.p_decoder_fifo->b_die = 0;
+ p_config->decoder_config.p_decoder_fifo->p_packets_mgt =
+ p_input->p_method_data;
+ p_config->decoder_config.p_decoder_fifo->pf_delete_pes =
+ p_input->p_plugin->pf_delete_pes;
+ p_es->p_decoder_fifo = p_config->decoder_config.p_decoder_fifo;
+ p_config->decoder_config.pf_init_bit_stream =
+ InitBitstream;
+ for( i_dummy = 0; i_dummy < INPUT_MAX_SELECTED_ES; i_dummy++ )
+ {
+ if( p_input->pp_selected_es[i_dummy] == NULL )
+ {
+ p_input->pp_selected_es[i_dummy] = p_es;
+ break;
+ }
+ }
+
+ p_es->thread_id = adec_CreateThread( p_config );
+#endif
+ }
+ else
+ {
+ b_trash = 1;
+ }
+ }
+ else
+ b_trash = 1;
+#else
+ b_trash = 1;
+#endif
+ }
+ else
+ {
+#ifdef STATS
+ p_es->c_packets++;
+#endif
+ input_GatherPES( p_input, p_data, p_es, 1, 0 );
+ }
+ }
+
+ /* Trash the packet if it has no payload or if it isn't selected */
+ if( b_trash )
+ {
+ p_input->p_plugin->pf_delete_packet( p_input, p_data );
+#ifdef STATS
+ p_input->c_packets_trashed++;
+#endif
+ }
+}
+
+
+/*
+ * TS Demultiplexing
+ */
+
+/*****************************************************************************
+ * input_DemuxTS: first step of demultiplexing: the TS header
+ *****************************************************************************/
+void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_data )
+{
+ int i_pid, i_dummy;
+ boolean_t b_adaptation; /* Adaptation field is present */
+ boolean_t b_payload; /* Packet carries payload */
+ boolean_t b_unit_start; /* A PSI or a PES start in the packet */
+ boolean_t b_trash = 0; /* Is the packet unuseful ? */
+ boolean_t b_lost = 0; /* Was there a packet loss ? */
+ 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_buffer)
+
+ //intf_DbgMsg("input debug: TS-demultiplexing packet %p, pid %d\n",
+ // p_ts_packet, U16_AT(&p[1]) & 0x1fff);
+
+ /* Extract flags values from TS common header. */
+ i_pid = U16_AT(&p[1]) & 0x1fff;
+ 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 < INPUT_MAX_ES; i_dummy++ )
+ {
+ if( p_input->p_es[i_dummy].i_id != EMPTY_ID )
+ {
+ if( p_input->p_es[i_dummy].i_id == i_pid )
+ {
+ p_es = &p_input->p_es[i_dummy];
+ p_es_demux = (es_ts_data_t *)p_es->p_demux_data;
+ p_pgrm_demux = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data;
+ break;
+ }
+ }
+ }
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+#ifdef STATS
+ p_es->c_packets++;
+#endif
+
+ if( p_es->p_decoder_fifo == NULL )
+ {
+ /* Not selected. Just read the adaptation field for a PCR. */
+ b_trash = 1;
+ }
+
+ if( (p_es->p_decoder_fifo != NULL) || (p_pgrm_demux->i_pcr_pid == i_pid) )
+ {
+ /* 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) )
+ {
+ intf_WarnMsg( 2,
+ "invalid TS adaptation field (%p)",
+ p_data );
+ p_data->b_discard_payload = 1;
+#ifdef STATS
+ p_es->c_invalid_packets++;
+#endif
+ }
+
+ /* Now we are sure that the byte containing flags is present:
+ * read it */
+ else
+ {
+ /* discontinuity_indicator */
+ if( p[5] & 0x80 )
+ {
+ intf_WarnMsg( 2,
+ "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->b_discontinuity = 1;
+
+ /* There also may be a continuity_counter
+ * discontinuity: resynchronise our counter with
+ * the one of the stream. */
+ p_es_demux->i_continuity_counter = (p[3] & 0x0f) - 1;
+ }
+
+ /* If this is a PCR_PID, and this TS packet contains a
+ * PCR, we pass it along to the PCR decoder. */
+ if( (p_pgrm_demux->i_pcr_pid == i_pid) && (p[5] & 0x10) )
+ {
+ /* There should be a PCR field in the packet, check
+ * if the adaptation field is long enough to carry
+ * it. */
+ if( p[4] >= 7 )
+ {
+ /* Convert the PCR in microseconds.
+ * WARNING: do not remove the casts in the
+ * following calculation ! */
+ mtime_t pcr_time;
+ pcr_time =
+ ( (( (mtime_t)U32_AT((u32*)&p[6]) << 1 )
+ | ( p[10] >> 7 )) * 300 ) / 27;
+ /* Call the pace control. */
+ CRDecode( p_input, p_es, pcr_time );
+ }
+ } /* PCR ? */
+ } /* 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. */
+ intf_WarnMsg( 1,
+ "Packet without payload received by TS demux" );
+ b_trash = 1;
+ }
+ else if( i_dummy <= 0 )
+ {
+ /* FIXME: this can never happen, can it ? --Meuuh */
+ /* Duplicate packet: mark it as being to be trashed. */
+ intf_WarnMsg( 1, "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. */
+ intf_DbgMsg( "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 */
+ intf_WarnMsg( 2,
+ "Packet lost by TS demux: current %d, packet %d\n",
+ 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 */
+
+ /* Trash the packet if it has no payload or if it isn't selected */
+ if( b_trash )
+ {
+ p_input->p_plugin->pf_delete_packet( p_input, p_data );
+#ifdef STATS
+ p_input->c_packets_trashed++;
+#endif
+ }
+ else
+ {
+ if( p_es_demux->b_psi )
+ {
+ /* The payload contains PSI tables */
+#if 0
+ input_DemuxPSI( p_input, p_data, p_es,
+ b_unit_start, b_lost );
+#endif
+ }
+ else
+ {
+ /* The payload carries a PES stream */
+ if( b_unit_start )
+ input_GatherPES( p_input, p_data, p_es, b_unit_start, b_lost );
+ }
+ }
+
+#undef p
+}
--- /dev/null
+/*****************************************************************************
+ * Constants
+ *****************************************************************************/
+#define TS_PACKET_SIZE 188 /* Size of a TS packet */
+#define PSI_SECTION_SIZE 4096 /* Maximum size of a PSI section */
+#define PADDING_PACKET_SIZE 100 /* Size of the NULL packet inserted in case
+ * of data loss (this should be < 188). */
+
+
+/*****************************************************************************
+ * 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_s
+{
+ byte_t buffer[PSI_SECTION_SIZE];
+
+ /* Is there a section being decoded ? */
+ boolean_t b_running_section;
+
+ u16 i_length;
+ u16 i_current_position;
+} psi_section_t;
+
+/*****************************************************************************
+ * es_ts_data_t: extension of es_descriptor_t
+ *****************************************************************************/
+typedef struct es_ts_data_s
+{
+ boolean_t b_psi; /* Does the stream have to be handled by
+ * the PSI decoder ? */
+ 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_s
+{
+ u16 i_pcr_pid; /* PCR ES, for TS streams */
+} pgrm_ts_data_t;
+
+/*****************************************************************************
+ * stream_ts_data_t: extension of stream_descriptor_t
+ *****************************************************************************/
+typedef struct stream_ts_data_s
+{
+ /* Program Association Table status */
+ u8 i_PAT_version; /* version number */
+ boolean_t b_is_PAT_complete; /* Is the PAT complete ? */
+ u8 i_known_PAT_sections;
+ /* Number of section we received so far */
+ byte_t a_known_PAT_sections[32];
+ /* Already received sections */
+
+ /* Program Map Table status */
+ boolean_t b_is_PMT_complete; /* Is the PMT complete ? */
+ u8 i_known_PMT_sections;
+ /* Number of section we received so far */
+ byte_t a_known_PMT_sections[32];
+ /* Already received sections */
+
+ /* Service Description Table status */
+ u8 i_SDT_version; /* version number */
+ boolean_t b_is_SDT_complete; /* Is the SDT complete ? */
+ u8 i_known_SDT_sections;
+ /* Number of section we received so far */
+ byte_t a_known_SDT_sections[32];
+ /* Already received sections */
+} stream_ts_data_t;
+
+/*****************************************************************************
+ * stream_ps_data_t: extension of stream_descriptor_t
+ *****************************************************************************/
+typedef struct stream_ps_data_s
+{
+ u8 i_PSM_version;
+ boolean_t b_is_PSM_complete;
+} stream_ps_data_t;
+
+
+/*****************************************************************************
+ * Prototypes
+ *****************************************************************************/
+void input_DecodePES( struct input_thread_s *, struct es_descriptor_s * );
+void input_ParsePES( struct input_thread_s *, struct es_descriptor_s * );
+void input_GatherPES( struct input_thread_s *, struct data_packet_s *,
+ struct es_descriptor_s *, boolean_t, boolean_t );
+void input_DemuxPS( struct input_thread_s *, struct data_packet_s * );
+void input_DemuxTS( struct input_thread_s *, struct data_packet_s * );
#include "mtime.h"
#include "plugins.h"
#include "playlist.h"
-#include "input.h"
+#include "stream_control.h"
+#include "input_ext-intf.h"
#include "audio_output.h"
void intf_Run( intf_thread_t *p_intf )
{
char * psz_server = main_GetPszVariable( INPUT_SERVER_VAR, NULL );
+ input_config_t * p_input_config;
/* If a server was specified */
if( psz_server )
{
- p_intf->p_input = input_CreateThread( INPUT_METHOD_TS_UCAST,
- psz_server, 0, 0,
- p_intf->p_vout, p_main->p_aout, NULL );
+ if( (p_input_config =
+ (input_config_t *)malloc( sizeof(input_config_t) )) == NULL )
+ {
+ intf_ErrMsg("Out of memory");
+ }
+ else
+ {
+ p_input_config->i_method = INPUT_METHOD_UCAST;
+ p_input_config->p_source = psz_server;
+ p_input_config->p_default_aout = p_main->p_aout;
+ p_input_config->p_default_vout = p_intf->p_vout;
+
+ p_intf->p_input = input_CreateThread( p_input_config, NULL );
+ }
}
/* Or if a file was specified */
- else if( p_main->p_playlist->p_list )
+ else if( p_main->p_playlist->p_list != NULL )
{
- p_intf->p_input = input_CreateThread( INPUT_METHOD_TS_FILE, NULL, 0, 0, p_main->p_intf->p_vout, p_main->p_aout, NULL );
+ if( (p_input_config =
+ (input_config_t *)malloc( sizeof(input_config_t) )) == NULL )
+ {
+ intf_ErrMsg("Out of memory");
+ }
+ else
+ {
+ p_input_config->i_method = INPUT_METHOD_FILE;
+ p_input_config->p_source = p_main->p_playlist->p_list[0]; /* FIXME ??? */
+ p_input_config->p_default_aout = p_main->p_aout;
+ p_input_config->p_default_vout = p_intf->p_vout;
+
+ p_intf->p_input = input_CreateThread( p_input_config, NULL );
+ }
}
/* Execute the initialization script - if a positive number is returned,
* the script could be executed but failed */
*****************************************************************************/
int intf_SelectChannel( intf_thread_t * p_intf, int i_channel )
{
+ /* FIXME */
+#if 0
intf_channel_t * p_channel; /* channel */
/* Look for channel in array */
/* Channel does not exist */
intf_Msg("Channel %d does not exist\n", i_channel );
+#endif
return( 1 );
}
#include "plugins.h"
#include "intf_msg.h"
-#include "input.h"
+#include "stream_control.h"
+#include "input_ext-intf.h"
#include "audio_output.h"
#include "intf_cmd.h"
#include "interface.h"
int i_port = 0; /* port parameter */
int i_vlan = 0; /* vlan parameter */
+ /* FIXME */
+#if 0
/* Parse parameters - see command list above */
for ( i_arg = 1; i_arg < i_argc; i_arg++ )
{
p_main->p_intf->p_vout, p_main->p_aout,
NULL );
return( INTF_NO_ERROR );
+#endif
}
/*****************************************************************************
#include "tests.h" /* TestMMX() */
#include "plugins.h"
#include "playlist.h"
-#include "input_vlan.h"
-#include "input_ps.h"
+#include "stream_control.h"
+#include "input_ext-intf.h"
#include "intf_msg.h"
#include "interface.h"
/*
* Initialize shared resources and libraries
*/
+ /* FIXME: no VLANs */
+#if 0
if( p_main->b_vlans && input_VlanCreate() )
{
/* On error during vlans initialization, switch off vlans */
"vlans management is deactivated\n" );
p_main->b_vlans = 0;
}
+#endif
/*
* Open audio device and start aout thread
/*
* Free shared resources and libraries
*/
+ /* FIXME */
+#if 0
if( p_main->b_vlans )
{
input_VlanDestroy();
}
+#endif
/*
* Free plugin bank
main_PutPszVariable( YUV_METHOD_VAR, optarg );
break;
+ /* FIXME */
+#if 0
/* DVD options */
case 'a':
if ( ! strcmp(optarg, "mpeg") )
else
main_PutIntVariable( INPUT_DVD_AUDIO_VAR, REQUESTED_AC3 );
break;
+#endif
case 'c':
main_PutIntVariable( INPUT_DVD_CHANNEL_VAR, atoi(optarg) );
break;
#include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */
-#include "input.h" /* pes_packet_t */
-#include "input_netlist.h" /* input_NetlistFreePES() */
-#include "decoder_fifo.h" /* DECODER_FIFO_(ISEMPTY|START|INCSTART)() */
+#include "stream_control.h"
+#include "input_ext-dec.h"
#include "audio_output.h"
/*****************************************************************************
* lpcmdec_CreateThread: creates an lpcm decoder thread
*****************************************************************************/
-lpcmdec_thread_t * lpcmdec_CreateThread (input_thread_t * p_input)
+vlc_thread_t lpcmdec_CreateThread (adec_config_t * p_config)
{
lpcmdec_thread_t * p_lpcmdec;
intf_DbgMsg ( "LPCM Debug: creating lpcm decoder thread\n" );
/* Allocate the memory needed to store the thread's structure */
if ((p_lpcmdec = (lpcmdec_thread_t *)malloc (sizeof(lpcmdec_thread_t))) == NULL) {
intf_ErrMsg ( "LPCM Error: not enough memory for lpcmdec_CreateThread() to create the new thread\n" );
- return NULL;
+ return 0;
}
/*
*/
p_lpcmdec->b_die = 0;
p_lpcmdec->b_error = 0;
+ p_lpcmdec->p_config = p_config;
+ p_lpcmdec->p_fifo = p_config->decoder_config.p_decoder_fifo;
- /*
- * Initialize the input properties
- */
- /* Initialize the decoder fifo's data lock and conditional variable and set
- * its buffer as empty */
- vlc_mutex_init (&p_lpcmdec->fifo.data_lock);
- vlc_cond_init (&p_lpcmdec->fifo.data_wait);
- p_lpcmdec->fifo.i_start = 0;
- p_lpcmdec->fifo.i_end = 0;
/* Initialize the lpcm decoder structures */
lpcm_init (&p_lpcmdec->lpcm_decoder);
- /* Initialize the bit stream structure */
- p_lpcmdec->p_input = p_input;
-
/*
* Initialize the output properties
*/
- p_lpcmdec->p_aout = p_input->p_aout;
+ p_lpcmdec->p_aout = p_config->p_aout;
p_lpcmdec->p_aout_fifo = NULL;
/* Spawn the lpcm decoder thread */
if (vlc_thread_create(&p_lpcmdec->thread_id, "lpcm decoder", (vlc_thread_func_t)RunThread, (void *)p_lpcmdec)) {
intf_ErrMsg ( "LPCM Error: can't spawn lpcm decoder thread\n" );
free (p_lpcmdec);
- return NULL;
+ return 0;
}
intf_DbgMsg ( "LPCM Debug: lpcm decoder thread (%p) created\n", p_lpcmdec );
- return p_lpcmdec;
-}
-
-/*****************************************************************************
- * lpcmdec_DestroyThread: destroys an lpcm decoder thread
- *****************************************************************************/
-void lpcmdec_DestroyThread (lpcmdec_thread_t * p_lpcmdec)
-{
- intf_DbgMsg ( "LPCM Debug: requesting termination of lpcm decoder thread %p\n", p_lpcmdec );
-
- /* Ask thread to kill itself */
- p_lpcmdec->b_die = 1;
-
- /* Make sure the decoder thread leaves the GetByte() function */
- vlc_mutex_lock (&(p_lpcmdec->fifo.data_lock));
- vlc_cond_signal (&(p_lpcmdec->fifo.data_wait));
- vlc_mutex_unlock (&(p_lpcmdec->fifo.data_lock));
-
- /* Waiting for the decoder thread to exit */
- /* Remove this as soon as the "status" flag is implemented */
- vlc_thread_join (p_lpcmdec->thread_id);
+ return p_lpcmdec->thread_id;
}
/* Following functions are local */
/* Our first job is to initialize the bit stream structure with the
* beginning of the input stream */
- vlc_mutex_lock (&p_lpcmdec->fifo.data_lock);
- while (DECODER_FIFO_ISEMPTY(p_lpcmdec->fifo)) {
+ vlc_mutex_lock (&p_lpcmdec->p_fifo->data_lock);
+ while (DECODER_FIFO_ISEMPTY(*p_lpcmdec->p_fifo)) {
if (p_lpcmdec->b_die) {
- vlc_mutex_unlock (&p_lpcmdec->fifo.data_lock);
+ vlc_mutex_unlock (&p_lpcmdec->p_fifo->data_lock);
return -1;
}
- vlc_cond_wait (&p_lpcmdec->fifo.data_wait, &p_lpcmdec->fifo.data_lock);
+ vlc_cond_wait (&p_lpcmdec->p_fifo->data_wait, &p_lpcmdec->p_fifo->data_lock);
}
- p_lpcmdec->p_ts = DECODER_FIFO_START (p_lpcmdec->fifo)->p_first_ts;
+ p_lpcmdec->p_data = DECODER_FIFO_START (*p_lpcmdec->p_fifo)->p_first;
byte_stream = lpcm_byte_stream (&p_lpcmdec->lpcm_decoder);
- byte_stream->p_byte =
- p_lpcmdec->p_ts->buffer + p_lpcmdec->p_ts->i_payload_start;
- byte_stream->p_end =
- p_lpcmdec->p_ts->buffer + p_lpcmdec->p_ts->i_payload_end;
+ byte_stream->p_byte = p_lpcmdec->p_data->p_payload_start;
+ byte_stream->p_end = p_lpcmdec->p_data->p_payload_end;
byte_stream->info = p_lpcmdec;
- vlc_mutex_unlock (&p_lpcmdec->fifo.data_lock);
+ vlc_mutex_unlock (&p_lpcmdec->p_fifo->data_lock);
aout_fifo.i_type = AOUT_ADEC_STEREO_FIFO;
aout_fifo.i_channels = 2;
intf_DbgMsg( "LPCM Debug: running lpcm decoder thread (%p) (pid== %i)\n", p_lpcmdec, getpid() );
- msleep (INPUT_PTS_DELAY);
+ /* Fucking holy piece of shit ! */
+ //msleep (INPUT_PTS_DELAY);
/* Initializing the lpcm decoder thread */
if (InitThread (p_lpcmdec))
/* have to find a synchro point */
}
- if (DECODER_FIFO_START(p_lpcmdec->fifo)->b_has_pts)
+ if (DECODER_FIFO_START(*p_lpcmdec->p_fifo)->b_has_pts)
{
- p_lpcmdec->p_aout_fifo->date[p_lpcmdec->p_aout_fifo->l_end_frame] = DECODER_FIFO_START(p_lpcmdec->fifo)->i_pts;
- DECODER_FIFO_START(p_lpcmdec->fifo)->b_has_pts = 0;
+ p_lpcmdec->p_aout_fifo->date[p_lpcmdec->p_aout_fifo->l_end_frame] = DECODER_FIFO_START(*p_lpcmdec->p_fifo)->i_pts;
+ DECODER_FIFO_START(*p_lpcmdec->p_fifo)->b_has_pts = 0;
}
else
{
{
/* We take the lock, because we are going to read/write the start/end
* indexes of the decoder fifo */
- vlc_mutex_lock (&p_lpcmdec->fifo.data_lock);
+ vlc_mutex_lock (&p_lpcmdec->p_fifo->data_lock);
/* Wait until a `die' order is sent */
while (!p_lpcmdec->b_die) {
/* Trash all received PES packets */
- while (!DECODER_FIFO_ISEMPTY(p_lpcmdec->fifo)) {
- input_NetlistFreePES (p_lpcmdec->p_input, DECODER_FIFO_START(p_lpcmdec->fifo));
- DECODER_FIFO_INCSTART (p_lpcmdec->fifo);
+ while (!DECODER_FIFO_ISEMPTY(*p_lpcmdec->p_fifo)) {
+ p_lpcmdec->p_fifo->pf_delete_pes(p_lpcmdec->p_fifo->p_packets_mgt,
+ DECODER_FIFO_START(*p_lpcmdec->p_fifo));
+ DECODER_FIFO_INCSTART (*p_lpcmdec->p_fifo);
}
/* Waiting for the input thread to put new PES packets in the fifo */
- vlc_cond_wait (&p_lpcmdec->fifo.data_wait, &p_lpcmdec->fifo.data_lock);
+ vlc_cond_wait (&p_lpcmdec->p_fifo->data_wait, &p_lpcmdec->p_fifo->data_lock);
}
/* We can release the lock before leaving */
- vlc_mutex_unlock (&p_lpcmdec->fifo.data_lock);
+ vlc_mutex_unlock (&p_lpcmdec->p_fifo->data_lock);
}
/*****************************************************************************
/*
* Input properties
*/
- decoder_fifo_t fifo; /* stores the PES stream data */
- input_thread_t * p_input;
- ts_packet_t * p_ts;
- int sync_ptr; /* sync ptr from lpcm magic header */
+ decoder_fifo_t * p_fifo; /* stores the PES stream data */
+ data_packet_t * p_data;
+ int sync_ptr; /* sync ptr from lpcm magic header */
+ adec_config_t * p_config;
/*
* Decoder properties
/*****************************************************************************
* Prototypes
*****************************************************************************/
-lpcmdec_thread_t * lpcmdec_CreateThread( input_thread_t * p_input );
-void lpcmdec_DestroyThread( lpcmdec_thread_t * p_lcpmdec );
+vlc_thread_t lpcmdec_CreateThread( adec_config_t * p_config );
+++ /dev/null
-/*****************************************************************************
- * decoder_fifo.c: auxiliaries functions used in decoder_fifo.h
- *****************************************************************************
- * Copyright (C) 1998, 1999, 2000 VideoLAN
- *
- * Authors: Michel Kaempf <maxx@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.
- *****************************************************************************/
-#include "defs.h"
-
-#include <sys/types.h> /* on BSD, uio.h needs types.h */
-#include <sys/uio.h> /* for input.h */
-
-#include "config.h"
-#include "common.h"
-#include "threads.h"
-#include "mtime.h"
-
-#include "debug.h" /* XXX?? temporaire, requis par netlist.h */
-
-#include "input.h"
-#include "input_netlist.h"
-#include "decoder_fifo.h"
-
-void decoder_fifo_next( bit_stream_t * p_bit_stream )
-{
- /* We are looking for the next TS packet that contains real data,
- * and not just a PES header */
- do
- {
- /* We were reading the last TS packet of this PES packet... It's
- * time to jump to the next PES packet */
- if ( p_bit_stream->p_ts->p_next_ts == NULL )
- {
- /* We are going to read/write the start and end indexes of the
- * decoder fifo and to use the fifo's conditional variable,
- * that's why we need to take the lock before */
- vlc_mutex_lock( &p_bit_stream->p_decoder_fifo->data_lock );
-
- /* Is the input thread dying ? */
- if ( p_bit_stream->p_input->b_die )
- {
- vlc_mutex_unlock( &(p_bit_stream->p_decoder_fifo->data_lock) );
- return;
- }
-
- /* We should increase the start index of the decoder fifo, but
- * if we do this now, the input thread could overwrite the
- * pointer to the current PES packet, and we weren't able to
- * give it back to the netlist. That's why we free the PES
- * packet first. */
- input_NetlistFreePES( p_bit_stream->p_input, DECODER_FIFO_START(*p_bit_stream->p_decoder_fifo) );
- DECODER_FIFO_INCSTART( *p_bit_stream->p_decoder_fifo );
-
- while ( DECODER_FIFO_ISEMPTY(*p_bit_stream->p_decoder_fifo) )
- {
- vlc_cond_wait( &p_bit_stream->p_decoder_fifo->data_wait, &p_bit_stream->p_decoder_fifo->data_lock );
- if ( p_bit_stream->p_input->b_die )
- {
- vlc_mutex_unlock( &(p_bit_stream->p_decoder_fifo->data_lock) );
- return;
- }
- }
-
- /* The next byte could be found in the next PES packet */
- p_bit_stream->p_ts = DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->p_first_ts;
-
- /* We can release the fifo's data lock */
- vlc_mutex_unlock( &p_bit_stream->p_decoder_fifo->data_lock );
- }
- /* Perhaps the next TS packet of the current PES packet contains
- * real data (ie its payload's size is greater than 0) */
- else
- {
- p_bit_stream->p_ts = p_bit_stream->p_ts->p_next_ts;
- }
- } while ( p_bit_stream->p_ts->i_payload_start == p_bit_stream->p_ts->i_payload_end );
-
- /* We've found a TS packet which contains interesting data... */
- p_bit_stream->p_byte = p_bit_stream->p_ts->buffer + p_bit_stream->p_ts->i_payload_start;
- p_bit_stream->p_end = p_bit_stream->p_ts->buffer + p_bit_stream->p_ts->i_payload_end;
-}
-
-void PeekNextPacket( bit_stream_t * p_bit_stream )
-{
- WORD_TYPE buffer_left;
- int i_bytes_left; /* FIXME : not portable in a 64bit environment */
-
- /* Put the remaining bytes (not aligned on a word boundary) in a
- * temporary buffer. */
- i_bytes_left = p_bit_stream->p_end - p_bit_stream->p_byte;
- buffer_left = *((WORD_TYPE *)p_bit_stream->p_end - 1);
-
- /* We are looking for the next TS packet that contains real data,
- * and not just a PES header */
- do
- {
- /* We were reading the last TS packet of this PES packet... It's
- * time to jump to the next PES packet */
- if ( p_bit_stream->p_ts->p_next_ts == NULL )
- {
- /* We are going to read/write the start and end indexes of the
- * decoder fifo and to use the fifo's conditional variable,
- * that's why we need to take the lock before */
- vlc_mutex_lock( &p_bit_stream->p_decoder_fifo->data_lock );
-
- /* Is the input thread dying ? */
- if ( p_bit_stream->p_input->b_die )
- {
- vlc_mutex_unlock( &(p_bit_stream->p_decoder_fifo->data_lock) );
- return;
- }
-
- /* We should increase the start index of the decoder fifo, but
- * if we do this now, the input thread could overwrite the
- * pointer to the current PES packet, and we weren't able to
- * give it back to the netlist. That's why we free the PES
- * packet first. */
- input_NetlistFreePES( p_bit_stream->p_input, DECODER_FIFO_START(*p_bit_stream->p_decoder_fifo) );
- DECODER_FIFO_INCSTART( *p_bit_stream->p_decoder_fifo );
-
- while ( DECODER_FIFO_ISEMPTY(*p_bit_stream->p_decoder_fifo) )
- {
- vlc_cond_wait( &p_bit_stream->p_decoder_fifo->data_wait, &p_bit_stream->p_decoder_fifo->data_lock );
- if ( p_bit_stream->p_input->b_die )
- {
- vlc_mutex_unlock( &(p_bit_stream->p_decoder_fifo->data_lock) );
- return;
- }
- }
-
- /* The next byte could be found in the next PES packet */
- p_bit_stream->p_ts = DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->p_first_ts;
-
- /* We can release the fifo's data lock */
- vlc_mutex_unlock( &p_bit_stream->p_decoder_fifo->data_lock );
- }
- /* Perhaps the next TS packet of the current PES packet contains
- * real data (ie its payload's size is greater than 0) */
- else
- {
- p_bit_stream->p_ts = p_bit_stream->p_ts->p_next_ts;
- }
- } while ( p_bit_stream->p_ts->i_payload_start == p_bit_stream->p_ts->i_payload_end );
-
- /* We've found a TS packet which contains interesting data... */
- p_bit_stream->p_byte = p_bit_stream->p_ts->buffer + p_bit_stream->p_ts->i_payload_start;
- p_bit_stream->p_end = p_bit_stream->p_ts->buffer + p_bit_stream->p_ts->i_payload_end;
-
- /* Copy remaining bits of the previous packet */
- *((WORD_TYPE *)p_bit_stream->p_byte - 1) = buffer_left;
- p_bit_stream->p_byte -= i_bytes_left;
-}
#include "intf_msg.h"
#include "debug.h" /* ASSERT */
-#include "input.h"
-#include "input_netlist.h"
-#include "decoder_fifo.h"
+#include "stream_control.h"
+#include "input_ext-dec.h"
#include "video.h"
#include "video_output.h"
/*****************************************************************************
* spudec_CreateThread: create a spu decoder thread
*****************************************************************************/
-spudec_thread_t * spudec_CreateThread( input_thread_t * p_input )
+vlc_thread_t spudec_CreateThread( vdec_config_t * p_config )
{
spudec_thread_t * p_spudec;
if ( (p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) )) == NULL )
{
intf_ErrMsg("spudec error: not enough memory for spudec_CreateThread() to create the new thread\n");
- return( NULL );
+ return( 0 );
}
/*
*/
p_spudec->b_die = 0;
p_spudec->b_error = 0;
-
- /*
- * Initialize the input properties
- */
- /* Initialize the decoder fifo's data lock and conditional variable and set
- * its buffer as empty */
- vlc_mutex_init( &p_spudec->fifo.data_lock );
- vlc_cond_init( &p_spudec->fifo.data_wait );
- p_spudec->fifo.i_start = 0;
- p_spudec->fifo.i_end = 0;
- /* Initialize the bit stream structure */
- p_spudec->bit_stream.p_input = p_input;
- p_spudec->bit_stream.p_decoder_fifo = &p_spudec->fifo;
- p_spudec->bit_stream.fifo.buffer = 0;
- p_spudec->bit_stream.fifo.i_available = 0;
+ p_spudec->p_config = p_config;
+ p_spudec->p_fifo = p_config->decoder_config.p_decoder_fifo;
/* Get the video output informations */
- p_spudec->p_vout = p_input->p_vout;
+ p_spudec->p_vout = p_config->p_vout;
/* Spawn the spu decoder thread */
if ( vlc_thread_create(&p_spudec->thread_id, "spu decoder",
{
intf_ErrMsg("spudec error: can't spawn spu decoder thread\n");
free( p_spudec );
- return( NULL );
+ return( 0 );
}
intf_DbgMsg("spudec debug: spu decoder thread (%p) created\n", p_spudec);
- return( p_spudec );
-}
-
-/*****************************************************************************
- * spudec_DestroyThread: destroy a spu decoder thread
- *****************************************************************************
- * Destroy and terminate thread. This function will return 0 if the thread could
- * be destroyed, and non 0 else. The last case probably means that the thread
- * was still active, and another try may succeed.
- *****************************************************************************/
-void spudec_DestroyThread( spudec_thread_t *p_spudec )
-{
- intf_DbgMsg( "spudec debug: requesting termination of "
- "spu decoder thread %p\n", p_spudec);
-
- /* Ask thread to kill itself */
- p_spudec->b_die = 1;
-
- /* Warn the decoder that we're quitting */
- vlc_mutex_lock( &p_spudec->fifo.data_lock );
- vlc_cond_signal( &p_spudec->fifo.data_wait );
- vlc_mutex_unlock( &p_spudec->fifo.data_lock );
-
- /* Waiting for the decoder thread to exit */
- /* Remove this as soon as the "status" flag is implemented */
- vlc_thread_join( p_spudec->thread_id );
+ return( p_spudec->thread_id );
}
/* following functions are local */
{
intf_DbgMsg("spudec debug: initializing spu decoder thread %p\n", p_spudec);
- /* Our first job is to initialize the bit stream structure with the
- * beginning of the input stream */
- vlc_mutex_lock( &p_spudec->fifo.data_lock );
- while ( DECODER_FIFO_ISEMPTY(p_spudec->fifo) )
- {
- if ( p_spudec->b_die )
- {
- vlc_mutex_unlock( &p_spudec->fifo.data_lock );
- return( 1 );
- }
- vlc_cond_wait( &p_spudec->fifo.data_wait, &p_spudec->fifo.data_lock );
- }
-
- p_spudec->bit_stream.p_ts = DECODER_FIFO_START( p_spudec->fifo )->p_first_ts;
- p_spudec->bit_stream.p_byte = p_spudec->bit_stream.p_ts->buffer + p_spudec->bit_stream.p_ts->i_payload_start;
- p_spudec->bit_stream.p_end = p_spudec->bit_stream.p_ts->buffer + p_spudec->bit_stream.p_ts->i_payload_end;
- vlc_mutex_unlock( &p_spudec->fifo.data_lock );
+ p_spudec->p_config->decoder_config.pf_init_bit_stream( &p_spudec->bit_stream,
+ p_spudec->p_config->decoder_config.p_decoder_fifo );
/* Mark thread as running and return */
intf_DbgMsg( "spudec debug: InitThread(%p) succeeded\n", p_spudec );
unsigned char * p_spu_data;
subpicture_t * p_spu = NULL;
- while( !DECODER_FIFO_ISEMPTY(p_spudec->fifo) )
+ while( !DECODER_FIFO_ISEMPTY(*p_spudec->p_fifo) )
{
/* wait for the next SPU ID.
* XXX: We trash 0xff bytes since they probably come from
i_index = 2;
/* get the useful PES size (real size - 10) */
- i_pes_size = DECODER_FIFO_START(p_spudec->fifo)->i_pes_size - 9;
+ i_pes_size = DECODER_FIFO_START(*p_spudec->p_fifo)->i_pes_size - 9;
i_pes_count = 1;
/* the RLE stuff size */
/* get display time */
p_spu->begin_date = p_spu->end_date
- = DECODER_FIFO_START(p_spudec->fifo)->i_pts;
+ = DECODER_FIFO_START(*p_spudec->p_fifo)->i_pts;
/* getting the RLE part */
while( i_index++ < i_rle_size )
{
/* Unexpected PES packet - trash it */
intf_ErrMsg( "spudec: trying to recover from bad packet\n" );
- vlc_mutex_lock( &p_spudec->fifo.data_lock );
- input_NetlistFreePES( p_spudec->bit_stream.p_input,
- DECODER_FIFO_START(p_spudec->fifo) );
- DECODER_FIFO_INCSTART( p_spudec->fifo );
- vlc_mutex_unlock( &p_spudec->fifo.data_lock );
+ vlc_mutex_lock( &p_spudec->p_fifo->data_lock );
+ p_spudec->p_fifo->pf_delete_pes( p_spudec->p_fifo->p_packets_mgt,
+ DECODER_FIFO_START(*p_spudec->p_fifo) );
+ DECODER_FIFO_INCSTART( *p_spudec->p_fifo );
+ vlc_mutex_unlock( &p_spudec->p_fifo->data_lock );
}
}
{
/* We take the lock, because we are going to read/write the start/end
* indexes of the decoder fifo */
- vlc_mutex_lock( &p_spudec->fifo.data_lock );
+ vlc_mutex_lock( &p_spudec->p_fifo->data_lock );
/* Wait until a `die' order is sent */
while( !p_spudec->b_die )
{
/* Trash all received PES packets */
- while( !DECODER_FIFO_ISEMPTY(p_spudec->fifo) )
+ while( !DECODER_FIFO_ISEMPTY(*p_spudec->p_fifo) )
{
- input_NetlistFreePES( p_spudec->bit_stream.p_input, DECODER_FIFO_START(p_spudec->fifo) );
- DECODER_FIFO_INCSTART( p_spudec->fifo );
+ p_spudec->p_fifo->pf_delete_pes( p_spudec->p_fifo->p_packets_mgt,
+ DECODER_FIFO_START(*p_spudec->p_fifo) );
+ DECODER_FIFO_INCSTART( *p_spudec->p_fifo );
}
/* Waiting for the input thread to put new PES packets in the fifo */
- vlc_cond_wait( &p_spudec->fifo.data_wait, &p_spudec->fifo.data_lock );
+ vlc_cond_wait( &p_spudec->p_fifo->data_wait, &p_spudec->p_fifo->data_lock );
}
/* We can release the lock before leaving */
- vlc_mutex_unlock( &p_spudec->fifo.data_lock );
+ vlc_mutex_unlock( &p_spudec->p_fifo->data_lock );
}
/*****************************************************************************
/*
* Input properties
*/
- decoder_fifo_t fifo; /* stores the PES stream data */
+ decoder_fifo_t * p_fifo; /* stores the PES stream data */
/* The bit stream structure handles the PES stream at the bit level */
bit_stream_t bit_stream;
+ vdec_config_t * p_config;
/*
* Decoder properties
/*****************************************************************************
* Prototypes
*****************************************************************************/
-spudec_thread_t * spudec_CreateThread( input_thread_t * p_input );
-void spudec_DestroyThread( spudec_thread_t * p_spudec );
+vlc_thread_t spudec_CreateThread( vdec_config_t * p_config );
#include "intf_msg.h"
-#include "input.h"
-#include "decoder_fifo.h"
+#include "stream_control.h"
+#include "input_ext-dec.h"
+
#include "video.h"
#include "video_output.h"
#include "intf_msg.h"
-#include "input.h"
-#include "decoder_fifo.h"
+#include "stream_control.h"
+#include "input_ext-dec.h"
+
#include "video.h"
#include "video_output.h"
#include "intf_msg.h"
-#include "input.h"
-#include "decoder_fifo.h"
+#include "stream_control.h"
+#include "input_ext-dec.h"
+
#include "video.h"
#include "video_output.h"
#include "intf_msg.h"
-#include "input.h"
-#include "decoder_fifo.h"
+#include "stream_control.h"
+#include "input_ext-dec.h"
+
#include "video.h"
#include "video_output.h"
#include "intf_msg.h"
-#include "input.h"
-#include "decoder_fifo.h"
+#include "stream_control.h"
+#include "input_ext-dec.h"
+
#include "video.h"
#include "video_output.h"
#include "intf_msg.h"
#include "debug.h" /* XXX?? temporaire, requis par netlist.h */
-#include "input.h"
-#include "input_netlist.h"
-#include "decoder_fifo.h"
+#include "stream_control.h"
+#include "input_ext-dec.h"
+
#include "video.h"
#include "video_output.h"
#include "intf_msg.h"
#include "debug.h" /* XXX?? temporaire, requis par netlist.h */
-#include "input.h"
-#include "input_netlist.h"
-#include "decoder_fifo.h"
+#include "stream_control.h"
+#include "input_ext-dec.h"
+
#include "video.h"
#include "video_output.h"
/*
* Local prototypes
*/
-//static int CheckConfiguration ( video_cfg_t *p_cfg );
static int InitThread ( vpar_thread_t *p_vpar );
static void RunThread ( vpar_thread_t *p_vpar );
static void ErrorThread ( vpar_thread_t *p_vpar );
* Following configuration properties are used:
* XXX??
*****************************************************************************/
-#include "main.h"
-#include "interface.h"
-extern main_t * p_main;
-
-vpar_thread_t * vpar_CreateThread( /* video_cfg_t *p_cfg, */ input_thread_t *p_input /*,
- vout_thread_t *p_vout, int *pi_status */ )
+vlc_thread_t vpar_CreateThread( vdec_config_t * p_config )
{
vpar_thread_t * p_vpar;
{
intf_ErrMsg( "vpar error: not enough memory "
"for vpar_CreateThread() to create the new thread\n");
- return( NULL );
+ return( 0 );
}
/*
*/
p_vpar->b_die = 0;
p_vpar->b_error = 0;
+ p_vpar->p_fifo = p_config->decoder_config.p_decoder_fifo;
+ p_vpar->p_config = p_config;
- /*
- * Initialize the input properties
- */
- /* Initialize the decoder fifo's data lock and conditional variable
- * and set its buffer as empty */
- vlc_mutex_init( &p_vpar->fifo.data_lock );
- vlc_cond_init( &p_vpar->fifo.data_wait );
- p_vpar->fifo.i_start = 0;
- p_vpar->fifo.i_end = 0;
- /* Initialize the bit stream structure */
- p_vpar->bit_stream.p_input = p_input;
- p_vpar->bit_stream.p_decoder_fifo = &p_vpar->fifo;
- p_vpar->bit_stream.fifo.buffer = 0;
- p_vpar->bit_stream.fifo.i_available = 0;
-
- /* FIXME !!!!?? */
- p_vpar->p_vout = p_main->p_intf->p_vout;
+ p_vpar->p_vout = p_config->p_vout;
/* Spawn the video parser thread */
if ( vlc_thread_create( &p_vpar->thread_id, "video parser",
{
intf_ErrMsg("vpar error: can't spawn video parser thread\n");
free( p_vpar );
- return( NULL );
+ return( 0 );
}
intf_DbgMsg("vpar debug: video parser thread (%p) created\n", p_vpar);
- return( p_vpar );
-}
-
-/*****************************************************************************
- * vpar_DestroyThread: destroy a generic parser thread
- *****************************************************************************
- * Destroy a terminated thread. This function will return 0 if the thread could
- * be destroyed, and non 0 else. The last case probably means that the thread
- * was still active, and another try may succeed.
- *****************************************************************************/
-void vpar_DestroyThread( vpar_thread_t *p_vpar /*, int *pi_status */ )
-{
- intf_DbgMsg( "vpar debug: requesting termination of "
- "video parser thread %p\n", p_vpar);
-
- /* Ask thread to kill itself */
- p_vpar->b_die = 1;
- /* Make sure the parser thread leaves the GetByte() function */
- vlc_mutex_lock( &(p_vpar->fifo.data_lock) );
- vlc_cond_signal( &(p_vpar->fifo.data_wait) );
- vlc_mutex_unlock( &(p_vpar->fifo.data_lock) );
-
- /* Waiting for the parser thread to exit */
- /* Remove this as soon as the "status" flag is implemented */
- vlc_thread_join( p_vpar->thread_id );
+ return( p_vpar->thread_id );
}
/* following functions are local */
-/*****************************************************************************
- * CheckConfiguration: check vpar_CreateThread() configuration
- *****************************************************************************
- * Set default parameters where required. In DEBUG mode, check if configuration
- * is valid.
- *****************************************************************************/
-#if 0
-static int CheckConfiguration( video_cfg_t *p_cfg )
-{
- /* XXX?? */
-
- return( 0 );
-}
-#endif
-
/*****************************************************************************
* InitThread: initialize vpar output thread
*****************************************************************************
intf_DbgMsg("vpar debug: initializing video parser thread %p\n", p_vpar);
- /* Our first job is to initialize the bit stream structure with the
- * beginning of the input stream */
- vlc_mutex_lock( &p_vpar->fifo.data_lock );
- while ( DECODER_FIFO_ISEMPTY(p_vpar->fifo) )
- {
- if ( p_vpar->b_die )
- {
- vlc_mutex_unlock( &p_vpar->fifo.data_lock );
- return( 1 );
- }
- vlc_cond_wait( &p_vpar->fifo.data_wait, &p_vpar->fifo.data_lock );
- }
- p_vpar->bit_stream.p_ts = DECODER_FIFO_START( p_vpar->fifo )->p_first_ts;
- p_vpar->bit_stream.p_byte = p_vpar->bit_stream.p_ts->buffer
- + p_vpar->bit_stream.p_ts->i_payload_start;
- p_vpar->bit_stream.p_end = p_vpar->bit_stream.p_ts->buffer
- + p_vpar->bit_stream.p_ts->i_payload_end;
- vlc_mutex_unlock( &p_vpar->fifo.data_lock );
+ p_vpar->p_config->decoder_config.pf_init_bit_stream( &p_vpar->bit_stream,
+ p_vpar->p_config->decoder_config.p_decoder_fifo );
/* Initialize parsing data */
p_vpar->sequence.p_forward = NULL;
* Main loop - it is not executed if an error occured during
* initialization
*/
- while( (!p_vpar->b_die) && (!p_vpar->b_error) )
+ while( (!p_vpar->p_fifo->b_die) && (!p_vpar->b_error) )
{
/* Find the next sequence header in the stream */
p_vpar->b_error = vpar_NextSequenceHeader( p_vpar );
- while( (!p_vpar->b_die) && (!p_vpar->b_error) )
+ while( (!p_vpar->p_fifo->b_die) && (!p_vpar->b_error) )
{
#ifdef STATS
p_vpar->c_loops++;
{
/* We take the lock, because we are going to read/write the start/end
* indexes of the decoder fifo */
- vlc_mutex_lock( &p_vpar->fifo.data_lock );
+ vlc_mutex_lock( &p_vpar->p_fifo->data_lock );
/* Wait until a `die' order is sent */
- while( !p_vpar->b_die )
+ while( !p_vpar->p_fifo->b_die )
{
/* Trash all received PES packets */
- while( !DECODER_FIFO_ISEMPTY(p_vpar->fifo) )
+ while( !DECODER_FIFO_ISEMPTY(*p_vpar->p_fifo) )
{
- input_NetlistFreePES( p_vpar->bit_stream.p_input,
- DECODER_FIFO_START(p_vpar->fifo) );
- DECODER_FIFO_INCSTART( p_vpar->fifo );
+ p_vpar->p_fifo->pf_delete_pes( p_vpar->p_fifo->p_packets_mgt,
+ DECODER_FIFO_START(*p_vpar->p_fifo) );
+ DECODER_FIFO_INCSTART( *p_vpar->p_fifo );
}
/* Waiting for the input thread to put new PES packets in the fifo */
- vlc_cond_wait( &p_vpar->fifo.data_wait, &p_vpar->fifo.data_lock );
+ vlc_cond_wait( &p_vpar->p_fifo->data_wait, &p_vpar->p_fifo->data_lock );
}
/* We can release the lock before leaving */
- vlc_mutex_unlock( &p_vpar->fifo.data_lock );
+ vlc_mutex_unlock( &p_vpar->p_fifo->data_lock );
}
/*****************************************************************************
#include "intf_msg.h"
#include "debug.h" /* XXX?? temporaire, requis par netlist.h */
-#include "input.h"
-#include "input_netlist.h"
-#include "decoder_fifo.h"
+#include "stream_control.h"
+#include "input_ext-dec.h"
+
#include "video.h"
#include "video_output.h"
i_coef = 0;
b_sign = 0;
- for( i_parse = 0; !p_vpar->b_die; i_parse++ )
+ for( i_parse = 0; !p_vpar->p_fifo->b_die; i_parse++ )
{
i_code = ShowBits( &p_vpar->bit_stream, 16 );
if( i_code >= 16384 )
i_coef = 0;
b_sign = 0;
- for( i_parse = 1; !p_vpar->b_die/*i_parse < 64*/; i_parse++ )
+ for( i_parse = 1; !p_vpar->p_fifo->b_die/*i_parse < 64*/; i_parse++ )
{
i_code = ShowBits( &p_vpar->bit_stream, 16 );
/* We use 2 main tables for the coefficients */
i_nc = 0;
i_coef = 0;
- for( i_parse = 0; !p_vpar->b_die; i_parse++ )
+ for( i_parse = 0; !p_vpar->p_fifo->b_die; i_parse++ )
{
i_code = ShowBits( &p_vpar->bit_stream, 16 );
if( i_code >= 16384 )
i_coef = 0;
b_vlc_intra = p_vpar->picture.b_intra_vlc_format;
- for( i_parse = 1; !p_vpar->b_die/*i_parse < 64*/; i_parse++ )
+ for( i_parse = 1; !p_vpar->p_fifo->b_die/*i_parse < 64*/; i_parse++ )
{
i_code = ShowBits( &p_vpar->bit_stream, 16 );
/* We use 2 main tables for the coefficients */
return;
}
}
- while( ShowBits( &p_vpar->bit_stream, 23 ) && !p_vpar->b_die );
- NextStartCode( p_vpar );
+ while( ShowBits( &p_vpar->bit_stream, 23 )
+ && !p_vpar->p_fifo->b_die );
+ NextStartCode( &p_vpar->bit_stream );
}
/*****************************************************************************
int i_mb_address = 0;
u32 i_dummy;
- NextStartCode( p_vpar );
+ NextStartCode( &p_vpar->bit_stream );
while( ((p_vpar->picture.i_coding_type != I_CODING_TYPE
&& p_vpar->picture.i_coding_type != D_CODING_TYPE)
|| !p_vpar->picture.b_error)
&& i_mb_address < (p_vpar->sequence.i_mb_size
>> (p_vpar->picture.i_structure != FRAME_STRUCTURE))
- && !p_vpar->b_die )
+ && !p_vpar->p_fifo->b_die )
{
if( ((i_dummy = ShowBits( &p_vpar->bit_stream, 32 ))
< SLICE_START_CODE_MIN) ||
#include "intf_msg.h"
-#include "input.h"
-#include "decoder_fifo.h"
+#include "stream_control.h"
+#include "input_ext-dec.h"
+
#include "video.h"
#include "video_output.h"
/*
* Local prototypes
*/
-static __inline__ void NextStartCode( vpar_thread_t * p_vpar );
+static __inline__ void NextStartCode( bit_stream_t * );
static void SequenceHeader( vpar_thread_t * p_vpar );
static void GroupHeader( vpar_thread_t * p_vpar );
static void PictureHeader( vpar_thread_t * p_vpar );
*****************************************************************************/
int vpar_NextSequenceHeader( vpar_thread_t * p_vpar )
{
- while( !p_vpar->b_die )
+ while( !p_vpar->p_fifo->b_die )
{
- NextStartCode( p_vpar );
+ NextStartCode( &p_vpar->bit_stream );
if( ShowBits( &p_vpar->bit_stream, 32 ) == SEQUENCE_HEADER_CODE )
{
return 0;
*****************************************************************************/
int vpar_ParseHeader( vpar_thread_t * p_vpar )
{
- while( !p_vpar->b_die )
+ while( !p_vpar->p_fifo->b_die )
{
- NextStartCode( p_vpar );
+ NextStartCode( &p_vpar->bit_stream );
switch( GetBits32( &p_vpar->bit_stream ) )
{
case SEQUENCE_HEADER_CODE:
/*
* Sequence Extension
*/
- NextStartCode( p_vpar );
+ NextStartCode( &p_vpar->bit_stream );
if( ShowBits( &p_vpar->bit_stream, 32 ) == EXTENSION_START_CODE )
{
int i_dummy;
/*
* Picture Coding Extension
*/
- NextStartCode( p_vpar );
+ NextStartCode( &p_vpar->bit_stream );
if( ShowBits( &p_vpar->bit_stream, 32 ) == EXTENSION_START_CODE )
{
/* Parse picture_coding_extension */
== NULL )
{
intf_DbgMsg("vpar debug: allocation error in vout_CreatePicture, delaying\n");
- if( p_vpar->b_die || p_vpar->b_error )
+ if( p_vpar->p_fifo->b_die || p_vpar->b_error )
{
return;
}
vpar_PictureData( p_vpar, i_mb_base );
- if( p_vpar->b_die || p_vpar->b_error )
+ if( p_vpar->p_fifo->b_die || p_vpar->b_error )
{
return;
}
*****************************************************************************/
static void ExtensionAndUserData( vpar_thread_t * p_vpar )
{
- while( !p_vpar->b_die )
+ while( !p_vpar->p_fifo->b_die )
{
- NextStartCode( p_vpar );
+ NextStartCode( &p_vpar->bit_stream );
switch( ShowBits( &p_vpar->bit_stream, 32 ) )
{
case EXTENSION_START_CODE:
#include "intf_msg.h"
-#include "input.h"
-#include "decoder_fifo.h"
+#include "stream_control.h"
+#include "input_ext-dec.h"
+
#include "video.h"
#include "video_output.h"
memset( p_vpar->synchro.p_tau, 0, 4 * sizeof(mtime_t) );
memset( p_vpar->synchro.pi_meaningful, 0, 4 * sizeof(unsigned int) );
p_vpar->synchro.b_dropped_last = 0;
- p_vpar->synchro.current_pts = mdate() + INPUT_PTS_DELAY;
+ p_vpar->synchro.current_pts = mdate() + DEFAULT_PTS_DELAY;
p_vpar->synchro.backward_pts = 0;
}