diff --git a/include/common.h b/include/common.h index 7dae4a886d..4d64e1a759 100644 --- a/include/common.h +++ b/include/common.h @@ -3,6 +3,7 @@ * Collection of useful common types and macros definitions ***************************************************************************** * Copyright (C) 1998, 1999, 2000 VideoLAN + * $Id: common.h,v 1.19 2000/12/26 19:14:46 massiot Exp $ * * Authors: Samuel Hocevar * Vincent Seguin @@ -39,10 +40,23 @@ typedef u8 byte_t; #ifndef SYS_SOLARIS typedef int boolean_t; #else -#include +# include #endif #ifdef SYS_GNU -#define _MACH_I386_BOOLEAN_H_ +# define _MACH_I386_BOOLEAN_H_ +#endif + +/* ptrdiff_t definition */ +#ifdef _HAVE_STDDEF_H +# include +#else +# include +#endif + +#ifndef _PTRDIFF_T +# define _PTRDIFF_T +/* Not portable in a 64-bit environment. */ +typedef int ptrdiff_t; #endif /* Counter for statistics and profiling */ @@ -126,7 +140,7 @@ typedef struct video_parser_s * p_video_parser_t; #define MIN(a, b) ( ((a) < (b)) ? (a) : (b) ) #endif -/* MSB (big endian)/LSB (little endian) convertions - network order is always +/* MSB (big endian)/LSB (little endian) conversions - network order is always * MSB, and should be used for both network communications and files. Note that * byte orders other than little and big endians are not supported, but only * the VAX seems to have such exotic properties - note that these 'functions' @@ -151,6 +165,6 @@ typedef struct video_parser_s * p_video_parser_t; /* XXX??: cause a compilation error */ #endif -/* Macros used by input to access the TS buffer */ +/* Macros with automatic casts */ #define U32_AT(p) ( ntohl ( *( (u32 *)(p) ) ) ) #define U16_AT(p) ( ntohs ( *( (u16 *)(p) ) ) ) diff --git a/include/config.h.in b/include/config.h.in index 44d51bb1b3..d122619d4f 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -171,8 +171,8 @@ /* Maximum size of a data packet (128 kB) */ #define INPUT_MAX_PACKET_SIZE 131072 -/* Maximum length of a pre-parsed chunk (32 MB) */ -#define INPUT_PREPARSE_LENGTH 33554432 +/* Maximum length of a pre-parsed chunk (4 MB) */ +#define INPUT_PREPARSE_LENGTH 4194304 /* Maximum length of a hostname or source name */ #define INPUT_MAX_SOURCE_LENGTH 100 diff --git a/include/input_ext-dec.h b/include/input_ext-dec.h index 455374f186..55e0a38b7a 100644 --- a/include/input_ext-dec.h +++ b/include/input_ext-dec.h @@ -2,7 +2,7 @@ * input_ext-dec.h: structures exported to the VideoLAN decoders ***************************************************************************** * Copyright (C) 1999, 2000 VideoLAN - * $Id: input_ext-dec.h,v 1.5 2000/12/22 17:53:30 massiot Exp $ + * $Id: input_ext-dec.h,v 1.6 2000/12/26 19:14:46 massiot Exp $ * * Authors: * @@ -400,7 +400,7 @@ static __inline__ void RealignBits( bit_stream_t * p_bit_stream ) static __inline__ void GetChunk( bit_stream_t * p_bit_stream, byte_t * p_buffer, size_t i_buf_len ) { - int i_available; + ptrdiff_t i_available; if( (i_available = p_bit_stream->p_end - p_bit_stream->p_byte) >= i_buf_len ) diff --git a/src/input/input_ext-dec.c b/src/input/input_ext-dec.c index d8f0d7158f..97aa4221f9 100644 --- a/src/input/input_ext-dec.c +++ b/src/input/input_ext-dec.c @@ -69,8 +69,7 @@ void InitBitstream( bit_stream_t * p_bit_stream, decoder_fifo_t * p_fifo ) void NextDataPacket( bit_stream_t * p_bit_stream ) { WORD_TYPE buffer_left; - /* FIXME : not portable in a 64bit environment */ - int i_bytes_left; + ptrdiff_t 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 diff --git a/src/input/input_ps.c b/src/input/input_ps.c index 17e2ad8cec..d54fab9ac9 100644 --- a/src/input/input_ps.c +++ b/src/input/input_ps.c @@ -2,7 +2,7 @@ * input_ps.c: PS demux and packet management ***************************************************************************** * Copyright (C) 1998, 1999, 2000 VideoLAN - * $Id: input_ps.c,v 1.12 2000/12/22 13:04:45 sam Exp $ + * $Id: input_ps.c,v 1.13 2000/12/26 19:14:47 massiot Exp $ * * Authors: * @@ -30,6 +30,7 @@ #include #include #include +#include #include "config.h" #include "common.h" @@ -38,6 +39,8 @@ #include "intf_msg.h" +#include "main.h" + #include "stream_control.h" #include "input_ext-intf.h" #include "input_ext-dec.h" @@ -106,16 +109,28 @@ static void PSInit( input_thread_t * p_input ) if( p_input->stream.b_seekable ) { + stream_ps_data_t * p_demux_data = + (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data; + /* 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 ) + p_demux_data->i_PSM_version = EMPTY_PSM_VERSION; + + while( !p_input->b_die && !p_input->b_error + && !p_demux_data->b_has_PSM ) { 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 ) + { + /* EOF */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + p_input->stream.pp_programs[0]->b_is_ok = 1; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + break; + } if( i_result == -1 ) { p_input->b_error = 1; @@ -137,8 +152,66 @@ static void PSInit( input_thread_t * p_input ) } 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; + if( p_demux_data->b_has_PSM ) + { + /* (The PSM decoder will care about spawning the decoders) */ + p_input->stream.pp_programs[0]->b_is_ok = 1; + } +#ifdef AUTO_SPAWN + else + { + /* (We have to do it ourselves) */ + int i_es; + + /* FIXME: we should do multiple passes in case an audio type + * is not present */ + for( i_es = 0; + i_es < p_input->stream.pp_programs[0]->i_es_number; + i_es++ ) + { +#define p_es p_input->stream.pp_programs[0]->pp_es[i_es] + switch( p_es->i_type ) + { + case MPEG1_VIDEO_ES: + case MPEG2_VIDEO_ES: + input_SelectES( p_input, p_es ); + break; + + case MPEG1_AUDIO_ES: + case MPEG2_AUDIO_ES: + if( main_GetIntVariable( INPUT_DVD_AUDIO_VAR, 0 ) + == REQUESTED_MPEG + && main_GetIntVariable( INPUT_DVD_CHANNEL_VAR, 0 ) + == (p_es->i_id & 0x1F) ) + { + input_SelectES( p_input, p_es ); + } + break; + + case AC3_AUDIO_ES: + if( main_GetIntVariable( INPUT_DVD_AUDIO_VAR, 0 ) + == REQUESTED_AC3 + && main_GetIntVariable( INPUT_DVD_CHANNEL_VAR, 0 ) + == ((p_es->i_id & 0xF00) >> 8) ) + { + input_SelectES( p_input, p_es ); + } + + case DVD_SPU_ES: + if( main_GetIntVariable( INPUT_DVD_SUBTITLE_VAR, 0 ) + == ((p_es->i_id & 0x1F00) >> 8) ) + { + input_SelectES( p_input, p_es ); + } + + case LPCM_AUDIO_ES: + /* FIXME ! */ + } + } + + } +#endif #ifdef STATS input_DumpStream( p_input ); #endif diff --git a/src/input/mpeg_system.c b/src/input/mpeg_system.c index 9e045c4b60..423be65dbe 100644 --- a/src/input/mpeg_system.c +++ b/src/input/mpeg_system.c @@ -2,7 +2,7 @@ * mpeg_system.c: TS, PS and PES management ***************************************************************************** * Copyright (C) 1998, 1999, 2000 VideoLAN - * $Id: mpeg_system.c,v 1.18 2000/12/22 17:53:30 massiot Exp $ + * $Id: mpeg_system.c,v 1.19 2000/12/26 19:14:47 massiot Exp $ * * Authors: * @@ -55,17 +55,71 @@ * PES Packet management */ +/***************************************************************************** + * MoveChunk + ***************************************************************************** + * Small utility function used to parse discontinuous headers safely. Copies + * i_buf_len bytes of data to a buffer and returns the size copied. + * This is a variation on the theme of input_ext-dec.h:GetChunk(). + *****************************************************************************/ +static __inline__ size_t MoveChunk( byte_t * p_dest, + data_packet_t ** pp_data_src, + byte_t ** pp_src, + size_t i_buf_len ) +{ + ptrdiff_t i_available; + + if( (i_available = (*pp_data_src)->p_payload_end - *pp_src) + >= i_buf_len ) + { + if( p_dest != NULL ) + memcpy( p_dest, *pp_src, i_buf_len ); + *pp_src += i_buf_len; + return( i_buf_len ); + } + else + { + size_t i_init_len = i_buf_len; + + do + { + if( p_dest != NULL ) + memcpy( p_dest, *pp_src, i_available ); + *pp_data_src = (*pp_data_src)->p_next; + i_buf_len -= i_available; + p_dest += i_available; + if( *pp_data_src == NULL ) + { + *pp_src = NULL; + return( i_init_len - i_buf_len ); + } + *pp_src = (*pp_data_src)->p_payload_start; + } + while( (i_available = (*pp_data_src)->p_payload_end - *pp_src) + <= i_buf_len ); + + if( i_buf_len ) + { + if( p_dest != NULL ) + memcpy( p_dest, *pp_src, i_buf_len ); + *pp_src += i_buf_len; + } + return( i_init_len ); + } +} + /***************************************************************************** * input_ParsePES ***************************************************************************** * Parse a finished PES packet and analyze its header. *****************************************************************************/ -#define PES_HEADER_SIZE 14 +#define PES_HEADER_SIZE 7 void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es ) { - data_packet_t * p_header_data; + data_packet_t * p_data; + byte_t * p_byte; byte_t p_header[PES_HEADER_SIZE]; - int i_done, i_todo; + int i_done; #define p_pes (p_es->p_pes) @@ -74,31 +128,12 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es ) /* 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; + p_data = p_pes->p_first; + p_byte = p_data->p_payload_start; 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 ) + if( MoveChunk( p_header, &p_data, &p_byte, PES_HEADER_SIZE ) + != 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 ); @@ -150,45 +185,64 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es ) if( (p_header[6] & 0xC0) == 0x80 ) { /* MPEG-2 : the PES header contains at least 3 more bytes. */ + size_t i_max_len; + 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). */ + /* Re-use p_header buffer now that we don't need it. */ + i_max_len = MoveChunk( p_header, &p_data, &p_byte, 7 ); + if( i_max_len < 2 ) + { + intf_WarnMsg( 3, + "PES packet too short to have a MPEG-2 header" ); + p_input->p_plugin->pf_delete_pes( p_input->p_method_data, + p_pes ); + p_pes = NULL; + return; + } + + p_pes->b_has_pts = p_header[0] & 0x80; + i_pes_header_size = p_header[1] + 9; + + /* Now parse the optional header extensions */ if( p_pes->b_has_pts ) { + if( i_max_len < 7 ) + { + intf_WarnMsg( 3, + "PES packet too short to have a MPEG-2 header" ); + p_input->p_plugin->pf_delete_pes( + p_input->p_method_data, + p_pes ); + p_pes = NULL; + return; + } 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; + ( ((mtime_t)(p_header[2] & 0x0E) << 29) | + (((mtime_t)U16_AT(p_header + 3) << 14) - (1 << 14)) | + ((mtime_t)U16_AT(p_header + 5) >> 1) ) * 300; p_pes->i_pts /= 27; } } else { /* Probably MPEG-1 */ - byte_t * p_byte; - data_packet_t * p_data; - i_pes_header_size = 6; p_data = p_pes->p_first; - p_byte = p_data->p_buffer + 6; + p_byte = p_data->p_payload_start; + /* Cannot fail because the previous one succeeded. */ + MoveChunk( NULL, &p_data, &p_byte, 6 ); + while( *p_byte == 0xFF && i_pes_header_size < 22 ) { i_pes_header_size++; - p_byte++; - if( p_byte >= p_data->p_payload_end ) + if( MoveChunk( NULL, &p_data, &p_byte, 1 ) != 1 ) { - p_data = p_data->p_next; - if( p_data == NULL ) - { - intf_ErrMsg( "MPEG-1 packet too short for header" ); - p_input->p_plugin->pf_delete_pes( p_input->p_method_data, p_pes ); - p_pes = NULL; - return; - } - p_byte = p_data->p_payload_start; + intf_WarnMsg( 3, + "PES packet too short to have a MPEG-1 header" ); + p_input->p_plugin->pf_delete_pes( p_input->p_method_data, p_pes ); + p_pes = NULL; + return; } } if( i_pes_header_size == 22 ) @@ -203,57 +257,42 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es ) { /* Don't ask why... --Meuuh */ /* Erm... why ? --Sam */ - p_byte += 2; + /* Well... According to the recommendation, it is for + * STD_buffer_scale and STD_buffer_size. --Meuuh */ i_pes_header_size += 2; - if( p_byte >= p_data->p_payload_end ) + if( MoveChunk( NULL, &p_data, &p_byte, 2 ) != 2 ) { - int i_plus = p_byte - p_data->p_payload_end; - p_data = p_data->p_next; - if( p_data == NULL ) - { - intf_ErrMsg( "MPEG-1 packet too short for header" ); - p_input->p_plugin->pf_delete_pes( p_input->p_method_data, p_pes ); - p_pes = NULL; - return; - } - p_byte = p_data->p_payload_start + i_plus; + intf_WarnMsg( 3, + "PES packet too short to have a MPEG-1 header" ); + p_input->p_plugin->pf_delete_pes( p_input->p_method_data, p_pes ); + p_pes = NULL; + return; } } i_pes_header_size++; - p_pes->b_has_pts = *p_byte & 0x20; if( *p_byte & 0x10 ) { /* DTS */ i_pes_header_size += 5; } - if( *p_byte & 0x20 ) + if( (p_pes->b_has_pts = (*p_byte & 0x20)) ) { /* PTS */ byte_t p_pts[5]; - int i; i_pes_header_size += 4; - p_pts[0] = *p_byte; - for( i = 1; i < 5; i++ ) + if( MoveChunk( p_pts, &p_data, &p_byte, 5 ) != 5 ) { - p_byte++; - if( p_byte >= p_data->p_payload_end ) - { - p_data = p_data->p_next; - if( p_data == NULL ) - { - intf_ErrMsg( "MPEG-1 packet too short for header" ); - p_input->p_plugin->pf_delete_pes( p_input->p_method_data, p_pes ); - p_pes = NULL; - return; - } - p_byte = p_data->p_payload_start; - } - - p_pts[i] = *p_byte; + intf_WarnMsg( 3, + "PES packet too short to have a MPEG-1 header" ); + p_input->p_plugin->pf_delete_pes( + p_input->p_method_data, p_pes ); + p_pes = NULL; + return; } + p_pes->i_pts = ( ((mtime_t)(p_pts[0] & 0x0E) << 29) | (((mtime_t)U16_AT(p_pts + 1) << 14) - (1 << 14)) | @@ -299,16 +338,16 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es ) * 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; + p_data = p_pes->p_first; + i_payload_size = p_data->p_payload_end + - p_data->p_payload_start; while( i_pes_header_size > i_payload_size ) { /* These packets are entirely filled by the PES header. */ i_pes_header_size -= i_payload_size; - p_header_data->p_payload_start = p_header_data->p_payload_end; + p_data->p_payload_start = p_data->p_payload_end; /* Go to the next data packet. */ - if( (p_header_data = p_header_data->p_next) == NULL ) + if( (p_data = p_data->p_next) == NULL ) { intf_ErrMsg( "PES header bigger than payload" ); p_input->p_plugin->pf_delete_pes( p_input->p_method_data, @@ -316,8 +355,8 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es ) p_pes = NULL; return; } - i_payload_size = p_header_data->p_payload_end - - p_header_data->p_payload_start; + i_payload_size = p_data->p_payload_end + - p_data->p_payload_start; } /* This last packet is partly header, partly payload. */ if( i_payload_size < i_pes_header_size ) @@ -327,7 +366,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es ) p_pes = NULL; return; } - p_header_data->p_payload_start += i_pes_header_size; + p_data->p_payload_start += i_pes_header_size; /* Now we can eventually put the PES packet in the decoder's * PES fifo */ @@ -623,71 +662,121 @@ static u16 GetID( data_packet_t * p_data ) /***************************************************************************** * DecodePSM: Decode the Program Stream Map information *****************************************************************************/ -/* FIXME : deprecated code ! */ static void DecodePSM( input_thread_t * p_input, data_packet_t * p_data ) { stream_ps_data_t * p_demux = (stream_ps_data_t *)p_input->stream.p_demux_data; + byte_t * p_byte; + byte_t * p_end; + int i; + int i_new_es_number = 0; intf_Msg("input info: Your stream contains Program Stream Map information"); intf_Msg("input info: Please send a mail to "); -#if 0 - if( !p_demux->b_is_PSM_complete ) + p_demux->b_has_PSM = 1; + + if( p_data->p_payload_start + 10 > p_data->p_payload_end ) { - byte_t * p_byte; - byte_t * p_end; + intf_ErrMsg( "PSM too short : packet corrupt" ); + return; + } - 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; - } + if( p_demux->i_PSM_version == (p_data->p_buffer[6] & 0x1F) ) + { + /* Already got that one. */ + return; + } - vlc_mutex_lock( &p_input->stream.stream_lock ); + intf_DbgMsg( "Building PSM" ); + p_demux->i_PSM_version = p_data->p_buffer[6] & 0x1F; + + /* 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 ) + /* 4 == minimum useful size of a section */ + while( p_byte + 4 <= p_end ) + { + es_descriptor_t * p_es = NULL; + u8 i_stream_id = p_byte[1]; + /* FIXME: there will be a problem with private streams... (same + * stream_id) */ + + /* Look for the ES in the ES table */ + for( i = i_new_es_number; + i < p_input->stream.pp_programs[0]->i_es_number; + i++ ) { - es_descriptor_t * p_es; + if( p_input->stream.pp_programs[0]->pp_es[i]->i_stream_id + == i_stream_id ) + { + p_es = p_input->stream.pp_programs[0]->pp_es[i]; + if( p_es->i_type != p_byte[0] ) + { + input_DelES( p_input, p_es ); + p_es = NULL; + } + else + { + /* Move the ES to the beginning. */ + i_new_es_number++; + p_input->stream.pp_programs[0]->pp_es[i] + = p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ]; + p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ] + = p_es; + } + break; + } + } + /* The goal is to have all the ES we have just read in the + * beginning of the pp_es table, and all the others at the end, + * so that we can close them more easily at the end. */ + if( p_es == NULL ) + { p_es = input_AddES( p_input, p_input->stream.pp_programs[0], - p_byte[1], 0 ); + i_stream_id, 0 ); p_es->i_type = p_byte[0]; - p_byte += 4 + U16_AT(&p_byte[2]); - } + i_new_es_number++; - 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; + /* input_AddES has inserted the new element at the end. */ + p_input->stream.pp_programs[0]->pp_es[ + p_input->stream.pp_programs[0]->i_es_number ] + = p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ]; + p_input->stream.pp_programs[0]->pp_es[ i_new_es_number ] = p_es; + } + p_byte += 4 + U16_AT(&p_byte[2]); } - else if( p_demux->i_PSM_version != (p_data->p_buffer[6] & 0x1F) ) + + /* Un-select the streams that are no longer parts of the program. */ + for( i = i_new_es_number; + i < p_input->stream.pp_programs[0]->i_es_number; + i++ ) { - /* FIXME */ - intf_ErrMsg( "PSM changed, this is not supported yet !" ); - p_demux->i_PSM_version = p_data->p_buffer[6] & 0x1F; + input_DelES( p_input, + p_input->stream.pp_programs[0]->pp_es[i_new_es_number] ); + /* Yes, I wrote *i_new_es_number* */ } -#endif + vlc_mutex_unlock( &p_input->stream.stream_lock ); } /***************************************************************************** @@ -725,10 +814,13 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input, } else { + stream_ps_data_t * p_demux = + (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data; + /* Search all ES ; if not found -> AddES */ p_es = input_FindES( p_input, i_id ); - if( p_es == NULL ) + if( p_es == NULL && !p_demux->b_has_PSM ) { p_es = input_AddES( p_input, p_input->stream.pp_programs[0], i_id, 0 ); @@ -742,7 +834,8 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input, /* MPEG video */ p_es->i_type = MPEG2_VIDEO_ES; #ifdef AUTO_SPAWN - input_SelectES( p_input, p_es ); + if( !p_input->stream.b_seekable ) + input_SelectES( p_input, p_es ); #endif } else if( (i_id & 0xE0) == 0xC0 ) @@ -755,7 +848,8 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input, && main_GetIntVariable( INPUT_DVD_CHANNEL_VAR, 0 ) == (p_es->i_id & 0x1F) ) { - input_SelectES( p_input, p_es ); + if( !p_input->stream.b_seekable ) + input_SelectES( p_input, p_es ); } #endif } @@ -769,7 +863,8 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input, && main_GetIntVariable( INPUT_DVD_CHANNEL_VAR, 0 ) == ((p_es->i_id & 0xF00) >> 8) ) { - input_SelectES( p_input, p_es ); + if( !p_input->stream.b_seekable ) + input_SelectES( p_input, p_es ); } #endif } @@ -781,7 +876,8 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input, if( main_GetIntVariable( INPUT_DVD_SUBTITLE_VAR, 0 ) == ((p_es->i_id & 0x1F00) >> 8) ) { - input_SelectES( p_input, p_es ); + if( !p_input->stream.b_seekable ) + input_SelectES( p_input, p_es ); } #endif } diff --git a/src/input/mpeg_system.h b/src/input/mpeg_system.h index 9c27e7aa61..c405ccec95 100644 --- a/src/input/mpeg_system.h +++ b/src/input/mpeg_system.h @@ -3,7 +3,7 @@ * and TS system layers ***************************************************************************** * Copyright (C) 1999, 2000 VideoLAN - * $Id: mpeg_system.h,v 1.3 2000/12/22 10:58:27 massiot Exp $ + * $Id: mpeg_system.h,v 1.4 2000/12/26 19:14:47 massiot Exp $ * * Authors: * @@ -103,10 +103,14 @@ typedef struct stream_ts_data_s *****************************************************************************/ typedef struct stream_ps_data_s { + boolean_t b_has_PSM; /* very rare, in fact */ + u8 i_PSM_version; - boolean_t b_is_PSM_complete; } stream_ps_data_t; +/* PSM version is 5 bits, so -1 is not a valid value */ +#define EMPTY_PSM_VERSION -1 + /***************************************************************************** * Prototypes diff --git a/src/video_decoder/vpar_synchro.h b/src/video_decoder/vpar_synchro.h index f5ada16b44..06ce9a006f 100644 --- a/src/video_decoder/vpar_synchro.h +++ b/src/video_decoder/vpar_synchro.h @@ -2,7 +2,7 @@ * vpar_synchro.h : video parser blocks management ***************************************************************************** * Copyright (C) 1999, 2000 VideoLAN - * $Id: vpar_synchro.h,v 1.1 2000/12/21 17:19:52 massiot Exp $ + * $Id: vpar_synchro.h,v 1.2 2000/12/26 19:14:47 massiot Exp $ * * Author: Christophe Massiot * @@ -66,7 +66,7 @@ typedef struct video_synchro_s mtime_t backward_pts, current_pts; #ifdef STATS - unsigned int i_trashed_pic; + unsigned int i_trashed_pic, i_pic; #endif } video_synchro_t; diff --git a/src/video_parser/vpar_synchro.c b/src/video_parser/vpar_synchro.c index 8e3a1f5d7e..1f8e373f3a 100644 --- a/src/video_parser/vpar_synchro.c +++ b/src/video_parser/vpar_synchro.c @@ -2,7 +2,7 @@ * vpar_synchro.c : frame dropping routines ***************************************************************************** * Copyright (C) 1999, 2000 VideoLAN - * $Id: vpar_synchro.c,v 1.63 2000/12/22 13:04:45 sam Exp $ + * $Id: vpar_synchro.c,v 1.64 2000/12/26 19:14:47 massiot Exp $ * * Authors: Christophe Massiot * Samuel Hocevar @@ -271,7 +271,7 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type, if( S.i_eta_b ) S.i_n_b = S.i_eta_b; if( S.i_eta_p + 1 > S.i_n_p ) - S.i_n_p++; + S.i_n_p = S.i_eta_p + 1; if( S.backward_pts ) { @@ -310,7 +310,7 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type, case B_CODING_TYPE: /* Stream structure changes */ if( S.i_eta_b + 1 > S.i_n_b ) - S.i_n_b++; + S.i_n_b = S.i_eta_b + 1; pts = S.current_pts + period; @@ -495,6 +495,8 @@ static void SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type ) { case I_CODING_TYPE: p_vpar->synchro.i_eta_p = p_vpar->synchro.i_eta_b = 0; + if( p_vpar->synchro.i_eta_p ) + p_vpar->synchro.i_n_p = p_vpar->synchro.i_eta_p; #ifdef STATS if( p_vpar->synchro.i_type == VPAR_SYNCHRO_DEFAULT ) { @@ -505,16 +507,19 @@ static void SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type ) p_vpar->synchro.p_tau[B_CODING_TYPE], p_vpar->synchro.i_n_b, p_vpar->p_vout->render_time, - 1 + p_vpar->synchro.i_n_p * (1 + p_vpar->synchro.i_n_b) - + p_vpar->synchro.i_pic - p_vpar->synchro.i_trashed_pic, - 1 + p_vpar->synchro.i_n_p * (1 + p_vpar->synchro.i_n_b) ); + p_vpar->synchro.i_pic ); p_vpar->synchro.i_trashed_pic = 0; + p_vpar->synchro.i_pic = 0; } #endif break; case P_CODING_TYPE: - p_vpar->synchro.i_eta_b = 0; p_vpar->synchro.i_eta_p++; + if( p_vpar->synchro.i_eta_b ) + p_vpar->synchro.i_n_b = p_vpar->synchro.i_eta_b; + p_vpar->synchro.i_eta_b = 0; break; case B_CODING_TYPE: p_vpar->synchro.i_eta_b++; @@ -537,14 +542,16 @@ static void SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type ) } else { - p_vpar->synchro.current_pts += 1000000 / (p_vpar->sequence.i_frame_rate) * 1001; + p_vpar->synchro.current_pts += 1000000 + / (p_vpar->sequence.i_frame_rate) * 1001; } } else { if( p_vpar->synchro.backward_pts == 0 ) { - p_vpar->synchro.current_pts += 1000000 / (p_vpar->sequence.i_frame_rate) * 1001; + p_vpar->synchro.current_pts += 1000000 + / (p_vpar->sequence.i_frame_rate) * 1001; } else { @@ -564,4 +571,8 @@ static void SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type ) p_pes->b_has_pts = 0; } } + +#ifdef STATS + p_vpar->synchro.i_pic++; +#endif }