* system.c: helper module for TS, PS and PES management
*****************************************************************************
* Copyright (C) 1998-2002 VideoLAN
- * $Id: system.c,v 1.2 2002/08/30 22:22:24 massiot Exp $
+ * $Id: system.c,v 1.26 2003/12/22 14:32:56 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Michel Lespinasse <walken@via.ecp.fr>
* BenoƮt Steiner <benny@via.ecp.fr>
- * Samuel Hocevar <sam@zoy.org>
+ * Sam Hocevar <sam@zoy.org>
* Henri Fallon <henri@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Preamble
*****************************************************************************/
#include <stdlib.h>
-#include <string.h> /* memcpy(), memset() */
-#include <sys/types.h> /* off_t */
#include <vlc/vlc.h>
#include <vlc/input.h>
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;
+ size_t i_available;
- if( (i_available = (*pp_data_src)->p_payload_end - *pp_src)
- >= i_buf_len )
+ i_available = (ptrdiff_t)((*pp_data_src)->p_payload_end - *pp_src);
+ if( i_available >= i_buf_len )
{
if( p_dest != NULL )
memcpy( p_dest, *pp_src, i_buf_len );
}
else
{
- size_t i_init_len = i_buf_len;
+ size_t i_init_len = i_buf_len;
do
{
return( i_init_len - i_buf_len );
}
*pp_src = (*pp_data_src)->p_payload_start;
+
+ i_available = (ptrdiff_t)((*pp_data_src)->p_payload_end - *pp_src);
}
- while( (i_available = (*pp_data_src)->p_payload_end - *pp_src)
- <= i_buf_len );
+ while( i_available <= i_buf_len );
if( i_buf_len )
{
if( (p_header[0] || p_header[1] || (p_header[2] != 1)) )
{
/* packet_start_code_prefix != 0x000001 */
- msg_Err( p_input, "data loss, PES packet does not start with 000001" );
+ msg_Warn( p_input, "data loss, PES packet does not start with 000001" );
input_DeletePES( p_input->p_method_data, p_pes );
p_pes = NULL;
}
else
{
- int i_pes_header_size, i_payload_size;
+ unsigned 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) )
msg_Warn( p_input, "packet corrupted, PES sizes do not match" );
}
- switch( p_es->i_stream_id )
+ switch( p_header[3] )
{
case 0xBC: /* Program stream map */
case 0xBE: /* Padding */
i_max_len = MoveChunk( p_full_header, &p_data, &p_byte, 12 );
if( i_max_len < 2 )
{
- msg_Warn( p_input,
+ msg_Warn( p_input,
"PES packet too short to have a MPEG-2 header" );
input_DeletePES( p_input->p_method_data,
p_pes );
}
if( i_pes_header_size == 23 )
{
- msg_Err( p_input, "too much MPEG-1 stuffing" );
+ msg_Warn( p_input, "too much MPEG-1 stuffing" );
input_DeletePES( p_input->p_method_data, p_pes );
p_pes = NULL;
return;
}
/* Welcome to the kludge area ! --Meuuh */
- if( p_es->i_fourcc == VLC_FOURCC('a','5','2','b') )
+ if ( p_es->i_fourcc == VLC_FOURCC('a','5','2','b')
+ || p_es->i_fourcc == VLC_FOURCC('d','t','s','b') )
{
- /* With A/52 audio, we need to skip the first 4 bytes */
+ /* With A/52 or DTS audio, we need to skip the first 4 bytes */
i_pes_header_size += 4;
}
- else if( p_es->i_fourcc == VLC_FOURCC('l','p','c','b')
- || p_es->i_fourcc == VLC_FOURCC('s','p','u','b')
- || p_es->i_fourcc == VLC_FOURCC('d','t','s','b')
- || p_es->i_fourcc == VLC_FOURCC('s','d','d','b') )
+
+ if ( p_es->i_fourcc == VLC_FOURCC('l','p','c','b')
+ || p_es->i_fourcc == VLC_FOURCC('s','p','u','b')
+ || p_es->i_fourcc == VLC_FOURCC('s','d','d','b') )
{
- /* With others, we need to skip the first byte */
+ /* stream_private_id */
i_pes_header_size += 1;
}
/* Go to the next data packet. */
if( (p_data = p_data->p_next) == NULL )
{
- msg_Err( p_input, "PES header bigger than payload" );
+ msg_Warn( p_input, "PES header bigger than payload" );
input_DeletePES( p_input->p_method_data, p_pes );
p_pes = NULL;
return;
/* This last packet is partly header, partly payload. */
if( i_payload_size < i_pes_header_size )
{
- msg_Err( p_input, "PES header bigger than payload" );
+ msg_Warn( p_input, "PES header bigger than payload" );
input_DeletePES( p_input->p_method_data, p_pes );
p_pes = NULL;
return;
/* Now we can eventually put the PES packet in the decoder's
* PES fifo */
- if( p_es->p_decoder_fifo != NULL )
+ if( p_es->p_dec != NULL )
{
- input_DecodePES( p_es->p_decoder_fifo, p_pes );
+ input_DecodePES( p_es->p_dec, p_pes );
+ }
+ else if ( p_es->p_dec == NULL &&
+ ((es_ts_data_t*)p_es->p_demux_data)->b_dvbsub)
+ {
+ es_descriptor_t* p_dvbsub;
+ uint8_t i_count;
+ uint8_t i;
+ i_count = ((es_ts_data_t*)p_es->p_demux_data)->i_dvbsub_es_count;
+
+ // If a language is selected, we send the packet to the decoder
+ for(i = 0; i < i_count; i++)
+ {
+ p_dvbsub = ((es_ts_data_t*)p_es->p_demux_data)->p_dvbsub_es[i];
+ if(p_dvbsub->p_dec !=NULL)
+ {
+ input_DecodePES ( p_dvbsub->p_dec, p_pes );
+ break;
+ }
+ }
+ if(i == i_count)
+ {
+ input_DeletePES( p_input->p_method_data, p_pes );
+ }
}
else
{
{
#define p_pes (p_es->p_pes)
- /* If we lost data, insert a NULL data packet (philosophy : 0 is quite
- * often an escape sequence in decoders, so that should make them wait
- * for the next start code). */
- if( b_packet_lost )
+ if( b_packet_lost && p_pes != NULL )
{
- input_NullPacket( p_input, p_es );
+ p_pes->b_discontinuity = 1;
}
if( b_unit_start && p_pes != NULL )
}
p_pes->i_rate = p_input->stream.control.i_rate;
p_pes->p_first = p_data;
-
+
/* If the PES header fits in the first data packet, we can
* already set p_gather->i_pes_real_size. */
if( p_data->p_payload_end - p_data->p_payload_start
>= PES_HEADER_SIZE )
{
- p_es->i_pes_real_size = ((u16)p_data->p_payload_start[4] << 8)
- + p_data->p_payload_start[5] + 6;
+ p_es->i_pes_real_size = ((uint16_t)p_data->p_payload_start[4] << 8)
+ + p_data->p_payload_start[5];
+ if ( p_es->i_pes_real_size )
+ {
+ p_es->i_pes_real_size += 6;
+ }
}
else
- {
+ {
p_es->i_pes_real_size = 0;
- }
+ }
}
else
{
/* 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 )
+ if( p_es->i_pes_real_size && p_pes->i_pes_size >= p_es->i_pes_real_size )
{
+ if( p_pes->i_pes_size > p_es->i_pes_real_size )
+ {
+ msg_Warn( p_input,
+ "Oversized PES packet for PID %d: expected %d, actual %d",
+ p_es->i_id, p_es->i_pes_real_size, p_pes->i_pes_size );
+ }
/* The packet is finished, parse it */
ParsePES( p_input, p_es );
}
/*****************************************************************************
* GetID: Get the ID of a stream
*****************************************************************************/
-static u16 GetID( data_packet_t * p_data )
+static uint16_t GetID( data_packet_t * p_data )
{
- u16 i_id;
+ uint16_t i_id;
i_id = p_data->p_demux_start[3]; /* stream_id */
if( i_id == 0xBD )
(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;
+ unsigned int i;
+ unsigned int i_new_es_number = 0;
if( p_data->p_demux_start + 10 > p_data->p_payload_end )
{
while( p_byte + 4 <= p_end )
{
es_descriptor_t * p_es = NULL;
- u8 i_stream_id = p_byte[1];
+ uint8_t i_stream_id = p_byte[1];
/* FIXME: there will be a problem with private streams... (same
* stream_id) */
* so that we can close them more easily at the end. */
if( p_es == NULL )
{
- p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
- i_stream_id, 0 );
+ int i_fourcc, i_cat;
+
switch( p_byte[0] )
{
case MPEG1_VIDEO_ES:
case MPEG2_VIDEO_ES:
- p_es->i_fourcc = VLC_FOURCC('m','p','g','v');
- p_es->i_cat = VIDEO_ES;
+ case MPEG2_MOTO_VIDEO_ES:
+ i_fourcc = VLC_FOURCC('m','p','g','v');
+ i_cat = VIDEO_ES;
break;
case DVD_SPU_ES:
- p_es->i_fourcc = VLC_FOURCC('s','p','u','b');
- p_es->i_cat = SPU_ES;
+ i_fourcc = VLC_FOURCC('s','p','u','b');
+ i_cat = SPU_ES;
break;
case MPEG1_AUDIO_ES:
case MPEG2_AUDIO_ES:
- p_es->i_fourcc = VLC_FOURCC('m','p','g','a');
- p_es->i_cat = AUDIO_ES;
+ i_fourcc = VLC_FOURCC('m','p','g','a');
+ i_cat = AUDIO_ES;
break;
case A52_AUDIO_ES:
- p_es->i_fourcc = VLC_FOURCC('a','5','2','b');
- p_es->i_cat = AUDIO_ES;
+ i_fourcc = VLC_FOURCC('a','5','2','b');
+ i_cat = AUDIO_ES;
break;
case LPCM_AUDIO_ES:
- p_es->i_fourcc = VLC_FOURCC('l','p','c','b');
- p_es->i_cat = AUDIO_ES;
+ i_fourcc = VLC_FOURCC('l','p','c','b');
+ i_cat = AUDIO_ES;
break;
default:
- p_es->i_fourcc = 0;
+ i_cat = UNKNOWN_ES;
+ i_fourcc = 0;
break;
}
+ p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
+ i_stream_id, i_cat, NULL, 0 );
+ p_es->i_fourcc = i_fourcc;
+
/* 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 ]
{ \
return( -1 ); \
} \
- else if( i_error < SIZE ) \
+ else if( (size_t)i_error < SIZE ) \
{ \
/* EOF */ \
return( 0 ); \
else
{
msg_Err( p_input, "unable to determine stream type" );
+ p_input->p_current_data++;
return( -1 );
}
}
static es_descriptor_t * ParsePS( input_thread_t * p_input,
data_packet_t * p_data )
{
- u32 i_code;
+ uint32_t i_code;
es_descriptor_t * p_es = NULL;
i_code = p_data->p_demux_start[3];
if( i_code > 0xBC ) /* ES start code */
{
- u16 i_id;
- int i_dummy;
+ uint16_t i_id;
+ unsigned int i_dummy;
/* This is a PES packet. Find out if we want it or not. */
i_id = GetID( p_data );
}
else
{
+ vlc_bool_t b_auto_spawn = VLC_FALSE;
stream_ps_data_t * p_demux =
(stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
if( p_es == NULL && !p_demux->b_has_PSM )
{
- p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
- i_id, 0 );
- if( p_es != NULL )
- {
- p_es->i_stream_id = p_data->p_demux_start[3];
+ int i_fourcc, i_cat;
- /* Set stream type and auto-spawn. */
- if( (i_id & 0xF0) == 0xE0 )
- {
- /* MPEG video */
- p_es->i_fourcc = VLC_FOURCC('m','p','g','v');
- p_es->i_cat = VIDEO_ES;
+ /* Set stream type and auto-spawn. */
+ if( (i_id & 0xF0) == 0xE0 )
+ {
+ /* MPEG video */
+ i_fourcc = VLC_FOURCC('m','p','g','v');
+ i_cat = VIDEO_ES;
#ifdef AUTO_SPAWN
- if( !p_input->stream.b_seekable )
- input_SelectES( p_input, p_es );
+ if( !p_input->stream.b_seekable ) b_auto_spawn = VLC_TRUE;
#endif
- }
- else if( (i_id & 0xE0) == 0xC0 )
- {
- /* MPEG audio */
- p_es->i_fourcc = VLC_FOURCC('m','p','g','a');
- p_es->i_cat = AUDIO_ES;
+ }
+ else if( (i_id & 0xE0) == 0xC0 )
+ {
+ /* MPEG audio */
+ i_fourcc = VLC_FOURCC('m','p','g','a');
+ i_cat = AUDIO_ES;
#ifdef AUTO_SPAWN
- if( !p_input->stream.b_seekable )
- if( config_GetInt( p_input, "audio-channel" )
- == (p_es->i_id & 0x1F) ||
- ( config_GetInt( p_input, "audio-channel" ) < 0
- && !(p_es->i_id & 0x1F) ) )
- switch( config_GetInt( p_input, "audio-type" ) )
- {
- case -1:
- case REQUESTED_MPEG:
- input_SelectES( p_input, p_es );
- }
-#endif
- }
- else if( (i_id & 0xF0FF) == 0x80BD )
+ if( !p_input->stream.b_seekable )
+ if( config_GetInt( p_input, "audio-channel" )
+ == (i_id & 0x1F) ||
+ ( config_GetInt( p_input, "audio-channel" ) < 0
+ && !(i_id & 0x1F) ) )
+ switch( config_GetInt( p_input, "audio-type" ) )
{
- /* A52 audio (0x80->0x8F) */
- p_es->i_fourcc = VLC_FOURCC('a','5','2','b');
- p_es->i_cat = AUDIO_ES;
-#ifdef AUTO_SPAWN
- if( !p_input->stream.b_seekable )
- if( config_GetInt( p_input, "audio-channel" )
- == ((p_es->i_id & 0xF00) >> 8) ||
- ( config_GetInt( p_input, "audio-channel" ) < 0
- && !((p_es->i_id & 0xF00) >> 8)) )
- switch( config_GetInt( p_input, "audio-type" ) )
- {
- case -1:
- case REQUESTED_A52:
- input_SelectES( p_input, p_es );
- }
-#endif
+ case -1:
+ case REQUESTED_MPEG:
+ b_auto_spawn = VLC_TRUE;
}
- else if( (i_id & 0xE0FF) == 0x20BD )
- {
- /* Subtitles video (0x20->0x3F) */
- p_es->i_fourcc = VLC_FOURCC('s','p','u','b');
- p_es->i_cat = SPU_ES;
+#endif
+ }
+ else if( (i_id & 0xF8FF) == 0x88BD )
+ {
+ i_fourcc = VLC_FOURCC('d','t','s','b');
+ i_cat = AUDIO_ES;
#ifdef AUTO_SPAWN
- if( config_GetInt( p_input, "spu-channel" )
- == ((p_es->i_id & 0x1F00) >> 8) )
- {
- if( !p_input->stream.b_seekable )
- input_SelectES( p_input, p_es );
- }
+ if( !p_input->stream.b_seekable )
+ if( config_GetInt( p_input, "audio-channel" )
+ == ((i_id & 0x700) >> 8) ||
+ ( config_GetInt( p_input, "audio-channel" ) < 0
+ && !((i_id & 0x700) >> 8)) )
+ switch( config_GetInt( p_input, "audio-type" ) )
+ {
+ case -1:
+ case REQUESTED_DTS:
+ b_auto_spawn = VLC_TRUE;
+ }
#endif
+ }
+ else if( (i_id & 0xF0FF) == 0x80BD )
+ {
+ /* A52 audio (0x80->0x8F) */
+ i_fourcc = VLC_FOURCC('a','5','2','b');
+ i_cat = AUDIO_ES;
+#ifdef AUTO_SPAWN
+ if( !p_input->stream.b_seekable )
+ if( config_GetInt( p_input, "audio-channel" )
+ == ((i_id & 0xF00) >> 8) ||
+ ( config_GetInt( p_input, "audio-channel" ) < 0
+ && !((i_id & 0xF00) >> 8)) )
+ switch( config_GetInt( p_input, "audio-type" ) )
+ {
+ case -1:
+ case REQUESTED_A52:
+ b_auto_spawn = VLC_TRUE;
}
- else if( (i_id & 0xF0FF) == 0xA0BD )
+#endif
+ }
+ else if( (i_id & 0xE0FF) == 0x20BD )
+ {
+ /* Subtitles video (0x20->0x3F) */
+ i_fourcc = VLC_FOURCC('s','p','u','b');
+ i_cat = SPU_ES;
+#ifdef AUTO_SPAWN
+ if( !p_input->stream.b_seekable )
+ if( config_GetInt( p_input, "spu-channel" )
+ == ((i_id & 0x1F00) >> 8) )
{
- /* LPCM audio (0xA0->0xAF) */
- p_es->i_fourcc = VLC_FOURCC('l','p','c','b');
- p_es->i_cat = AUDIO_ES;
+ b_auto_spawn = VLC_TRUE;
}
- else
+#endif
+ }
+ else if( (i_id & 0xF0FF) == 0xA0BD )
+ {
+ /* LPCM audio (0xA0->0xAF) */
+ i_fourcc = VLC_FOURCC('l','p','c','b');
+ i_cat = AUDIO_ES;
+ }
+ else if( (i_id & 0xFFFF) == 0x70BD )
+ {
+ /* SVCD OGT subtitles in stream 0x070 */
+ i_fourcc = VLC_FOURCC('o','g','t', ' ');
+ i_cat = SPU_ES;
+#ifdef FINISHED_DEBUGGING
+ if( !p_input->stream.b_seekable )
+ if( config_GetInt( p_input, "spu-channel" )
+ == ((i_id & 0x0300) >> 8) )
+#endif
{
- p_es->i_fourcc = 0;
+ b_auto_spawn = VLC_TRUE;
}
}
+ else if( ((i_id >> 8) & 0xFF) <= 0x03 &&
+ (i_id & 0x00FF) == 0x00BD )
+ {
+ /* CVD subtitles (0x00->0x03) */
+ i_fourcc = VLC_FOURCC('c','v','d', ' ');
+ i_cat = SPU_ES;
+ msg_Warn( p_input,
+ "CVD subtitles not implemented yet" );
+ }
+ else
+ {
+ i_cat = UNKNOWN_ES;
+ i_fourcc = 0;
+ }
+
+ p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
+ i_id, i_cat, NULL, 0 );
+
+ p_es->i_stream_id = p_data->p_demux_start[3];
+ p_es->i_fourcc = i_fourcc;
+
+ if( b_auto_spawn ) input_SelectES( p_input, p_es );
/* Tell the interface the stream has changed */
p_input->stream.b_changed = 1;
*****************************************************************************/
static void DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
{
- u32 i_code;
- vlc_bool_t b_trash = 0;
- es_descriptor_t * p_es = NULL;
+ uint32_t i_code;
+ vlc_bool_t b_trash = 0;
+ es_descriptor_t * p_es = NULL;
- i_code = ((u32)p_data->p_demux_start[0] << 24)
- | ((u32)p_data->p_demux_start[1] << 16)
- | ((u32)p_data->p_demux_start[2] << 8)
+ i_code = ((uint32_t)p_data->p_demux_start[0] << 24)
+ | ((uint32_t)p_data->p_demux_start[1] << 16)
+ | ((uint32_t)p_data->p_demux_start[2] << 8)
| p_data->p_demux_start[3];
if( i_code <= 0x1BC )
{
case 0x1BA: /* PACK_START_CODE */
{
/* Read the SCR. */
- mtime_t scr_time;
- u32 i_mux_rate;
+ mtime_t scr_time;
+ uint32_t i_mux_rate;
if( (p_data->p_demux_start[4] & 0xC0) == 0x40 )
{
>> 11);
/* mux_rate */
- i_mux_rate = ((u32)U16_AT(p_header + 10) << 6)
+ i_mux_rate = ((uint32_t)U16_AT(p_header + 10) << 6)
| (p_header[12] >> 2);
/* FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
* This is the biggest kludge ever !
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;
p_es = ParsePS( p_input, p_data );
vlc_mutex_lock( &p_input->stream.control.control_lock );
- if( p_es != NULL && p_es->p_decoder_fifo != NULL
+ if( p_es != NULL && p_es->p_dec != NULL
&& (p_es->i_cat != AUDIO_ES || !p_input->stream.control.b_mute) )
{
vlc_mutex_unlock( &p_input->stream.control.control_lock );
}
}
-
+
/*
* TS Demultiplexing
*/
static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
psi_callback_t pf_psi_callback )
{
- u16 i_pid;
- int i_dummy;
+ uint16_t i_pid;
+ unsigned int i_dummy;
vlc_bool_t b_adaptation; /* Adaptation field is present */
vlc_bool_t b_payload; /* Packet carries payload */
vlc_bool_t b_unit_start; /* A PSI or a PES start in the packet */
vlc_bool_t b_trash = 0; /* Is the packet unuseful ? */
vlc_bool_t b_lost = 0; /* Was there a packet loss ? */
vlc_bool_t b_psi = 0; /* Is this a PSI ? */
+ vlc_bool_t b_dvbsub = 0; /* Is this a dvb subtitle ? */
vlc_bool_t b_pcr = 0; /* Does it have a PCR ? */
es_descriptor_t * p_es = NULL;
es_ts_data_t * p_es_demux = NULL;
pgrm_ts_data_t * p_pgrm_demux = NULL;
+ stream_ts_data_t * p_stream_demux =
+ (stream_ts_data_t *)p_input->stream.p_demux_data;
#define p (p_data->p_demux_start)
/* Extract flags values from TS common header. */
b_adaptation = (p[3] & 0x20);
b_payload = (p[3] & 0x10);
+ /* Was there a transport error ? */
+ if ( p[1] & 0x80 )
+ {
+ msg_Warn( p_input, "transport_error_indicator set for PID %d counter %x", i_pid, p[3] & 0x0f );
+ }
+
/* Find out the elementary stream. */
vlc_mutex_lock( &p_input->stream.stream_lock );
-
+
for( i_dummy = 0; i_dummy < p_input->stream.i_pgrm_number; i_dummy ++ )
{
if( (( pgrm_ts_data_t * ) p_input->stream.pp_programs[i_dummy]->
break;
}
}
-
- p_es= input_FindES( p_input, i_pid );
-
+
+ p_es = input_FindES( p_input, i_pid );
+
if( (p_es != NULL) && (p_es->p_demux_data != NULL) )
{
p_es_demux = (es_ts_data_t *)p_es->p_demux_data;
-
+
if( p_es_demux->b_psi )
{
b_psi = 1;
}
+ else if ( p_es_demux->b_dvbsub )
+ {
+ b_dvbsub = 1;
+ }
else
{
- p_pgrm_demux = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data;
+ p_pgrm_demux = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data;
}
}
/* Not selected. Just read the adaptation field for a PCR. */
b_trash = 1;
}
- else if( p_es->p_decoder_fifo == NULL && !b_psi )
+ else if( p_es->p_dec == NULL && !b_psi && !b_dvbsub )
{
- b_trash = 1;
+ b_trash = 1;
}
vlc_mutex_unlock( &p_input->stream.control.control_lock );
vlc_mutex_unlock( &p_input->stream.stream_lock );
- /* Don't change the order of the tests : if b_psi then p_pgrm_demux
+ /* Don't change the order of the tests : if b_psi then p_pgrm_demux
* may still be null. Who said it was ugly ?
* I have written worse. --Meuuh */
- if( ( p_es ) &&
- ((p_es->p_decoder_fifo != NULL) || b_psi || b_pcr ) )
+ if( ( p_es ) &&
+ ((p_es->p_dec != NULL) || b_psi || b_pcr || b_dvbsub) )
{
p_es->c_packets++;
{
/* 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 */
* 183 bytes. */
if( b_payload ? (p[4] > 182) : (p[4] != 183) )
{
- msg_Warn( p_input, "invalid TS adaptation field (%p)",
- p_data );
+ msg_Warn( p_input, "invalid TS adaptation field for PID %d (%2x)",
+ i_pid, p[4] );
p_data->b_discard_payload = 1;
p_es->c_invalid_packets++;
+
+ /* The length was invalid so we shouldn't have added it to
+ * p_payload_start above. Ensure p_payload_start has a
+ * valid value by setting it equal to p_payload_end. This
+ * also stops any data being processed from the packet.
+ */
+ p_data->p_payload_start = p_data->p_payload_end;
}
-
+
/* Now we are sure that the byte containing flags is present:
* read it */
else
{
msg_Warn( p_input,
"discontinuity_indicator encountered by TS demux "
- "(position read: %d, saved: %d)",
- p[5] & 0x80, p_es_demux->i_continuity_counter );
-
+ "(PID %d: current %d, packet %d)",
+ i_pid,
+ ( p_es_demux->i_continuity_counter ) & 0x0f,
+ p[3] & 0x0f );
+
/* If the PID carries the PCR, there will be a system
* time-based discontinuity. We let the PCR decoder
* handle that. */
p_es->p_pgrm->i_synchro_state = SYNCHRO_REINIT;
-
- /* There also may be a continuity_counter
- * discontinuity: resynchronize our counter with
- * the one of the stream. */
- p_es_demux->i_continuity_counter = (p[3] & 0x0f) - 1;
+
+ /* Don't resynchronise the counter here - it will
+ * be checked later and b_lost will then be set if
+ * necessary.
+ */
}
-
+
} /* 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 )
+ if( b_payload &&
+ ( i_dummy == 1 || (b_psi && p_stream_demux->b_buggy_psi ) ) )
{
/* Everything is ok, just increase our counter */
(p_es_demux->i_continuity_counter)++;
* the packet. */
b_trash = 1;
}
+ else if( !b_payload )
+ {
+ /* If there is no payload, the counter should be unchanged */
+ msg_Warn( p_input, "packet rxd for PID %d with no payload but "
+ "wrong counter: current %d, packet %d", i_pid,
+ p_es_demux->i_continuity_counter & 0x0f, p[3] & 0x0f );
+ }
else if( i_dummy <= 0 )
{
/* Duplicate packet: mark it as being to be trashed. */
msg_Warn( p_input,
- "duplicate packet received by TS demux" );
+ "duplicate packet received for PID %d (counter %d)",
+ p_es->i_id, p[3] & 0x0f );
b_trash = 1;
}
else if( p_es_demux->i_continuity_counter == 0xFF )
* as we don't know, do as if we missed a packet to be sure
* to recover from this situation */
msg_Warn( p_input,
- "packet lost by TS demux: current %d, packet %d",
+ "packet lost by TS demux for PID %d: current %d, packet %d",
+ i_pid,
p_es_demux->i_continuity_counter & 0x0f,
p[3] & 0x0f );
b_lost = 1;
} /* not continuous */
} /* continuity */
} /* if selected or PCR */
-
+
/* Handle PCR */
if( b_pcr && b_adaptation && (p[5] & 0x10) && p[4]>=7 )
{
( (mtime_t)p[9] << 1 ) |
( (mtime_t)p[10] >> 7 );
/* Call the pace control. */
- for( i_dummy = 0; i_dummy < p_input->stream.i_pgrm_number;
+ for( i_dummy = 0; i_dummy < p_input->stream.i_pgrm_number;
i_dummy ++ )
{
if( ( ( pgrm_ts_data_t * ) p_input->stream.pp_programs[i_dummy]->
}
}
-
+
/* Trash the packet if it has no payload or if it isn't selected */
if( b_trash )
{
else
{
/* The payload carries a PES stream */
- GatherPES( p_input, p_data, p_es, b_unit_start, b_lost );
+ GatherPES( p_input, p_data, p_es, b_unit_start, b_lost );
}
}
#undef p
}
-