#include <vlc_common.h>
#include <vlc_plugin.h>
-#include <ctype.h>
#include <assert.h>
#include <vlc_access.h> /* DVB-specific things */
#include <vlc_iso_lang.h>
#include <vlc_network.h>
#include <vlc_charset.h>
+#include <vlc_fs.h>
#include "../mux/mpeg/csa.h"
# include "tables/eit.h"
# endif
#endif
-#include <time.h>
+
+/* TDT support */
+#ifdef _DVBPSI_DR_58_H_
+# define TS_USE_TDT 1
+# ifdef HAVE_DVBPSI_DR_H
+# include <dvbpsi/tot.h>
+# else
+# include "tables/tot.h"
+# endif
+#else
+# include <time.h>
+#endif
+
#undef TS_DEBUG
/*****************************************************************************
"Tweak the buffer size for reading and writing an integer number of packets." \
"Specify the size of the buffer here and not the number of packets." )
+#define SPLIT_ES_TEXT N_("Separate sub-streams")
+#define SPLIT_ES_LONGTEXT N_( \
+ "Separate teletex/dvbs pages into independent ES. " \
+ "It can be useful to turn off this option when using stream output." )
+
vlc_module_begin ()
set_description( N_("MPEG Transport Stream demuxer") )
set_shortname ( "MPEG-TS" )
add_bool( "ts-dump-append", false, NULL, APPEND_TEXT, APPEND_LONGTEXT, false )
add_integer( "ts-dump-size", 16384, NULL, DUMPSIZE_TEXT,
DUMPSIZE_LONGTEXT, true )
+ add_bool( "ts-split-es", true, NULL, SPLIT_ES_TEXT, SPLIT_ES_LONGTEXT, false )
set_capability( "demux", 10 )
set_callbacks( Open, Close )
bool b_user_pmt;
int i_pmt;
ts_pid_t **pmt;
+ int i_pmt_es;
/* */
bool b_es_id_pid;
csa_t *csa;
int i_csa_pkt_size;
bool b_silent;
+ bool b_split_es;
bool b_udp_out;
int fd; /* udp socket */
/* */
bool b_dvb_meta;
+ int64_t i_tdt_delta;
int64_t i_dvb_start;
int64_t i_dvb_length;
+ bool b_broken_charset; /* True if broken encoding is used in EPG/SDT */
/* */
int i_current_program;
- vlc_list_t *p_programs_list;
+ vlc_list_t programs_list;
/* TS dump */
char *psz_file; /* file to dump data in */
bool b_start_record;
};
-static int i_broken_epg;
-
static int Demux ( demux_t *p_demux );
static int DemuxFile( demux_t *p_demux );
static int Control( demux_t *p_demux, int i_query, va_list args );
static void PIDInit ( ts_pid_t *pid, bool b_psi, ts_psi_t *p_owner );
-static void PIDClean( es_out_t *out, ts_pid_t *pid );
+static void PIDClean( demux_t *, ts_pid_t *pid );
static int PIDFillFormat( ts_pid_t *pid, int i_stream_type );
static void PATCallBack( demux_t *, dvbpsi_pat_t * );
#define TS_USER_PMT_NUMBER (0)
static int UserPmt( demux_t *p_demux, const char * );
+static int SetPIDFilter( demux_t *, int i_pid, bool b_selected );
+static void SetPrgFilter( demux_t *, int i_prg, bool b_selected );
+
#define TS_PACKET_SIZE_188 188
#define TS_PACKET_SIZE_192 192
#define TS_PACKET_SIZE_204 204
msg_Info( p_demux, "dumping raw stream to standard output" );
p_sys->p_file = stdout;
}
- else if( ( p_sys->p_file = utf8_fopen( p_sys->psz_file, psz_mode ) ) == NULL )
+ else if( ( p_sys->p_file = vlc_fopen( p_sys->psz_file, psz_mode ) ) == NULL )
{
msg_Err( p_demux, "cannot create `%s' for writing", p_sys->psz_file );
p_sys->b_file_out = false;
{
p_sys->i_ts_read = 1500 / p_sys->i_packet_size;
}
- p_sys->buffer = malloc( p_sys->i_packet_size * p_sys->i_ts_read );
+ p_sys->buffer = xmalloc( p_sys->i_packet_size * p_sys->i_ts_read );
msg_Info( p_demux, "%s raw stream to file `%s' reading packets %d",
b_append ? "appending" : "dumping", p_sys->psz_file,
p_sys->i_ts_read );
p_sys->b_dvb_meta = true;
p_sys->b_access_control = true;
p_sys->i_current_program = 0;
+ p_sys->programs_list.i_count = 0;
+ p_sys->programs_list.p_values = NULL;
+ p_sys->i_tdt_delta = 0;
p_sys->i_dvb_start = 0;
p_sys->i_dvb_length = 0;
+ p_sys->b_broken_charset = false;
+
for( i = 0; i < 8192; i++ )
{
ts_pid_t *pid = &p_sys->pid[i];
eit->psi->handle =
dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack,
p_demux );
+#ifdef TS_USE_TDT
+ ts_pid_t *tdt = &p_sys->pid[0x14];
+ PIDInit( tdt, true, NULL );
+ tdt->psi->handle =
+ dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack,
+ p_demux );
+#endif
if( p_sys->b_access_control )
{
- if( stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, 0x11, true ) ||
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, 0x12, true ) )
+ if( SetPIDFilter( p_demux, 0x11, true ) ||
+#ifdef TS_USE_TDT
+ SetPIDFilter( p_demux, 0x14, true ) ||
+#endif
+ SetPIDFilter( p_demux, 0x12, true ) )
p_sys->b_access_control = false;
}
}
/* Init PMT array */
TAB_INIT( p_sys->i_pmt, p_sys->pmt );
+ p_sys->i_pmt_es = 0;
/* Read config */
p_sys->b_es_id_pid = var_CreateGetBool( p_demux, "ts-es-id-pid" );
free( psz_string );
p_sys->b_silent = var_CreateGetBool( p_demux, "ts-silent" );
+ p_sys->b_split_es = var_InheritBool( p_demux, "ts-split-es" );
+
+ while( !p_sys->b_file_out && p_sys->i_pmt_es <= 0 &&
+ vlc_object_alive( p_demux ) )
+ {
+ if( p_demux->pf_demux( p_demux ) != 1 )
+ break;
+ }
+
return VLC_SUCCESS;
}
free( pid->psi );
break;
default:
- if( p_sys->b_dvb_meta && ( pid->i_pid == 0x11 || pid->i_pid == 0x12 ) )
+ if( p_sys->b_dvb_meta && ( pid->i_pid == 0x11 || pid->i_pid == 0x12 || pid->i_pid == 0x14 ) )
{
- /* SDT or EIT */
+ /* SDT or EIT or TDT */
dvbpsi_DetachDemux( pid->psi->handle );
free( pid->psi );
}
else
{
- PIDClean( p_demux->out, pid );
+ PIDClean( p_demux, pid );
}
break;
}
}
else if( pid->b_valid && pid->es )
{
- PIDClean( p_demux->out, pid );
+ PIDClean( p_demux, pid );
}
if( pid->b_seen )
msg_Dbg( p_demux, " - pid[%d] seen", pid->i_pid );
}
- if( p_sys->b_access_control && pid->i_pid > 0 )
- {
- /* too much */
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, pid->i_pid,
- false );
- }
+ /* too much */
+ if( pid->i_pid > 0 )
+ SetPIDFilter( p_demux, pid->i_pid, false );
}
vlc_mutex_lock( &p_sys->csa_lock );
TAB_CLEAN( p_sys->i_pmt, p_sys->pmt );
- if( p_sys->p_programs_list )
- {
- vlc_value_t val;
- val.p_list = p_sys->p_programs_list;
- var_FreeList( &val, NULL );
- }
+ free( p_sys->programs_list.p_values );
/* If in dump mode, then close the file */
if( p_sys->b_file_out )
{
- msg_Info( p_demux ,"closing %s (%"PRId64" Kbytes dumped)",
+ msg_Info( p_demux ,"closing %s (%"PRId64" KiB dumped)",
p_sys->psz_file, p_sys->i_write / 1024 );
if( p_sys->p_file != stdout )
static int Demux( demux_t *p_demux )
{
demux_sys_t *p_sys = p_demux->p_sys;
+ bool b_wait_es = p_sys->i_pmt_es <= 0;
/* We read at most 100 TS packet or until a frame is completed */
for( int i_pkt = 0; i_pkt < p_sys->i_ts_read; i_pkt++ )
{
if( p_pid->psi )
{
- if( p_pid->i_pid == 0 || ( p_sys->b_dvb_meta && ( p_pid->i_pid == 0x11 || p_pid->i_pid == 0x12 ) ) )
+ if( p_pid->i_pid == 0 || ( p_sys->b_dvb_meta && ( p_pid->i_pid == 0x11 || p_pid->i_pid == 0x12 || p_pid->i_pid == 0x14 ) ) )
{
dvbpsi_PushPacket( p_pid->psi->handle, p_pkt->p_buffer );
}
}
p_pid->b_seen = true;
- if( b_frame )
+ if( b_frame || ( b_wait_es && p_sys->i_pmt_es > 0 ) )
break;
}
if( pi_time )
*pi_time = 0;
- if( p_sys->b_access_control && p_sys->i_dvb_length > 0 )
+ if( p_sys->i_dvb_length > 0 )
{
- /* FIXME we should not use time() but read the date from the tdt */
- const time_t t = time( NULL );
+#ifdef TS_USE_TDT
+ const int64_t t = mdate() + p_sys->i_tdt_delta;
+#else
+ const int64_t t = CLOCK_FREQ * time ( NULL );
+#endif
+
if( p_sys->i_dvb_start <= t && t < p_sys->i_dvb_start + p_sys->i_dvb_length )
{
if( pi_length )
- *pi_length = p_sys->i_dvb_length * INT64_C(1000000);
+ *pi_length = p_sys->i_dvb_length;
if( pi_time )
- *pi_time = (t - p_sys->i_dvb_start) * INT64_C(1000000);
+ *pi_time = t - p_sys->i_dvb_start;
return VLC_SUCCESS;
}
}
#endif
case DEMUX_SET_GROUP:
{
- uint16_t i_vpid = 0, i_apid1 = 0, i_apid2 = 0, i_apid3 = 0;
- ts_prg_psi_t *p_prg = NULL;
vlc_list_t *p_list;
i_int = (int)va_arg( args, int );
p_list = (vlc_list_t *)va_arg( args, vlc_list_t * );
msg_Dbg( p_demux, "DEMUX_SET_GROUP %d %p", i_int, p_list );
- if( p_sys->b_access_control && i_int > 0 && i_int != p_sys->i_current_program )
- {
- int i_pmt_pid = -1;
-
- /* Search pmt to be unselected */
- for( int i = 0; i < p_sys->i_pmt; i++ )
- {
- ts_pid_t *pmt = p_sys->pmt[i];
-
- for( int i_prg = 0; i_prg < pmt->psi->i_prg; i_prg++ )
- {
- if( pmt->psi->prg[i_prg]->i_number == p_sys->i_current_program )
- {
- i_pmt_pid = p_sys->pmt[i]->i_pid;
- break;
- }
- }
- if( i_pmt_pid > 0 ) break;
- }
-
- if( i_pmt_pid > 0 )
- {
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, i_pmt_pid,
- false );
- /* All ES */
- for( int i = 2; i < 8192; i++ )
- {
- ts_pid_t *pid = &p_sys->pid[i];
-
- if( !pid->b_valid || pid->psi )
- continue;
+ if( i_int == 0 && p_sys->i_current_program > 0 )
+ i_int = p_sys->i_current_program;
- for( int i_prg = 0; i_prg < pid->p_owner->i_prg; i_prg++ )
- {
- if( pid->p_owner->prg[i_prg]->i_pid_pmt == i_pmt_pid && pid->es->id )
- {
- /* We only remove es that aren't defined by extra pmt */
- stream_Control( p_demux->s,
- STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE,
- i, false );
- break;
- }
- }
- }
- }
+ if( p_sys->i_current_program > 0 )
+ {
+ if( p_sys->i_current_program != i_int )
+ SetPrgFilter( p_demux, p_sys->i_current_program, false );
+ }
+ else if( p_sys->i_current_program < 0 )
+ {
+ for( int i = 0; i < p_sys->programs_list.i_count; i++ )
+ SetPrgFilter( p_demux, p_sys->programs_list.p_values[i].i_int, false );
+ }
- /* select new program */
+ if( i_int > 0 )
+ {
p_sys->i_current_program = i_int;
- i_pmt_pid = -1;
- for( int i = 0; i < p_sys->i_pmt; i++ )
+ SetPrgFilter( p_demux, p_sys->i_current_program, true );
+ }
+ else if( i_int < 0 )
+ {
+ p_sys->i_current_program = -1;
+ p_sys->programs_list.i_count = 0;
+ if( p_list )
{
- ts_pid_t *pmt = p_sys->pmt[i];
+ vlc_list_t *p_dst = &p_sys->programs_list;
+ free( p_dst->p_values );
- for( int i_prg = 0; i_prg < pmt->psi->i_prg; i_prg++ )
- {
- if( pmt->psi->prg[i_prg]->i_number == i_int )
- {
- i_pmt_pid = p_sys->pmt[i]->i_pid;
- p_prg = p_sys->pmt[i]->psi->prg[i_prg];
- break;
- }
- }
- if( i_pmt_pid > 0 )
- break;
- }
- if( i_pmt_pid > 0 )
- {
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, i_pmt_pid,
- true );
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, p_prg->i_pid_pcr,
- true );
-
- for( int i = 2; i < 8192; i++ )
+ p_dst->p_values = calloc( p_list->i_count,
+ sizeof(*p_dst->p_values) );
+ if( p_dst->p_values )
{
- ts_pid_t *pid = &p_sys->pid[i];
-
- if( !pid->b_valid || pid->psi )
- continue;
-
- for( int i_prg = 0; i_prg < pid->p_owner->i_prg; i_prg++ )
+ p_dst->i_count = p_list->i_count;
+ for( int i = 0; i < p_list->i_count; i++ )
{
- if( pid->p_owner->prg[i_prg]->i_pid_pmt == i_pmt_pid && pid->es->id )
- {
- if ( pid->es->fmt.i_cat == VIDEO_ES && !i_vpid )
- i_vpid = i;
- if ( pid->es->fmt.i_cat == AUDIO_ES && !i_apid1 )
- i_apid1 = i;
- else if ( pid->es->fmt.i_cat == AUDIO_ES && !i_apid2 )
- i_apid2 = i;
- else if ( pid->es->fmt.i_cat == AUDIO_ES && !i_apid3 )
- i_apid3 = i;
-
- stream_Control( p_demux->s,
- STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE,
- i, true );
- break;
- }
+ p_dst->p_values[i] = p_list->p_values[i];
+ SetPrgFilter( p_demux, p_dst->p_values[i].i_int, true );
}
}
}
}
- else
- {
- p_sys->i_current_program = -1;
- p_sys->p_programs_list = p_list;
- }
return VLC_SUCCESS;
}
(char*)&pid->es->fmt.i_codec );
pid->es->id = es_out_Add( p_demux->out,
&pid->es->fmt );
+ p_sys->i_pmt_es++;
}
}
return VLC_EGENERIC;
}
+static int SetPIDFilter( demux_t *p_demux, int i_pid, bool b_selected )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+
+ if( !p_sys->b_access_control )
+ return VLC_EGENERIC;
+
+ return stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
+ ACCESS_SET_PRIVATE_ID_STATE, i_pid, b_selected );
+}
+
+static void SetPrgFilter( demux_t *p_demux, int i_prg_id, bool b_selected )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ ts_prg_psi_t *p_prg = NULL;
+ int i_pmt_pid = -1;
+
+ /* Search pmt to be unselected */
+ for( int i = 0; i < p_sys->i_pmt; i++ )
+ {
+ ts_pid_t *pmt = p_sys->pmt[i];
+
+ for( int i_prg = 0; i_prg < pmt->psi->i_prg; i_prg++ )
+ {
+ if( pmt->psi->prg[i_prg]->i_number == i_prg_id )
+ {
+ i_pmt_pid = p_sys->pmt[i]->i_pid;
+ p_prg = p_sys->pmt[i]->psi->prg[i_prg];
+ break;
+ }
+ }
+ if( i_pmt_pid > 0 )
+ break;
+ }
+ if( i_pmt_pid <= 0 )
+ return;
+ assert( p_prg );
+
+ SetPIDFilter( p_demux, i_pmt_pid, b_selected );
+ if( p_prg->i_pid_pcr > 0 )
+ SetPIDFilter( p_demux, p_prg->i_pid_pcr, b_selected );
+
+ /* All ES */
+ for( int i = 2; i < 8192; i++ )
+ {
+ ts_pid_t *pid = &p_sys->pid[i];
+
+ if( !pid->b_valid || pid->psi )
+ continue;
+
+ for( int i_prg = 0; i_prg < pid->p_owner->i_prg; i_prg++ )
+ {
+ if( pid->p_owner->prg[i_prg]->i_pid_pmt == i_pmt_pid && pid->es->id )
+ {
+ /* We only remove/select es that aren't defined by extra pmt */
+ SetPIDFilter( p_demux, i, b_selected );
+ break;
+ }
+ }
+ }
+}
+
static void PIDInit( ts_pid_t *pid, bool b_psi, ts_psi_t *p_owner )
{
bool b_old_valid = pid->b_valid;
if( !b_old_valid )
{
- pid->psi = malloc( sizeof( ts_psi_t ) );
+ pid->psi = xmalloc( sizeof( ts_psi_t ) );
if( pid->psi )
{
pid->psi->handle = NULL;
}
}
-static void PIDClean( es_out_t *out, ts_pid_t *pid )
+static void PIDClean( demux_t *p_demux, ts_pid_t *pid )
{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ es_out_t *out = p_demux->out;
+
if( pid->psi )
{
if( pid->psi->handle )
else
{
if( pid->es->id )
+ {
es_out_Del( out, pid->es->id );
+ p_sys->i_pmt_es--;
+ }
if( pid->es->p_pes )
block_ChainRelease( pid->es->p_pes );
for( int i = 0; i < pid->i_extra_es; i++ )
{
if( pid->extra_es[i]->id )
+ {
es_out_Del( out, pid->extra_es[i]->id );
+ p_sys->i_pmt_es--;
+ }
if( pid->extra_es[i]->p_pes )
block_ChainRelease( pid->extra_es[i]->p_pes );
int i;
if( i_dts >= 0 )
- {
- p_pes->i_dts = i_dts * 100 / 9;
- }
+ p_pes->i_dts = VLC_TS_0 + i_dts * 100 / 9;
+
if( i_pts >= 0 )
- {
- p_pes->i_pts = i_pts * 100 / 9;
- }
+ p_pes->i_pts = VLC_TS_0 + i_pts * 100 / 9;
+
p_pes->i_length = i_length * 100 / 9;
p_block = block_ChainGather( p_pes );
demux_sys_t *p_sys = p_demux->p_sys;
const uint8_t *p = p_bk->p_buffer;
+ if( p_sys->i_pmt_es <= 0 )
+ return;
+
if( ( p[3]&0x20 ) && /* adaptation */
( p[5]&0x10 ) &&
( p[4] >= 7 ) )
{
es_out_Control( p_demux->out, ES_OUT_SET_GROUP_PCR,
(int)p_sys->pmt[i]->psi->prg[i_prg]->i_number,
- (int64_t)(i_pcr * 100 / 9) );
+ (int64_t)(VLC_TS_0 + i_pcr * 100 / 9) );
}
}
}
pid->i_cc = i_cc;
if( pid->es->p_pes && pid->es->fmt.i_cat != VIDEO_ES )
{
- /* Small video artifacts are usually better then
+ /* Small video artifacts are usually better than
* dropping full frames */
pid->es->p_pes->i_flags |= BLOCK_FLAG_CORRUPTED;
}
case 0x04: /* MPEG-2 audio */
es_format_Init( fmt, AUDIO_ES, VLC_CODEC_MPGA );
break;
- case 0x11: /* MPEG4 (audio) */
+ case 0x11: /* MPEG4 (audio) LATM */
case 0x0f: /* ISO/IEC 13818-7 Audio with ADTS transport syntax */
es_format_Init( fmt, AUDIO_ES, VLC_CODEC_MP4A );
break;
case 0x85: /* DTS (audio) */
es_format_Init( fmt, AUDIO_ES, VLC_CODEC_DTS );
break;
+ case 0x87: /* E-AC3 */
+ es_format_Init( fmt, AUDIO_ES, VLC_CODEC_EAC3 );
+ break;
case 0x91: /* A52 vls (audio) */
es_format_Init( fmt, AUDIO_ES, VLC_FOURCC( 'a', '5', '2', 'b' ) );
{
demux_sys_t *p_sys = p_demux->p_sys;
- if( !p_sys->b_access_control )
- return false;
- if( ( p_sys->i_current_program == -1 && p_sys->p_programs_list == NULL ) ||
+ if( ( p_sys->i_current_program == -1 && p_sys->programs_list.i_count == 0 ) ||
p_sys->i_current_program == 0 )
return true;
if( p_sys->i_current_program == i_pgrm )
return true;
- if( p_sys->p_programs_list != NULL )
+ if( p_sys->programs_list.i_count != 0 )
{
- for( int i = 0; i < p_sys->p_programs_list->i_count; i++ )
+ for( int i = 0; i < p_sys->programs_list.i_count; i++ )
{
- if( i_pgrm == p_sys->p_programs_list->p_values[i].i_int )
+ if( i_pgrm == p_sys->programs_list.p_values[i].i_int )
return true;
}
}
{
demux_sys_t *p_sys = p_demux->p_sys;
- if( !p_sys->b_dvb_meta || ( i_pid != 0x11 && i_pid != 0x12 ) )
+ if( !p_sys->b_dvb_meta || ( i_pid != 0x11 && i_pid != 0x12 && i_pid != 0x14 ) )
return;
msg_Warn( p_demux, "Switching to non DVB mode" );
/* This doesn't look like a DVB stream so don't try
- * parsing the SDT/EDT */
+ * parsing the SDT/EDT/TDT */
- for( int i = 0x11; i <= 0x12; i++ )
+ for( int i = 0x11; i <= 0x14; i++ )
{
+ if( i == 0x13 ) continue;
ts_pid_t *p_pid = &p_sys->pid[i];
if( p_pid->psi )
{
p_pid->psi = NULL;
p_pid->b_valid = false;
}
- if( p_sys->b_access_control )
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, i, false );
-
+ SetPIDFilter( p_demux, i, false );
}
p_sys->b_dvb_meta = false;
}
#ifdef TS_USE_DVB_SI
/* FIXME same than dvbsi_to_utf8 from dvb access */
static char *EITConvertToUTF8( const unsigned char *psz_instring,
- size_t i_length )
+ size_t i_length,
+ bool b_broken )
{
const char *psz_encoding;
char *psz_outstring;
{
/* According to ETSI EN 300 468 Annex A, this should be ISO6937,
* but some broadcasters use different charset... */
- if ( i_broken_epg == 1 )
- {
+ if( b_broken )
psz_encoding = "ISO_8859-1";
- }
else
- {
psz_encoding = "ISO_6937";
- }
offset = 0;
}
vlc_iconv_close( iconv_handle );
*psz_out = '\0';
+
+ /* Convert EIT-coded CR/LFs */
+ unsigned char *pbuf = (unsigned char *)psz_outstring;
+ for( ; pbuf < (unsigned char *)psz_out ; pbuf++)
+ {
+ if( pbuf[0] == 0xc2 && pbuf[1] == 0x8a )
+ {
+ pbuf[0] = ' ';
+ pbuf[1] = '\n';
+ }
+ }
+
+
}
return psz_outstring;
}
p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
p_sdt->i_network_id );
- i_broken_epg = 0;
+ p_sys->b_broken_charset = false;
for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
{
p_srv->b_eit_present, p_srv->i_running_status,
p_srv->b_free_ca );
- if( p_sys->i_current_program != -1 && p_sys->i_current_program != p_srv->i_service_id )
- continue;
-
p_meta = vlc_meta_New();
for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
{
/* Workarounds for broadcasters with broken EPG */
- if ( p_sdt->i_network_id == 133 )
- i_broken_epg = 1; /* SKY DE & BetaDigital use ISO8859-1 */
+ if( p_sdt->i_network_id == 133 )
+ p_sys->b_broken_charset = true; /* SKY DE & BetaDigital use ISO8859-1 */
- if ( (pD->i_service_provider_name_length == 4) &&
- !strncmp(pD->i_service_provider_name, "CSAT", 4) )
- i_broken_epg = 1; /* CanalSat FR uses ISO8859-1 */
+ /* List of providers using ISO8859-1 */
+ static const char ppsz_broken_providers[][8] = {
+ "CSAT", /* CanalSat FR */
+ "GR1", /* France televisions */
+ "MULTI4", /* NT1 */
+ "MR5", /* France 2/M6 HD */
+ ""
+ };
+ for( int i = 0; *ppsz_broken_providers[i]; i++ )
+ {
+ const size_t i_length = strlen(ppsz_broken_providers[i]);
+ if( pD->i_service_provider_name_length == i_length &&
+ !strncmp( pD->i_service_provider_name, ppsz_broken_providers[i], i_length ) )
+ p_sys->b_broken_charset = true;
+ }
/* FIXME: Digital+ ES also uses ISO8859-1 */
str1 = EITConvertToUTF8(pD->i_service_provider_name,
- pD->i_service_provider_name_length);
+ pD->i_service_provider_name_length,
+ p_sys->b_broken_charset );
str2 = EITConvertToUTF8(pD->i_service_name,
- pD->i_service_name_length);
+ pD->i_service_name_length,
+ p_sys->b_broken_charset );
msg_Dbg( p_demux, " - type=%d provider=%s name=%s",
pD->i_service_type, str1, str2 );
}
#undef CVT_FROM_BCD
+#ifdef TS_USE_TDT
+static void TDTCallBack( demux_t *p_demux, dvbpsi_tot_t *p_tdt )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+
+ p_sys->i_tdt_delta = CLOCK_FREQ * EITConvertStartTime( p_tdt->i_utc_time )
+ - mdate();
+ dvbpsi_DeleteTOT(p_tdt);
+}
+#endif
+
static void EITCallBack( demux_t *p_demux,
dvbpsi_eit_t *p_eit, bool b_current_following )
vlc_epg_t *p_epg;
msg_Dbg( p_demux, "EITCallBack called" );
- if( !p_eit->b_current_next || ( p_sys->i_current_program != -1 && p_sys->i_current_program != p_eit->i_service_id ) )
+ if( !p_eit->b_current_next )
{
dvbpsi_DeleteEIT( p_eit );
return;
{
dvbpsi_short_event_dr_t *pE = dvbpsi_DecodeShortEventDr( p_dr );
- if( pE )
+ /* Only take first description, as we don't handle language-info
+ for epg atm*/
+ if( pE && psz_name == NULL)
{
- psz_name = EITConvertToUTF8( pE->i_event_name, pE->i_event_name_length);
- psz_text = EITConvertToUTF8( pE->i_text, pE->i_text_length );
+ psz_name = EITConvertToUTF8( pE->i_event_name, pE->i_event_name_length,
+ p_sys->b_broken_charset );
+ psz_text = EITConvertToUTF8( pE->i_text, pE->i_text_length,
+ p_sys->b_broken_charset );
msg_Dbg( p_demux, " - short event lang=%3.3s '%s' : '%s'",
pE->i_iso_639_code, psz_name, psz_text );
}
if( pE->i_text_length > 0 )
{
- char *psz_text = EITConvertToUTF8( pE->i_text, pE->i_text_length );
+ char *psz_text = EITConvertToUTF8( pE->i_text, pE->i_text_length,
+ p_sys->b_broken_charset );
if( psz_text )
{
msg_Dbg( p_demux, " - text='%s'", psz_text );
- psz_extra = realloc( psz_extra, strlen(psz_extra) + strlen(psz_text) + 1 );
+ psz_extra = xrealloc( psz_extra,
+ strlen(psz_extra) + strlen(psz_text) + 1 );
strcat( psz_extra, psz_text );
free( psz_text );
}
for( int i = 0; i < pE->i_entry_count; i++ )
{
char *psz_dsc = EITConvertToUTF8( pE->i_item_description[i],
- pE->i_item_description_length[i] );
- char *psz_itm = EITConvertToUTF8( pE->i_item[i], pE->i_item_length[i] );
+ pE->i_item_description_length[i],
+ p_sys->b_broken_charset );
+ char *psz_itm = EITConvertToUTF8( pE->i_item[i], pE->i_item_length[i],
+ p_sys->b_broken_charset );
if( psz_dsc && psz_itm )
{
msg_Dbg( p_demux, " - desc='%s' item='%s'", psz_dsc, psz_itm );
#if 0
- psz_extra = realloc( psz_extra, strlen(psz_extra) + strlen(psz_dsc) + strlen(psz_itm) + 3 + 1 );
+ psz_extra = xrealloc( psz_extra,
+ strlen(psz_extra) + strlen(psz_dsc) +
+ strlen(psz_itm) + 3 + 1 );
strcat( psz_extra, "(" );
strcat( psz_extra, psz_dsc );
strcat( psz_extra, " " );
}
if( p_epg->i_event > 0 )
{
- if( p_eit->i_service_id == p_sys->i_current_program && b_current_following )
+ if( b_current_following &&
+ ( p_sys->i_current_program == -1 ||
+ p_sys->i_current_program == p_eit->i_service_id ) )
{
p_sys->i_dvb_length = 0;
p_sys->i_dvb_start = 0;
if( p_epg->p_current )
{
- p_sys->i_dvb_start = p_epg->p_current->i_start;
- p_sys->i_dvb_length = p_epg->p_current->i_duration;
+ p_sys->i_dvb_start = CLOCK_FREQ * p_epg->p_current->i_start;
+ p_sys->i_dvb_length = CLOCK_FREQ * p_epg->p_current->i_duration;
}
}
es_out_Control( p_demux->out, ES_OUT_SET_GROUP_EPG, p_eit->i_service_id, p_epg );
(dvbpsi_eit_callback)EITCallBackSchedule;
dvbpsi_AttachEIT( h, i_table_id, i_extension, cb, p_demux );
}
+#ifdef TS_USE_TDT
+ else if( p_demux->p_sys->pid[0x11].psi->i_sdt_version != -1 &&
+ i_table_id == 0x70 ) /* TDT */
+ {
+ msg_Dbg( p_demux, "PSINewTableCallBack: table 0x%x(%d) ext=0x%x(%d)",
+ i_table_id, i_table_id, i_extension, i_extension );
+ dvbpsi_AttachTOT( h, i_table_id, i_extension,
+ (dvbpsi_tot_callback)TDTCallBack, p_demux);
+ }
+#endif
+
}
#endif
ts_teletext_page_t p_page[2 * 64 + 20];
unsigned i_page = 0;
- /* Gather pages informations */
+ /* Gather pages information */
#if defined _DVBPSI_DR_56_H_ && \
defined DVBPSI_VERSION && DVBPSI_VERSION_INT > ((0<<16)+(1<<8)+5)
for( unsigned i_tag_idx = 0; i_tag_idx < 2; i_tag_idx++ )
/* */
es_format_Init( p_fmt, SPU_ES, VLC_CODEC_TELETEXT );
- /* In stream output mode, do not separate the stream by page */
- if( p_demux->out->b_sout || i_page <= 0 )
+ if( !p_demux->p_sys->b_split_es || i_page <= 0 )
{
p_fmt->subs.teletext.i_magazine = -1;
p_fmt->subs.teletext.i_page = 0;
if( !p_dr )
p_dr = PMTEsFindDescriptor( p_es, 0x56 );
- if( p_demux->out->b_sout && p_dr && p_dr->i_length > 0 )
+ if( !p_demux->p_sys->b_split_es && p_dr && p_dr->i_length > 0 )
{
- /* Descriptor pass-through for sout */
+ /* Descriptor pass-through */
p_fmt->p_extra = malloc( p_dr->i_length );
if( p_fmt->p_extra )
{
/* */
const ts_teletext_page_t *p = &p_page[i];
+ p_es->fmt.i_priority = (p->i_type == 0x02 || p->i_type == 0x05) ? 0 : -1;
p_es->fmt.psz_language = strndup( p->p_iso639, 3 );
p_es->fmt.psz_description = strdup(vlc_gettext(ppsz_teletext_type[p->i_type]));
p_es->fmt.subs.teletext.i_magazine = p->i_magazine;
}
#endif
- /* In stream output mode, do not separate the stream by page */
- if( p_demux->out->b_sout || i_page <= 0 )
+ if( !p_demux->p_sys->b_split_es || i_page <= 0 )
{
p_fmt->subs.dvb.i_id = -1;
p_fmt->psz_description = strdup( _("DVB subtitles") );
- if( p_demux->out->b_sout && p_dr && p_dr->i_length > 0 )
+ if( !p_demux->p_sys->b_split_es && p_dr && p_dr->i_length > 0 )
{
- /* Descriptor pass-through for sout */
+ /* Descriptor pass-through */
p_fmt->p_extra = malloc( p_dr->i_length );
if( p_fmt->p_extra )
{
}
#ifdef _DVBPSI_DR_52_H_
- /* FIXME is it usefull ? */
+ /* FIXME is it useful ? */
if( PMTEsFindDescriptor( p_es, 0x52 ) )
{
dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, 0x52 );
break;
case 0x84: /* E-AC3 */
- case 0x87: /* E-AC3 */
case 0xA1: /* Secondary E-AC3 */
p_fmt->i_cat = AUDIO_ES;
p_fmt->i_codec = VLC_CODEC_EAC3;
break;
}
}
+
+static void PMTSetupEsRegistration( demux_t *p_demux, ts_pid_t *pid,
+ const dvbpsi_pmt_es_t *p_es )
+{
+ static const struct
+ {
+ char psz_tag[5];
+ int i_cat;
+ vlc_fourcc_t i_codec;
+ } p_regs[] = {
+ { "AC-3", AUDIO_ES, VLC_CODEC_A52 },
+ { "DTS1", AUDIO_ES, VLC_CODEC_DTS },
+ { "DTS2", AUDIO_ES, VLC_CODEC_DTS },
+ { "DTS3", AUDIO_ES, VLC_CODEC_DTS },
+ { "BSSD", AUDIO_ES, VLC_CODEC_302M },
+ { "VC-1", VIDEO_ES, VLC_CODEC_VC1 },
+ { "drac", VIDEO_ES, VLC_CODEC_DIRAC },
+ { "", UNKNOWN_ES, 0 }
+ };
+ es_format_t *p_fmt = &pid->es->fmt;
+
+ for( int i = 0; p_regs[i].i_cat != UNKNOWN_ES; i++ )
+ {
+ if( PMTEsHasRegistration( p_demux, p_es, p_regs[i].psz_tag ) )
+ {
+ p_fmt->i_cat = p_regs[i].i_cat;
+ p_fmt->i_codec = p_regs[i].i_codec;
+ break;
+ }
+ }
+}
+
static void PMTParseEsIso639( demux_t *p_demux, ts_pid_t *pid,
const dvbpsi_pmt_es_t *p_es )
{
switch( p_decoded->code[0].i_audio_type )
{
case 0:
+ pid->es->fmt.i_priority = 1; // prioritize normal audio tracks
pid->es->fmt.psz_description = NULL;
break;
case 1:
if( ProgramIsSelected( p_demux, prg->i_number ) )
{
/* Set demux filter */
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, prg->i_pid_pcr,
- true );
- }
- else if ( p_sys->b_access_control )
- {
- msg_Warn( p_demux, "skipping program (not selected)" );
- dvbpsi_DeletePMT(p_pmt);
- return;
+ SetPIDFilter( p_demux, prg->i_pid_pcr, true );
}
/* Parse descriptor */
{
PMTSetupEsHDMV( p_demux, pid, p_es );
}
+ else if( p_es->i_type >= 0x80 )
+ {
+ PMTSetupEsRegistration( p_demux, pid, p_es );
+ }
if( pid->es->fmt.i_cat == AUDIO_ES ||
( pid->es->fmt.i_cat == SPU_ES &&
{
if( old_pid )
{
- PIDClean( p_demux->out, old_pid );
+ PIDClean( p_demux, old_pid );
TAB_REMOVE( i_clean, pp_clean, old_pid );
old_pid = 0;
}
pid->extra_es[i]->id =
es_out_Add( p_demux->out, &pid->extra_es[i]->fmt );
}
+ p_sys->i_pmt_es += 1 + pid->i_extra_es;
}
}
/* Add ES to the list */
if( old_pid )
{
- PIDClean( p_demux->out, old_pid );
+ PIDClean( p_demux, old_pid );
TAB_REMOVE( i_clean, pp_clean, old_pid );
}
p_sys->pid[p_es->i_pid] = *pid;
( pid->es->id != NULL || p_sys->b_udp_out ) )
{
/* Set demux filter */
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, p_es->i_pid,
- true );
+ SetPIDFilter( p_demux, p_es->i_pid, true );
}
}
- if( ProgramIsSelected( p_demux, prg->i_number ) )
- {
- /* Set CAM descrambling */
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_CA, p_pmt );
- }
- else
- {
+ /* Set CAM descrambling */
+ if( !ProgramIsSelected( p_demux, prg->i_number )
+ || stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
+ ACCESS_SET_PRIVATE_ID_CA, p_pmt ) != VLC_SUCCESS )
dvbpsi_DeletePMT( p_pmt );
- }
for( int i = 0; i < i_clean; i++ )
{
if( ProgramIsSelected( p_demux, prg->i_number ) )
{
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, pp_clean[i]->i_pid,
- false );
+ SetPIDFilter( p_demux, pp_clean[i]->i_pid, false );
}
- PIDClean( p_demux->out, pp_clean[i] );
+ PIDClean( p_demux, pp_clean[i] );
}
if( i_clean )
free( pp_clean );
if( pid->p_owner->prg[i_prg]->i_pid_pmt != pmt_rm[j]->i_pid )
continue;
- if( p_sys->b_access_control && pid->es->id )
- {
- if( stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, i,
- false ) )
- p_sys->b_access_control = false;
- }
+ if( pid->es->id )
+ SetPIDFilter( p_demux, i, false );
- PIDClean( p_demux->out, pid );
+ PIDClean( p_demux, pid );
break;
}
}
/* Delete PMT pid */
for( int i = 0; i < i_pmt_rm; i++ )
{
- if( p_sys->b_access_control )
- {
- if( stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE,
- pmt_rm[i]->i_pid, false ) )
- p_sys->b_access_control = false;
- }
+ SetPIDFilter( p_demux, pmt_rm[i]->i_pid, false );
for( int i_prg = 0; i_prg < pmt_rm[i]->psi->i_prg; i_prg++ )
{
es_out_Control( p_demux->out, ES_OUT_DEL_GROUP, i_number );
}
- PIDClean( p_demux->out, &p_sys->pid[pmt_rm[i]->i_pid] );
+ PIDClean( p_demux, &p_sys->pid[pmt_rm[i]->i_pid] );
TAB_REMOVE( p_sys->i_pmt, p_sys->pmt, pmt_rm[i] );
}
p_program->i_pid;
/* Now select PID at access level */
- if( p_sys->b_access_control )
+ if( ProgramIsSelected( p_demux, p_program->i_number ) )
{
- if( ProgramIsSelected( p_demux, p_program->i_number ) )
- {
- if( p_sys->i_current_program == 0 )
- p_sys->i_current_program = p_program->i_number;
+ if( p_sys->i_current_program == 0 )
+ p_sys->i_current_program = p_program->i_number;
- if( stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE,
- p_program->i_pid, true ) )
- p_sys->b_access_control = false;
- }
+ if( SetPIDFilter( p_demux, p_program->i_pid, true ) )
+ p_sys->b_access_control = false;
}
}
}