From: Christophe Massiot Date: Thu, 15 Sep 2005 16:41:26 +0000 (+0000) Subject: * modules/mux/mpeg/ts.c: Support for SDT and multiple PMTs, original X-Git-Tag: 0.8.4~497 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=b879e009016c67b3d242f5d2fd6b42d8278f2987;p=vlc * modules/mux/mpeg/ts.c: Support for SDT and multiple PMTs, original patch courtesy of Wallace Wadge (thanks!). --- diff --git a/THANKS b/THANKS index a3d27e5e94..dada15f94e 100644 --- a/THANKS +++ b/THANKS @@ -108,6 +108,7 @@ Vicente Jimenez Aguilar - Spanish translation Vitalijus Slavinskas - nsv patches Vladimir Chernyshov - MMX motion optimizations Wade Majors - BeOS icon integration, debugging and fixes +Wallace Wadge - multiple programs TS mux Watanabe Go - fix for non-ASCII filenames Xavier Maillard - audio converters Xavier Marchesini - Win32 fixes diff --git a/configure.ac b/configure.ac index 5ce3520298..d5ce09069b 100644 --- a/configure.ac +++ b/configure.ac @@ -325,7 +325,7 @@ CPPFLAGS_save="${CPPFLAGS_save} -DSYS_`echo ${SYS} | sed -e 's/-.*//' | tr 'abcd dnl Check for system libs needed need_libc=false -AC_CHECK_FUNCS(gettimeofday select strerror strtod strtol strtof strtoll strtoull strsep isatty vasprintf asprintf swab sigrelse getpwuid memalign posix_memalign if_nametoindex atoll getenv putenv setenv gmtime_r ctime_r localtime_r lrintf daemon scandir fork) +AC_CHECK_FUNCS(gettimeofday select strerror strtod strtol strtof strtoll strtoull strsep isatty vasprintf asprintf swab sigrelse getpwuid memalign posix_memalign if_nametoindex atoll getenv putenv setenv gmtime_r ctime_r localtime_r lrintf daemon scandir fork bsearch) dnl Check for usual libc functions AC_CHECK_FUNCS(strdup strndup atof) diff --git a/modules/mux/mpeg/ts.c b/modules/mux/mpeg/ts.c index cfc0a70a4a..3df5a86995 100644 --- a/modules/mux/mpeg/ts.c +++ b/modules/mux/mpeg/ts.c @@ -7,6 +7,7 @@ * Authors: Laurent Aimar * Eric Petit * Jean-Paul Saman + * Wallace Wadge * * 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 @@ -40,16 +41,20 @@ #ifdef HAVE_DVBPSI_DR_H # include +# include # include # include # include +# include # include # include #else # include "dvbpsi.h" +# include "demux.h" # include "descriptor.h" # include "tables/pat.h" # include "tables/pmt.h" +# include "tables/sdt.h" # include "descriptors/dr.h" # include "psi.h" #endif @@ -86,8 +91,15 @@ static void Close ( vlc_object_t * ); #define PMTPID_LONGTEXT N_("Assigns a fixed PID to the PMT") #define TSID_TEXT N_("TS ID") #define TSID_LONGTEXT N_("Assigns a fixed Transport Stream ID.") -#define PMTPROG_TEXT N_("PMT Program number") -#define PMTPROG_LONGTEXT N_("Assigns a program number to the PMT.") +#define NETID_TEXT N_("NET ID") +#define NETID_LONGTEXT N_("Assigns a fixed Network ID (for SDT table)") +#define PMTPROG_TEXT N_("PMT Program numbers (requires --sout-ts-es-id-pid)") +#define PMTPROG_LONGTEXT N_("Assigns a program number to each PMT") +#define MUXPMT_TEXT N_("Mux PMT (requires --sout-ts-es-id-pid)") +#define MUXPMT_LONGTEXT N_("Defines the pids to add to each pmt." ) + +#define SDTDESC_TEXT N_("SDT Descriptors (requires --sout-ts-es-id-pid)") +#define SDTDESC_LONGTEXT N_("Defines the descriptors of each SDT" ) #define PID_TEXT N_("Set PID to id of ES") #define PID_LONGTEXT N_("set PID to id of es") @@ -137,6 +149,12 @@ static void Close ( vlc_object_t * ); "encrypting. " ) #define SOUT_CFG_PREFIX "sout-ts-" +#ifdef HAVE_BSEARCH +# define MAX_PMT 64 /* Maximum number of programs. FIXME: I just chose an arbitary number. Where is the maximum in the spec? */ +#else +# define MAX_PMT 1 +#endif +#define MAX_PMT_PID 64 /* Maximum pids in each pmt. FIXME: I just chose an arbitary number. Where is the maximum in the spec? */ vlc_module_begin(); set_description( _("TS muxer (libdvbpsi)") ); @@ -156,10 +174,14 @@ vlc_module_begin(); PMTPID_LONGTEXT, VLC_TRUE ); add_integer( SOUT_CFG_PREFIX "tsid", 0, NULL, TSID_TEXT, TSID_LONGTEXT, VLC_TRUE ); - add_integer( SOUT_CFG_PREFIX "program-pmt", 1, NULL, PMTPROG_TEXT, - PMTPROG_LONGTEXT, VLC_TRUE ); + add_integer( SOUT_CFG_PREFIX "netid", 0, NULL, NETID_TEXT, + NETID_LONGTEXT, VLC_TRUE ); + add_string( SOUT_CFG_PREFIX "program-pmt", NULL, NULL, PMTPROG_TEXT, + PMTPROG_LONGTEXT, VLC_TRUE ); add_bool( SOUT_CFG_PREFIX "es-id-pid", 0, NULL, PID_TEXT, PID_LONGTEXT, VLC_TRUE ); + add_string( SOUT_CFG_PREFIX "muxpmt", NULL, NULL, MUXPMT_TEXT, MUXPMT_LONGTEXT, VLC_TRUE ); + add_string( SOUT_CFG_PREFIX "sdtdesc", NULL, NULL, SDTDESC_TEXT, SDTDESC_LONGTEXT, VLC_TRUE ); add_integer( SOUT_CFG_PREFIX "shaping", 200, NULL,SHAPING_TEXT, SHAPING_LONGTEXT, VLC_TRUE ); @@ -191,12 +213,25 @@ vlc_module_end(); * Local data structures *****************************************************************************/ static const char *ppsz_sout_options[] = { - "pid-video", "pid-audio", "pid-spu", "pid-pmt", "tsid", "program-pmt", + "pid-video", "pid-audio", "pid-spu", "pid-pmt", "tsid", "netid", "es-id-pid", "shaping", "pcr", "bmin", "bmax", "use-key-frames", "dts-delay", "csa-ck", "csa-pkt", "crypt-audio", "crypt-video", + "muxpmt", "sdtdesc", "program-pmt", NULL }; +typedef struct pmt_map_t /* Holds the mapping between the pmt-pid/pmt table */ +{ + int i_pid; + unsigned long i_prog; +} pmt_map_t; + +typedef struct sdt_desc_t +{ + char *psz_provider; + char *psz_service_name; /* name of program */ +} sdt_desc_t; + typedef struct { int i_depth; @@ -302,22 +337,30 @@ struct sout_mux_sys_t int i_video_bound; vlc_bool_t b_es_id_pid; + vlc_bool_t b_sdt; int i_pid_video; int i_pid_audio; int i_pid_spu; int i_pid_free; /* first usable pid */ int i_tsid; + int i_netid; + int i_num_pmt; + int i_pmtslots; int i_pat_version_number; ts_stream_t pat; int i_pmt_version_number; - ts_stream_t pmt; /* Up to now only one program */ - int i_pmt_program_number; + ts_stream_t pmt[MAX_PMT]; + pmt_map_t pmtmap[MAX_PMT_PID]; + int i_pmt_program_number[MAX_PMT]; + sdt_desc_t sdt_descriptors[MAX_PMT]; int i_mpeg4_streams; int i_null_continuity_counter; /* Needed ? */ + ts_stream_t sdt; + dvbpsi_pmt_t *dvbpmt; /* for TS building */ int64_t i_bitrate_min; @@ -364,6 +407,26 @@ static int AllocatePID( sout_mux_sys_t *p_sys, int i_cat ) return i_pid; } +static int pmtcompare( const void *pa, const void *pb ) +{ + if ( ((pmt_map_t *)pa)->i_pid < ((pmt_map_t *)pb)->i_pid ) + return -1; + else if ( ((pmt_map_t *)pa)->i_pid > ((pmt_map_t *)pb)->i_pid ) + return 1; + else + return 0; +} + +static int intcompare( const void *pa, const void *pb ) +{ + if ( *(int *)pa < *(int *)pb ) + return -1; + else if ( *(int *)pa > *(int *)pb ) + return 1; + else + return 0; +} + /***************************************************************************** * Local prototypes *****************************************************************************/ @@ -393,13 +456,17 @@ static int Open( vlc_object_t *p_this ) sout_mux_t *p_mux =(sout_mux_t*)p_this; sout_mux_sys_t *p_sys = NULL; vlc_value_t val; + int i; - msg_Dbg( p_mux, "Open" ); sout_CfgParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg ); p_sys = malloc( sizeof( sout_mux_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; + p_sys->i_pmtslots = p_sys->b_sdt = 0; + p_sys->i_num_pmt = 1; + p_sys->dvbpmt = NULL; + memset( &p_sys->pmtmap, 0, sizeof(p_sys->pmtmap) ); p_mux->pf_control = Control; p_mux->pf_addstream = AddStream; @@ -408,10 +475,68 @@ static int Open( vlc_object_t *p_this ) p_mux->p_sys = p_sys; srand( (uint32_t)mdate() ); + for ( i = 0; i < MAX_PMT; i++ ) + p_sys->sdt_descriptors[i].psz_service_name + = p_sys->sdt_descriptors[i].psz_provider = NULL; + memset( p_sys->sdt_descriptors, 0, sizeof(sdt_desc_t) ); p_sys->i_audio_bound = 0; p_sys->i_video_bound = 0; + var_Get( p_mux, SOUT_CFG_PREFIX "es-id-pid", &val ); + p_sys->b_es_id_pid = val.b_bool; + + var_Get( p_mux, SOUT_CFG_PREFIX "muxpmt", &val ); + /* + fetch string of pmts. Here's a sample: --sout-ts-muxpmt="0x451,0x200,0x28a,0x240,,0x450,0x201,0x28b,0x241,,0x452,0x202,0x28c,0x242" + This would mean 0x451, 0x200, 0x28a, 0x240 would fall under one pmt (program), 0x450,0x201,0x28b,0x241 would fall under another + */ + if( val.psz_string != NULL && *val.psz_string ) + { + char *psz_next; + char *psz = val.psz_string; + uint16_t i_pid; + psz_next = psz; + + while( psz != NULL ) + { + i_pid = strtoul( psz, &psz_next, 0 ); + + if ( strlen(psz_next) > 0 ) + psz = &psz_next[1]; + if ( i_pid == 0 ) + { + p_sys->i_num_pmt++; + if ( p_sys->i_num_pmt > MAX_PMT ) + { + msg_Err( p_mux, + "Number of PMTs greater than compiled maximum (%d)", MAX_PMT ); + p_sys->i_num_pmt = MAX_PMT; + } + } + else + { + p_sys->pmtmap[p_sys->i_pmtslots].i_pid = i_pid; + p_sys->pmtmap[p_sys->i_pmtslots].i_prog = p_sys->i_num_pmt - 1; + p_sys->i_pmtslots++; + if ( p_sys->i_pmtslots > MAX_PMT_PID ) + { + msg_Err( p_mux, + "Number of pids in PMT greater than compiled maximum (%d)", + MAX_PMT_PID ); + p_sys->i_pmtslots = MAX_PMT_PID; + } + } + + /* Now sort according to pids for fast search later on */ + qsort( (void *)p_sys->pmtmap, p_sys->i_pmtslots, + sizeof(pmt_map_t), &pmtcompare ); + if ( !*psz_next ) + psz = NULL; + } + } + if( val.psz_string != NULL) free( val.psz_string ); + p_sys->i_pat_version_number = rand() % 32; p_sys->pat.i_pid = 0; p_sys->pat.i_continuity_counter = 0; @@ -421,33 +546,103 @@ static int Open( vlc_object_t *p_this ) p_sys->i_tsid = val.i_int; else p_sys->i_tsid = rand() % 65536; + var_Get( p_mux, SOUT_CFG_PREFIX "netid", &val ); + if ( val.i_int ) + p_sys->i_netid = val.i_int; + else + p_sys->i_netid = rand() % 65536; p_sys->i_pmt_version_number = rand() % 32; - p_sys->pmt.i_continuity_counter = 0; + p_sys->sdt.i_continuity_counter = 0; + + for( i = 0; i < p_sys->i_num_pmt; i++ ) + p_sys->pmt[i].i_continuity_counter = 0; + + var_Get( p_mux, SOUT_CFG_PREFIX "sdtdesc", &val ); + p_sys->b_sdt = val.psz_string && *val.psz_string ? VLC_TRUE : VLC_FALSE; + + /* Syntax is provider_sdt1,service_name_sdt1,provider_sdt2,service_name_sdt2... */ + if( val.psz_string != NULL && *val.psz_string ) + { + + char *psz = val.psz_string; + char *psz_sdttoken = psz; + + i = 0; + while ( psz_sdttoken != NULL ) + { + char *psz_end = strchr( psz_sdttoken, ',' ); + if( psz_end != NULL ) + { + *psz_end++ = '\0'; + } + if ( !(i % 2) ) + { + p_sys->sdt_descriptors[i/2].psz_provider + = strdup(psz_sdttoken); + } + else + { + p_sys->sdt_descriptors[i/2].psz_service_name + = strdup(psz_sdttoken); + } + + i++; + psz_sdttoken = psz_end; + } + } + if( val.psz_string != NULL ) free( val.psz_string ); var_Get( p_mux, SOUT_CFG_PREFIX "program-pmt", &val ); - if (val.i_int ) + if( val.psz_string && *val.psz_string ) { - p_sys->i_pmt_program_number = val.i_int; + char *psz_next; + char *psz = val.psz_string; + uint16_t i_pid; + + psz_next = psz; + i = 0; + while ( psz != NULL ) + { + i_pid = strtoul( psz, &psz_next, 0 ); + if( strlen(psz_next) > 0 ) + psz = &psz_next[1]; + else + psz = NULL; + + if( i_pid == 0 ) + { + if( i > MAX_PMT ) + msg_Err( p_mux, "Number of PMTs > maximum (%d)", + MAX_PMT ); + } + else + { + p_sys->i_pmt_program_number[i] = i_pid; + i++; + } + } } else { - p_sys->i_pmt_program_number = 1; + /* Option not specified, use 1, 2, 3... */ + for( i = 0; i < p_sys->i_num_pmt; i++ ) + p_sys->i_pmt_program_number[i] = i + 1; } + if( val.psz_string != NULL ) free( val.psz_string ); var_Get( p_mux, SOUT_CFG_PREFIX "pid-pmt", &val ); - if (val.i_int ) + if( val.i_int ) { - p_sys->pmt.i_pid = val.i_int; + for( i = 0; i < p_sys->i_num_pmt; i++ ) + p_sys->pmt[i].i_pid = val.i_int + i; /* Does this make any sense? */ } else { - p_sys->pmt.i_pid = 0x42; + for( i = 0; i < p_sys->i_num_pmt; i++ ) + p_sys->pmt[i].i_pid = 0x42 + i; } - p_sys->i_pid_free = p_sys->pmt.i_pid + 1; - - var_Get( p_mux, SOUT_CFG_PREFIX "es-id-pid", &val ); - p_sys->b_es_id_pid = val.b_bool; + p_sys->i_pid_free = p_sys->pmt[p_sys->i_num_pmt - 1].i_pid + 1; var_Get( p_mux, SOUT_CFG_PREFIX "pid-video", &val ); p_sys->i_pid_video = val.i_int; @@ -597,12 +792,22 @@ static void Close( vlc_object_t * p_this ) { sout_mux_t *p_mux = (sout_mux_t*)p_this; sout_mux_sys_t *p_sys = p_mux->p_sys; + int i; - msg_Dbg( p_mux, "Close" ); if( p_sys->csa ) { csa_Delete( p_sys->csa ); } + for( i = 0; i < MAX_PMT; i++ ) + { + if( p_sys->sdt_descriptors[i].psz_service_name != NULL ) + free( p_sys->sdt_descriptors[i].psz_service_name ); + if( p_sys->sdt_descriptors[i].psz_provider != NULL ) + free( p_sys->sdt_descriptors[i].psz_provider ); + } + + if( p_sys->dvbpmt != NULL ) /* safety */ + free ( p_sys->dvbpmt ); free( p_sys ); } @@ -1880,16 +2085,18 @@ static void GetPAT( sout_mux_t *p_mux, sout_buffer_chain_t *c ) { sout_mux_sys_t *p_sys = p_mux->p_sys; - block_t *p_pat; + block_t *p_pat; dvbpsi_pat_t pat; dvbpsi_psi_section_t *p_section; + int i; dvbpsi_InitPAT( &pat, p_sys->i_tsid, p_sys->i_pat_version_number, 1 ); /* b_current_next */ - /* add all program (only one) */ - dvbpsi_PATAddProgram( &pat, - p_sys->i_pmt_program_number, /* i_number */ - p_sys->pmt.i_pid ); /* i_pid */ + /* add all programs */ + for ( i = 0; i < p_sys->i_num_pmt; i++ ) + dvbpsi_PATAddProgram( &pat, + p_sys->i_pmt_program_number[i], + p_sys->pmt[i].i_pid ); p_section = dvbpsi_GenPATSections( &pat, 0 ); /* max program per section */ @@ -1917,19 +2124,71 @@ static void GetPMT( sout_mux_t *p_mux, sout_buffer_chain_t *c ) { sout_mux_sys_t *p_sys = p_mux->p_sys; - block_t *p_pmt; + block_t *p_pmt[MAX_PMT]; + block_t *p_sdt; - dvbpsi_pmt_t pmt; + dvbpsi_sdt_t sdt; dvbpsi_pmt_es_t *p_es; - dvbpsi_psi_section_t *p_section; + dvbpsi_psi_section_t *p_section[MAX_PMT], *p_section2; + dvbpsi_sdt_service_t *p_service; + char *psz_sdt_desc; + int i_pidinput; + + int i_stream; + int i; + int *p_usepid = NULL; - int i_stream; + if( p_sys->dvbpmt == NULL ) + p_sys->dvbpmt = malloc( p_sys->i_num_pmt * sizeof(dvbpsi_pmt_t) ); + if( p_sys->b_sdt ) + dvbpsi_InitSDT( &sdt, p_sys->i_tsid, 1, 1, p_sys->i_netid ); - dvbpsi_InitPMT( &pmt, - p_sys->i_pmt_program_number, /* program number */ - p_sys->i_pmt_version_number, - 1, /* b_current_next */ - p_sys->i_pcr_pid ); + for( i = 0; i < p_sys->i_num_pmt; i++ ) + { + dvbpsi_InitPMT( &p_sys->dvbpmt[i], + p_sys->i_pmt_program_number[i], /* program number */ + p_sys->i_pmt_version_number, + 1, /* b_current_next */ + p_sys->i_pcr_pid ); + + if( p_sys->b_sdt ) + { + p_service = dvbpsi_SDTAddService( &sdt, + p_sys->i_pmt_program_number[i], /* service id */ + 0, /* eit schedule */ + 0, /* eit present */ + 4, /* running status ("4=RUNNING") */ + 0 ); /* free ca */ + +#define psz_sdtprov p_sys->sdt_descriptors[i].psz_provider +#define psz_sdtserv p_sys->sdt_descriptors[i].psz_service_name + + /* FIXME: Ineffecient malloc's & ugly code...... */ + if( psz_sdtprov != NULL && psz_sdtserv != NULL ) + { + psz_sdt_desc = malloc( 3 + strlen(psz_sdtprov) + + strlen(psz_sdtserv) ); + psz_sdt_desc[0] = 0x01; /* digital television service */ + + /* service provider name length */ + psz_sdt_desc[1] = (char)strlen(psz_sdtprov); + memcpy( &psz_sdt_desc[2], psz_sdtprov, strlen(psz_sdtprov) ); + + /* service name length */ + psz_sdt_desc[ 2 + strlen(psz_sdtprov) ] + = (char)strlen(psz_sdtserv); + memcpy( &psz_sdt_desc[3+strlen(psz_sdtprov)], psz_sdtserv, + strlen(psz_sdtserv) ); + + dvbpsi_SDTServiceAddDescriptor( p_service, 0x48, + 3 + strlen(psz_sdtprov) + strlen(psz_sdtserv), + psz_sdt_desc ); + free( psz_sdt_desc ); + } +#undef psz_sdtprov +#undef psz_sdtserv + } + } if( p_sys->i_mpeg4_streams > 0 ) { @@ -2065,7 +2324,23 @@ static void GetPMT( sout_mux_t *p_mux, bits_write( &bits_fix_IOD, 24, GetDescriptorLength24b( bits.i_data - bits_fix_IOD.i_data - 3 ) ); - dvbpsi_PMTAddDescriptor( &pmt, 0x1d, bits.i_data, bits.p_data ); + +#ifdef HAVE_BSEARCH + i_pidinput = ((es_format_t *)(p_mux->pp_inputs[i]->p_fmt))->i_id; + p_usepid = bsearch( &i_pidinput, p_sys->pmtmap, p_sys->i_pmtslots, + sizeof(pmt_map_t), intcompare ); + p_usepid = bsearch( &p_usepid, p_sys->pmtmap, p_sys->i_num_pmt, + sizeof(pmt_map_t), pmtcompare ); + if( p_usepid != NULL ) + dvbpsi_PMTAddDescriptor( + &p_sys->dvbpmt[((pmt_map_t *)p_usepid)->i_prog], 0x1d, + bits.i_data, bits.p_data ); + else + msg_Err( p_mux, "Received an unmapped PID" ); +#else + dvbpsi_PMTAddDescriptor( &p_sys->dvbpmt[0], 0x1d, bits.i_data, + bits.p_data ); +#endif } for( i_stream = 0; i_stream < p_mux->i_nb_inputs; i_stream++ ) @@ -2073,9 +2348,21 @@ static void GetPMT( sout_mux_t *p_mux, ts_stream_t *p_stream; p_stream = (ts_stream_t*)p_mux->pp_inputs[i_stream]->p_sys; + i_pidinput = ((es_format_t *)(p_mux->pp_inputs[i_stream]->p_fmt))->i_id; + p_usepid = bsearch( &i_pidinput, p_sys->pmtmap, p_sys->i_pmtslots, + sizeof(pmt_map_t), intcompare ); + +#ifdef HAVE_BSEARCH + if( p_usepid != NULL ) + p_es = dvbpsi_PMTAddES( + &p_sys->dvbpmt[((pmt_map_t *)p_usepid)->i_prog], + p_stream->i_stream_type, p_stream->i_pid ); + else + /* If there's an error somewhere, dump it to the first pmt */ +#endif + p_es = dvbpsi_PMTAddES( &p_sys->dvbpmt[0], p_stream->i_stream_type, + p_stream->i_pid ); - p_es = dvbpsi_PMTAddES( &pmt, p_stream->i_stream_type, - p_stream->i_pid ); if( p_stream->i_stream_id == 0xfa || p_stream->i_stream_id == 0xfb ) { uint8_t es_id[2]; @@ -2166,12 +2453,22 @@ static void GetPMT( sout_mux_t *p_mux, } } - p_section = dvbpsi_GenPMTSections( &pmt ); - - p_pmt = WritePSISection( p_mux->p_sout, p_section ); - - PEStoTS( p_mux->p_sout, c, p_pmt, &p_sys->pmt ); + for( i = 0; i < p_sys->i_num_pmt; i++ ) + { + p_section[i] = dvbpsi_GenPMTSections( &p_sys->dvbpmt[i] ); + p_pmt[i] = WritePSISection( p_mux->p_sout, p_section[i] ); + PEStoTS( p_mux->p_sout, c, p_pmt[i], &p_sys->pmt[i] ); + dvbpsi_DeletePSISections( p_section[i] ); + dvbpsi_EmptyPMT( &p_sys->dvbpmt[i] ); + } - dvbpsi_DeletePSISections( p_section ); - dvbpsi_EmptyPMT( &pmt ); + if( p_sys->b_sdt ) + { + p_section2 = dvbpsi_GenSDTSections( &sdt ); + p_sdt = WritePSISection( p_mux->p_sout, p_section2 ); + p_sys->sdt.i_pid = 0x11; + PEStoTS( p_mux->p_sout, c, p_sdt, &p_sys->sdt ); + dvbpsi_DeletePSISections( p_section2 ); + dvbpsi_EmptySDT( &sdt ); + } }