Commit 50118171 authored by Christophe Massiot's avatar Christophe Massiot

* Big cleanup of the PS input plugin ;

* Fixed a bug in AC3 initialization ;
* PS streams are now pre-parsed (this can take a while) if possible ;

./configure is required after this update.
parent d719269b
...@@ -183,6 +183,9 @@ ...@@ -183,6 +183,9 @@
/* Maximum number of selected ES in an input thread */ /* Maximum number of selected ES in an input thread */
#define INPUT_MAX_SELECTED_ES 10 #define INPUT_MAX_SELECTED_ES 10
/* Maximum size of a data packet (128 kB) */
#define INPUT_MAX_PACKET_SIZE 131072
/* Maximum number of TS packets in the client at any time /* Maximum number of TS packets in the client at any time
* INPUT_MAX_TS + 1 must be a power of 2, to optimize the %(INPUT_MAX_TS+1) * INPUT_MAX_TS + 1 must be a power of 2, to optimize the %(INPUT_MAX_TS+1)
* operation with a &INPUT_MAX_TS in the case of a fifo netlist. * operation with a &INPUT_MAX_TS in the case of a fifo netlist.
......
/* Structures exported to the interface */ /*****************************************************************************
* input_ext-intf.h: structures of the input exported to the interface
* This header provides structures to read the stream descriptors and
* control the pace of reading.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input_ext-intf.h,v 1.4 2000/12/20 16:04:31 massiot Exp $
*
* 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.
*****************************************************************************/
/* /*
* Communication input -> interface * Communication input -> interface
...@@ -54,8 +77,10 @@ typedef struct es_descriptor_s ...@@ -54,8 +77,10 @@ typedef struct es_descriptor_s
#define MPEG1_AUDIO_ES 0x03 #define MPEG1_AUDIO_ES 0x03
#define MPEG2_AUDIO_ES 0x04 #define MPEG2_AUDIO_ES 0x04
#define AC3_AUDIO_ES 0x81 #define AC3_AUDIO_ES 0x81
#define DVD_SPU_ES 0x82 /* 0x82 might violate the norm */ /* These ones might violate the norm : */
#define DVD_SPU_ES 0x82
#define LPCM_AUDIO_ES 0x83 #define LPCM_AUDIO_ES 0x83
#define UNKNOWN_ES 0xFF
/***************************************************************************** /*****************************************************************************
* pgrm_descriptor_t * pgrm_descriptor_t
......
...@@ -126,6 +126,17 @@ static int InitThread (ac3dec_thread_t * p_ac3dec) ...@@ -126,6 +126,17 @@ static int InitThread (ac3dec_thread_t * p_ac3dec)
intf_DbgMsg ("ac3dec debug: initializing ac3 decoder thread %p\n", p_ac3dec); intf_DbgMsg ("ac3dec debug: initializing ac3 decoder thread %p\n", p_ac3dec);
/* Get the first data packet. */
vlc_mutex_lock( &p_ac3dec->p_fifo->data_lock );
while ( DECODER_FIFO_ISEMPTY( *p_ac3dec->p_fifo ) )
{
if ( p_ac3dec->p_fifo->b_die )
{
vlc_mutex_unlock( &p_ac3dec->p_fifo->data_lock );
return -1;
}
vlc_cond_wait( &p_ac3dec->p_fifo->data_wait, &p_ac3dec->p_fifo->data_lock );
}
p_ac3dec->p_data = DECODER_FIFO_START(*p_ac3dec->p_fifo)->p_first; p_ac3dec->p_data = DECODER_FIFO_START(*p_ac3dec->p_fifo)->p_first;
byte_stream = ac3_byte_stream (&p_ac3dec->ac3_decoder); byte_stream = ac3_byte_stream (&p_ac3dec->ac3_decoder);
byte_stream->p_byte = p_ac3dec->p_data->p_payload_start; byte_stream->p_byte = p_ac3dec->p_data->p_payload_start;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* decoders. * decoders.
***************************************************************************** *****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN * Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: input.c,v 1.59 2000/12/19 19:08:51 massiot Exp $ * $Id: input.c,v 1.60 2000/12/20 16:04:31 massiot Exp $
* *
* Authors: * Authors:
* *
...@@ -177,6 +177,7 @@ void input_DestroyThread( input_thread_t *p_input, int *pi_status ) ...@@ -177,6 +177,7 @@ void input_DestroyThread( input_thread_t *p_input, int *pi_status )
static void RunThread( input_thread_t *p_input ) static void RunThread( input_thread_t *p_input )
{ {
data_packet_t * pp_packets[INPUT_READ_ONCE]; data_packet_t * pp_packets[INPUT_READ_ONCE];
int i_error, i;
InitThread( p_input ); InitThread( p_input );
...@@ -195,15 +196,23 @@ static void RunThread( input_thread_t *p_input ) ...@@ -195,15 +196,23 @@ static void RunThread( input_thread_t *p_input )
} }
vlc_mutex_unlock( &p_input->stream.control.control_lock ); vlc_mutex_unlock( &p_input->stream.control.control_lock );
p_input->p_plugin->pf_read( p_input, pp_packets ); i_error = p_input->p_plugin->pf_read( p_input, pp_packets );
if( !p_input->b_error )
{
int i;
/* Demultiplex read packets. */
for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ ) for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
{ {
p_input->p_plugin->pf_demux( p_input, pp_packets[i] ); p_input->p_plugin->pf_demux( p_input, pp_packets[i] );
} }
if( i_error )
{
if( i_error == 1 )
{
/* End of file */
intf_WarnMsg( 1, "End of file reached" );
/* FIXME: don't treat that as an error */
}
p_input->b_error = 1;
} }
} }
......
/* Communication plugin -> input */ /*****************************************************************************
* input.h: structures of the input not exported to other modules
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input.h,v 1.4 2000/12/20 16:04:31 massiot Exp $
*
* 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.
*****************************************************************************/
/*
* Communication plugin -> input
*/
/* FIXME: you've gotta move this move this, you've gotta move this move this */
#define INPUT_READ_ONCE 7 /* We live in a world dominated by Ethernet. * #define INPUT_READ_ONCE 7 /* We live in a world dominated by Ethernet. *
* Ethernet MTU is 1500 bytes, so in a UDP * * Ethernet MTU is 1500 bytes, so in a UDP *
* packet we can put : 1500/188 = 7 TS * * packet we can put : 1500/188 = 7 TS *
...@@ -22,7 +48,7 @@ typedef struct input_capabilities_s ...@@ -22,7 +48,7 @@ typedef struct input_capabilities_s
void (* pf_end)( struct input_thread_s * ); void (* pf_end)( struct input_thread_s * );
/* Read & Demultiplex */ /* Read & Demultiplex */
void (* pf_read)( struct input_thread_s *, int (* pf_read)( struct input_thread_s *,
struct data_packet_s * pp_packets[INPUT_READ_ONCE] ); struct data_packet_s * pp_packets[INPUT_READ_ONCE] );
void (* pf_demux)( struct input_thread_s *, void (* pf_demux)( struct input_thread_s *,
struct data_packet_s * ); struct data_packet_s * );
...@@ -54,6 +80,7 @@ void input_InitStream( struct input_thread_s *, size_t ); ...@@ -54,6 +80,7 @@ void input_InitStream( struct input_thread_s *, size_t );
struct pgrm_descriptor_s * input_AddProgram( struct input_thread_s *, struct pgrm_descriptor_s * input_AddProgram( struct input_thread_s *,
u16, size_t ); u16, size_t );
void input_DelProgram( struct input_thread_s *, u16 ); void input_DelProgram( struct input_thread_s *, u16 );
void input_DumpStream( struct input_thread_s * );
struct es_descriptor_s * input_AddES( struct input_thread_s *, struct es_descriptor_s * input_AddES( struct input_thread_s *,
struct pgrm_descriptor_s *, u16, struct pgrm_descriptor_s *, u16,
size_t ); size_t );
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* input_programs.c: es_descriptor_t, pgrm_descriptor_t management * input_programs.c: es_descriptor_t, pgrm_descriptor_t management
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* $Id: input_programs.c,v 1.4 2000/12/19 19:08:51 massiot Exp $ * $Id: input_programs.c,v 1.5 2000/12/20 16:04:31 massiot Exp $
* *
* Authors: * Authors:
* *
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
*****************************************************************************/ *****************************************************************************/
void input_InitStream( input_thread_t * p_input, size_t i_data_len ) void input_InitStream( input_thread_t * p_input, size_t i_data_len )
{ {
p_input->stream.i_stream_id = 0;
p_input->stream.i_pgrm_number = 0; p_input->stream.i_pgrm_number = 0;
p_input->stream.pp_programs = NULL; p_input->stream.pp_programs = NULL;
...@@ -283,6 +284,44 @@ void input_DelES( input_thread_t * p_input, u16 i_id ) ...@@ -283,6 +284,44 @@ void input_DelES( input_thread_t * p_input, u16 i_id )
} }
} }
#ifdef STATS
/*****************************************************************************
* input_DumpStream: dumps the contents of a stream descriptor
*****************************************************************************/
void input_DumpStream( input_thread_t * p_input )
{
int i, j;
#define S p_input->stream
intf_Msg( "input info: Dumping stream ID 0x%x\n", S.i_stream_id );
if( S.b_seekable )
intf_Msg( "input info: seekable stream, position: %d/%d\n",
S.i_tell, S.i_size );
else
intf_Msg( "input info: %s\n", S.b_pace_control ? "pace controlled" :
"pace un-controlled" );
#undef S
for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
{
#define P p_input->stream.pp_programs[i]
intf_Msg( "input info: Dumping program 0x%x, version %d (%s)\n",
P->i_number, P->i_version,
P->b_is_ok ? "complete" : "partial" );
if( P->i_synchro_state == SYNCHRO_OK )
intf_Msg( "input info: synchro absolute delta : %lld (jitter : %lld)\n",
P->delta_absolute, P->delta_cr );
#undef P
for( j = 0; j < p_input->stream.pp_programs[i]->i_es_number; j++ )
{
#define ES p_input->stream.pp_programs[i]->pp_es[j]
intf_Msg( "input info: ES 0x%x, stream 0x%x, type 0x%x, %s\n",
ES->i_id, ES->i_stream_id, ES->i_type,
ES->p_decoder_fifo != NULL ? "selected" : "not selected");
#undef ES
}
}
}
#endif
/***************************************************************************** /*****************************************************************************
* InitDecConfig: initializes a decoder_config_t * InitDecConfig: initializes a decoder_config_t
*****************************************************************************/ *****************************************************************************/
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* input_ps.c: PS demux and packet management * input_ps.c: PS demux and packet management
***************************************************************************** *****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN * Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: input_ps.c,v 1.7 2000/12/20 16:04:31 massiot Exp $
* *
* Authors: * Authors:
* *
...@@ -52,7 +53,7 @@ ...@@ -52,7 +53,7 @@
* Local prototypes * Local prototypes
*****************************************************************************/ *****************************************************************************/
static int PSProbe ( struct input_thread_s * ); static int PSProbe ( struct input_thread_s * );
static void PSRead ( struct input_thread_s *, static int PSRead ( struct input_thread_s *,
data_packet_t * p_packets[INPUT_READ_ONCE] ); data_packet_t * p_packets[INPUT_READ_ONCE] );
static void PSInit ( struct input_thread_s * ); static void PSInit ( struct input_thread_s * );
static void PSEnd ( struct input_thread_s * ); static void PSEnd ( struct input_thread_s * );
...@@ -100,10 +101,49 @@ static void PSInit( input_thread_t * p_input ) ...@@ -100,10 +101,49 @@ static void PSInit( input_thread_t * p_input )
} }
fseek( p_method->stream, 0, SEEK_SET ); fseek( p_method->stream, 0, SEEK_SET );
/* Pre-parse the stream to gather stream_descriptor_t. */
input_InitStream( p_input, 0 ); input_InitStream( p_input, 0 );
input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) ); input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
if( p_input->stream.b_seekable )
{
/* Pre-parse the stream to gather stream_descriptor_t. */
p_input->stream.pp_programs[0]->b_is_ok = 0;
/* FIXME: don't read all stream (it can be long !) */
while( !p_input->b_die && !p_input->b_error )
{
int i_result, i;
data_packet_t * pp_packets[INPUT_READ_ONCE];
i_result = PSRead( p_input, pp_packets );
if( i_result == 1 ) break;
if( i_result == -1 )
{
p_input->b_error = 1;
break;
}
for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
{
/* FIXME: use i_p_config_t */
input_ParsePS( p_input, pp_packets[i] );
}
}
fseek( p_method->stream, 0, SEEK_SET );
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.pp_programs[0]->b_is_ok = 1;
p_input->stream.i_tell = 0;
#ifdef STATS
input_DumpStream( p_input );
#endif
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
else
{
/* The programs will be added when we read them. */
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.pp_programs[0]->b_is_ok = 0;
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
} }
/***************************************************************************** /*****************************************************************************
...@@ -115,62 +155,104 @@ static void PSEnd( input_thread_t * p_input ) ...@@ -115,62 +155,104 @@ static void PSEnd( input_thread_t * p_input )
free( p_input->p_method_data ); free( p_input->p_method_data );
} }
/*****************************************************************************
* SafeRead: reads a chunk of stream and correctly detects errors
*****************************************************************************/
static __inline__ int SafeRead( input_thread_t * p_input, byte_t * p_buffer,
size_t i_len )
{
thread_ps_data_t * p_method;
int i_error;
p_method = (thread_ps_data_t *)p_input->p_method_data;
while( fread( p_buffer, i_len, 1, p_method->stream ) != 1 )
{
if( feof( p_method->stream ) )
{
return( 1 );
}
if( (i_error = ferror( p_method->stream )) )
{
intf_ErrMsg( "Read failed (%s)", strerror(i_error) );
return( -1 );
}
}
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.i_tell += i_len;
vlc_mutex_unlock( &p_input->stream.stream_lock );
return( 0 );
}
/***************************************************************************** /*****************************************************************************
* PSRead: reads a data packet * PSRead: reads a data packet
*****************************************************************************
* Returns -1 in case of error, 0 if everything went well, and 1 in case of
* EOF.
*****************************************************************************/ *****************************************************************************/
/* FIXME: read INPUT_READ_ONCE packet at once */ static int PSRead( input_thread_t * p_input,
static void PSRead( input_thread_t * p_input, data_packet_t * pp_packets[INPUT_READ_ONCE] )
data_packet_t * p_packets[INPUT_READ_ONCE] )
{ {
byte_t p_header[6]; byte_t p_header[6];
data_packet_t * p_data; data_packet_t * p_data;
int i_packet_size; size_t i_packet_size;
int i_packet, i_error;
thread_ps_data_t * p_method; thread_ps_data_t * p_method;
p_method = (thread_ps_data_t *)p_input->p_method_data; p_method = (thread_ps_data_t *)p_input->p_method_data;
while( fread( p_header, 6, 1, p_method->stream ) != 1 ) memset( pp_packets, 0, INPUT_READ_ONCE * sizeof(data_packet_t *) );
for( i_packet = 0; i_packet < INPUT_READ_ONCE; i_packet++ )
{ {
int i_error; /* Read what we believe to be a packet header. */
if( (i_error = ferror( p_method->stream )) ) if( (i_error = SafeRead( p_input, p_header, 6 )) )
{ {
intf_ErrMsg( "Read 1 failed (%s)", strerror(i_error) ); return( i_error );
p_input->b_error = 1;
return;
} }
if( feof( p_method->stream ) ) if( (U32_AT(p_header) & 0xFFFFFF00) != 0x100L )
{ {
intf_ErrMsg( "EOF reached" ); /* This is not the startcode of a packet. Read the stream
p_input->b_error = 1; * until we find one. */
return; u32 i_startcode = U32_AT(p_header);
} int i_dummy;
if( i_startcode )
{
/* It is common for MPEG-1 streams to pad with zeros
* (although it is forbidden by the recommendation), so
* don't bother everybody in this case. */
intf_WarnMsg( 1, "Garbage at input (%x)\n", i_startcode );
} }
if( (U32_AT(p_header) & 0xFFFFFF00) != 0x100L ) while( (i_startcode & 0xFFFFFF00) != 0x100L )
{ {
u32 i_buffer = U32_AT(p_header); i_startcode <<= 8;
intf_WarnMsg( 1, "Garbage at input (%x)\n", i_buffer ); if( (i_dummy = getc( p_method->stream )) != EOF )
while( (i_buffer & 0xFFFFFF00) != 0x100L )
{ {
i_buffer <<= 8; i_startcode |= i_dummy;
i_buffer |= getc( p_method->stream ); }
if( feof(p_method->stream) || ferror(p_method->stream) ) else
{ {
p_input->b_error = 1; return( 1 );
return;
} }
} }
*(u32 *)p_header = U32_AT(&i_buffer); /* Packet found. */
fread( p_header + 4, 2, 1, p_method->stream ); *(u32 *)p_header = U32_AT(&i_startcode);
if( (i_error = SafeRead( p_input, p_header + 4, 2 )) )
{
return( i_error );
}
} }
if( U32_AT(p_header) != 0x1BA ) if( U32_AT(p_header) != 0x1BA )
{ {
/* That's the case for all packets, except pack header. */
i_packet_size = U16_AT(&p_header[4]); i_packet_size = U16_AT(&p_header[4]);
} }
else else
{ {
/* Pack header. */
if( (p_header[4] & 0xC0) == 0x40 ) if( (p_header[4] & 0xC0) == 0x40 )
{ {
/* MPEG-2 */ /* MPEG-2 */
...@@ -184,57 +266,47 @@ static void PSRead( input_thread_t * p_input, ...@@ -184,57 +266,47 @@ static void PSRead( input_thread_t * p_input,
else else
{ {
intf_ErrMsg( "Unable to determine stream type" ); intf_ErrMsg( "Unable to determine stream type" );
p_input->b_error = 1; return( -1 );
return;
} }
} }
/* Fetch a packet of the appropriate size. */
if( (p_data = NewPacket( p_input, i_packet_size + 6 )) == NULL ) if( (p_data = NewPacket( p_input, i_packet_size + 6 )) == NULL )
{ {
p_input->b_error = 1;
intf_ErrMsg( "Out of memory" ); intf_ErrMsg( "Out of memory" );
return; return( -1 );
} }
/* Copy the header we already read. */
memcpy( p_data->p_buffer, p_header, 6 ); memcpy( p_data->p_buffer, p_header, 6 );
/* FIXME: catch EINTR ! */ /* Read the remaining of the packet. */
while( fread( p_data->p_buffer + 6, i_packet_size, if( (i_error =
1, p_method->stream ) != 1 ) SafeRead( p_input, p_data->p_buffer + 6, i_packet_size )) )
{ {
int i_error; return( 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;
}
} }
/* In MPEG-2 pack headers we still have to read stuffing bytes. */
if( U32_AT(p_header) == 0x1BA ) if( U32_AT(p_header) == 0x1BA )
{ {
if( i_packet_size == 8 ) if( i_packet_size == 8 && (p_data->p_buffer[13] & 0x7) != 0 )
{ {
/* MPEG-2 stuffing bytes */ /* MPEG-2 stuffing bytes */
byte_t p_garbage[8]; byte_t p_garbage[8];
if( (p_data->p_buffer[13] & 0x7) != 0 ) if( (i_error = SafeRead( p_input, p_garbage,
p_data->p_buffer[13] & 0x7)) )
{ {
/* FIXME: catch EINTR ! */ return( i_error );
fread( p_garbage, p_garbage[0] & 0x7, 1,
p_method->stream );
} }
} }
} }
memset( p_packets, 0, sizeof(p_packets) ); /* Give the packet to the other input stages. */
p_packets[0] = p_data; pp_packets[i_packet] = p_data;
}
return( 0 );
} }
...@@ -250,6 +322,13 @@ static struct data_packet_s * NewPacket( void * p_garbage, ...@@ -250,6 +322,13 @@ static struct data_packet_s * NewPacket( void * p_garbage,
{ {
data_packet_t * p_data; data_packet_t * p_data;
/* Safety check */
if( i_size > INPUT_MAX_PACKET_SIZE )
{
intf_ErrMsg( "Packet too big (%d)", i_size );
return NULL;
}
if( (p_data = (data_packet_t *)malloc( sizeof(data_packet_t) )) == NULL ) if( (p_data = (data_packet_t *)malloc( sizeof(data_packet_t) )) == NULL )
{ {
intf_DbgMsg( "Out of memory" ); intf_DbgMsg( "Out of memory" );
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* mpeg_system.c: TS, PS and PES management * mpeg_system.c: TS, PS and PES management
***************************************************************************** *****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN * Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: mpeg_system.c,v 1.9 2000/12/19 19:08:51 massiot Exp $ * $Id: mpeg_system.c,v 1.10 2000/12/20 16:04:31 massiot Exp $
* *
* Authors: * Authors:
* *
...@@ -749,75 +749,16 @@ static void DecodePSM( input_thread_t * p_input, data_packet_t * p_data ) ...@@ -749,75 +749,16 @@ static void DecodePSM( input_thread_t * p_input, data_packet_t * p_data )
} }
/***************************************************************************** /*****************************************************************************
* input_DemuxPS: first step of demultiplexing: the PS header * input_ParsePS: read the PS header
*****************************************************************************/ *****************************************************************************/
void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data ) es_descriptor_t * input_ParsePS( input_thread_t * p_input,
data_packet_t * p_data )
{ {
u32 i_code; u32 i_code;
boolean_t b_trash = 0;
es_descriptor_t * p_es = NULL; es_descriptor_t * p_es = NULL;
i_code = U32_AT( p_data->p_buffer ); i_code = U32_AT( p_data->p_buffer );
if( i_code >= 0x1B9 && i_code <= 0x1BC ) if( i_code > 0x1BC ) /* ES start code */
{
switch( i_code )
{
case 0x1BA: /* PACK_START_CODE */
{
/* Convert the SCR in microseconds. */
mtime_t scr_time;
if( (p_data->p_buffer[4] & 0xC0) == 0x40 )
{
/* MPEG-2 */
scr_time =
(( ((mtime_t)(p_data->p_buffer[4] & 0x38) << 27) |
((mtime_t)(U32_AT(p_data->p_buffer + 4) & 0x03FFF800)
<< 4) |
((mtime_t)(U32_AT(p_data->p_buffer + 6) & 0x03FFF800)
>> 11)
) * 300) / 27;
}
else
{
/* MPEG-1 SCR is like PTS */
scr_time =
(( ((mtime_t)(p_data->p_buffer[4] & 0x0E) << 29) |
(((mtime_t)U16_AT(p_data->p_buffer + 5) << 14)
- (1 << 14)) |
((mtime_t)U16_AT(p_data->p_buffer + 7) >> 1)
) * 300) / 27;
}
/* Call the pace control. */
//intf_Msg("+%lld\n", scr_time);
CRDecode( p_input, p_input->stream.pp_programs[0],
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; u16 i_id;
int i_dummy; int i_dummy;
...@@ -826,17 +767,9 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data ) ...@@ -826,17 +767,9 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
i_id = GetID( p_data ); i_id = GetID( p_data );
vlc_mutex_lock( &p_input->stream.stream_lock ); vlc_mutex_lock( &p_input->stream.stream_lock );
#if 1 if( p_input->stream.pp_programs[0]->b_is_ok )
for( i_dummy = 0; i_dummy < INPUT_MAX_ES; i_dummy++ )
{ {
if( p_input->p_es[i_dummy].i_id != EMPTY_ID /* Look only at the selected ES. */
&& p_input->p_es[i_dummy].i_id == i_id )
{
p_es = &p_input->p_es[i_dummy];
break;
}
}
#else
for( i_dummy = 0; i_dummy < INPUT_MAX_SELECTED_ES; i_dummy++ ) for( i_dummy = 0; i_dummy < INPUT_MAX_SELECTED_ES; i_dummy++ )
{ {
if( p_input->pp_selected_es[i_dummy] != NULL if( p_input->pp_selected_es[i_dummy] != NULL
...@@ -846,24 +779,33 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data ) ...@@ -846,24 +779,33 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
break; break;
} }
} }
#endif }
vlc_mutex_unlock( &p_input->stream.stream_lock ); else
{
/* Search all ES ; if not found -> AddES */
for( i_dummy = 0; i_dummy < INPUT_MAX_ES; i_dummy++ )
{
if( p_input->p_es[i_dummy].i_id != EMPTY_ID
&& p_input->p_es[i_dummy].i_id == i_id )
{
p_es = &p_input->p_es[i_dummy];
break;
}
}
if( p_es == NULL ) if( p_es == NULL )
{ {
#if 1
vlc_mutex_lock( &p_input->stream.stream_lock );
p_es = input_AddES( p_input, p_input->stream.pp_programs[0], p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
i_id, 0 ); i_id, 0 );
if( p_es != NULL ) if( p_es != NULL )
{ {
p_es->i_stream_id = p_data->p_buffer[3];
/* Set stream type and auto-spawn. */
if( (i_id & 0xF0) == 0xE0 ) if( (i_id & 0xF0) == 0xE0 )
{ {
/* MPEG video */ /* MPEG video */
p_es->i_stream_id = i_id;
p_es->i_type = MPEG2_VIDEO_ES; p_es->i_type = MPEG2_VIDEO_ES;
#ifdef AUTO_SPAWN #ifdef AUTO_SPAWN
input_SelectES( p_input, p_es ); input_SelectES( p_input, p_es );
#endif #endif
...@@ -871,9 +813,7 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data ) ...@@ -871,9 +813,7 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
else if( (i_id & 0xE0) == 0xC0 ) else if( (i_id & 0xE0) == 0xC0 )
{ {
/* MPEG audio */ /* MPEG audio */
p_es->i_stream_id = i_id;
p_es->i_type = MPEG2_AUDIO_ES; p_es->i_type = MPEG2_AUDIO_ES;
#ifdef AUTO_SPAWN #ifdef AUTO_SPAWN
input_SelectES( p_input, p_es ); input_SelectES( p_input, p_es );
#endif #endif
...@@ -881,9 +821,7 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data ) ...@@ -881,9 +821,7 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
else if( (i_id & 0xF0FF) == 0x80BD ) else if( (i_id & 0xF0FF) == 0x80BD )
{ {
/* AC3 audio */ /* AC3 audio */
p_es->i_stream_id = 0xBD;
p_es->i_type = AC3_AUDIO_ES; p_es->i_type = AC3_AUDIO_ES;
#ifdef AUTO_SPAWN #ifdef AUTO_SPAWN
input_SelectES( p_input, p_es ); input_SelectES( p_input, p_es );
#endif #endif
...@@ -891,27 +829,98 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data ) ...@@ -891,27 +829,98 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
else if( (i_id & 0xF0FF) == 0x20BD ) else if( (i_id & 0xF0FF) == 0x20BD )
{ {
/* Subtitles video */ /* Subtitles video */
p_es->i_stream_id = 0xBD;
p_es->i_type = DVD_SPU_ES; p_es->i_type = DVD_SPU_ES;
#ifdef AUTO_SPAWN #ifdef AUTO_SPAWN
input_SelectES( p_input, p_es ); input_SelectES( p_input, p_es );
#endif #endif
} }
else else
{ {
b_trash = 1; p_es->i_type = UNKNOWN_ES;
}
} }
}
} /* stream.b_is_ok */
vlc_mutex_unlock( &p_input->stream.stream_lock ); vlc_mutex_unlock( &p_input->stream.stream_lock );
} /* i_code > 0xBC */
return( p_es );
}
/*****************************************************************************
* input_DemuxPS: first step of demultiplexing: the PS header
*****************************************************************************/
void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
{
u32 i_code;
boolean_t b_trash = 0;
es_descriptor_t * p_es = NULL;
i_code = U32_AT( p_data->p_buffer );
if( i_code <= 0x1BC )
{
switch( i_code )
{
case 0x1BA: /* PACK_START_CODE */
{
/* Convert the SCR in microseconds. */
mtime_t scr_time;
if( (p_data->p_buffer[4] & 0xC0) == 0x40 )
{
/* MPEG-2 */
scr_time =
(( ((mtime_t)(p_data->p_buffer[4] & 0x38) << 27) |
((mtime_t)(U32_AT(p_data->p_buffer + 4) & 0x03FFF800)
<< 4) |
((mtime_t)(U32_AT(p_data->p_buffer + 6) & 0x03FFF800)
>> 11)
) * 300) / 27;
} }
else else
{
/* MPEG-1 SCR is like PTS */
scr_time =
(( ((mtime_t)(p_data->p_buffer[4] & 0x0E) << 29) |
(((mtime_t)U16_AT(p_data->p_buffer + 5) << 14)
- (1 << 14)) |
((mtime_t)U16_AT(p_data->p_buffer + 7) >> 1)
) * 300) / 27;
}
/* Call the pace control. */
//intf_Msg("+%lld\n", scr_time);
CRDecode( p_input, p_input->stream.pp_programs[0],
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; b_trash = 1;
#else break;
case 0x1B9: /* PROGRAM_END_CODE */
b_trash = 1; b_trash = 1;
#endif break;
default:
/* This should not happen */
b_trash = 1;
intf_WarnMsg( 1, "Unwanted packet received with start code %x",
i_code );
}
} }
else
{
p_es = input_ParsePS( p_input, p_data );
if( p_es->p_decoder_fifo != NULL && !b_trash ) if( p_es != NULL && p_es->p_decoder_fifo != NULL && !b_trash )
{ {
#ifdef STATS #ifdef STATS
p_es->c_packets++; p_es->c_packets++;
......
/*****************************************************************************
* mpeg_system.h: structures of the input used to parse MPEG-1, MPEG-2 PS
* and TS system layers
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: mpeg_system.h,v 1.2 2000/12/20 16:04:31 massiot Exp $
*
* 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.
*****************************************************************************/
/***************************************************************************** /*****************************************************************************
* Constants * Constants
*****************************************************************************/ *****************************************************************************/
...@@ -91,5 +115,7 @@ void input_DecodePES( struct input_thread_s *, struct es_descriptor_s * ); ...@@ -91,5 +115,7 @@ void input_DecodePES( struct input_thread_s *, struct es_descriptor_s * );
void input_ParsePES( 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 *, void input_GatherPES( struct input_thread_s *, struct data_packet_s *,
struct es_descriptor_s *, boolean_t, boolean_t ); struct es_descriptor_s *, boolean_t, boolean_t );
es_descriptor_t * input_ParsePS( struct input_thread_s *,
struct data_packet_s * );
void input_DemuxPS( struct input_thread_s *, struct data_packet_s * ); void input_DemuxPS( struct input_thread_s *, struct data_packet_s * );
void input_DemuxTS( struct input_thread_s *, struct data_packet_s * ); void input_DemuxTS( struct input_thread_s *, struct data_packet_s * );
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment