/*****************************************************************************
* ts.c: MPEG-II TS Muxer
*****************************************************************************
- * Copyright (C) 2001-2005 the VideoLAN team
+ * Copyright (C) 2001-2005 VLC authors and VideoLAN
* $Id$
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Jean-Paul Saman <jpsaman #_at_# m2x.nl>
* Wallace Wadge <wwadge #_at_# gmail.com>
*
- * 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
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
#include "bits.h"
#include "pes.h"
#include "csa.h"
+#include "tsutil.h"
# include <dvbpsi/dvbpsi.h>
# include <dvbpsi/demux.h>
# include <dvbpsi/dr.h>
# include <dvbpsi/psi.h>
+#include "dvbpsi_compat.h"
+
/*
* TODO:
* - check PCR frequency requirement
vlc_mutex_t csa_lock;
+#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
+ dvbpsi_t *p_dvbpsi;
+#endif
bool b_es_id_pid;
bool b_sdt;
int i_pid_video;
int64_t i_pcr_delay;
int64_t i_dts_delay;
+ mtime_t first_dts;
bool b_use_key_frames;
return VLC_ENOMEM;
p_sys->i_num_pmt = 1;
- p_mux->pf_control = Control;
- p_mux->pf_addstream = AddStream;
- p_mux->pf_delstream = DelStream;
- p_mux->pf_mux = Mux;
- p_mux->p_sys = p_sys;
+
+#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
+ p_sys->p_dvbpsi = dvbpsi_new( &dvbpsi_messages, DVBPSI_MSG_DEBUG );
+ if( !p_sys->p_dvbpsi )
+ {
+ free( p_sys );
+ return VLC_ENOMEM;
+ }
+ p_sys->p_dvbpsi->p_sys = (void *) p_mux;
+#endif
p_sys->b_es_id_pid = var_GetBool( p_mux, SOUT_CFG_PREFIX "es-id-pid" );
{
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;
- if ( ++p_sys->i_pmtslots > MAX_PMT_PID )
+ if ( ++p_sys->i_pmtslots >= MAX_PMT_PID )
{
msg_Err( p_mux, "Number of pids in PMT > %d", MAX_PMT_PID );
- p_sys->i_pmtslots = MAX_PMT_PID;
+ p_sys->i_pmtslots = MAX_PMT_PID - 1;
}
}
}
if( i_pid == 0 )
{
- if( i > MAX_PMT )
+ if( i >= MAX_PMT )
msg_Err( p_mux, "Number of PMTs > maximum (%d)", MAX_PMT );
}
else
p_sys->b_use_key_frames = var_GetBool( p_mux, SOUT_CFG_PREFIX "use-key-frames" );
+ p_mux->p_sys = p_sys;
+
p_sys->csa = csaSetup(p_this);
+ p_mux->pf_control = Control;
+ p_mux->pf_addstream = AddStream;
+ p_mux->pf_delstream = DelStream;
+ p_mux->pf_mux = Mux;
+
return VLC_SUCCESS;
}
sout_mux_t *p_mux = (sout_mux_t*)p_this;
sout_mux_sys_t *p_sys = p_mux->p_sys;
+#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
+ if( p_sys->p_dvbpsi )
+ dvbpsi_delete( p_sys->p_dvbpsi );
+#endif
+
if( p_sys->csa )
{
var_DelCallback( p_mux, SOUT_CFG_PREFIX "csa-ck", ChangeKeyCallback, NULL );
/* VIDEO */
case VLC_CODEC_MPGV:
+ case VLC_CODEC_MP2V:
+ case VLC_CODEC_MP1V:
/* TODO: do we need to check MPEG-I/II ? */
p_stream->i_stream_type = 0x02;
p_stream->i_stream_id = 0xe0;
p_stream->i_stream_id = 0xe0;
p_stream->i_es_id = p_stream->i_pid;
break;
+ case VLC_CODEC_HEVC:
+ p_stream->i_stream_type = 0x24;
+ p_stream->i_stream_id = 0xe0;
+ break;
case VLC_CODEC_H264:
p_stream->i_stream_type = 0x1b;
p_stream->i_stream_id = 0xe0;
/* AUDIO */
case VLC_CODEC_MPGA:
+ case VLC_CODEC_MP3:
p_stream->i_stream_type =
p_input->p_fmt->audio.i_rate >= 32000 ? 0x03 : 0x04;
p_stream->i_stream_id = 0xc0;
p_stream->i_stream_type = 0x81;
p_stream->i_stream_id = 0xbd;
break;
- case VLC_CODEC_EAC3:
- p_stream->i_stream_type = 0x06;
- p_stream->i_stream_id = 0xbd;
- break;
case VLC_CODEC_DVD_LPCM:
p_stream->i_stream_type = 0x83;
p_stream->i_stream_id = 0xbd;
break;
+ case VLC_CODEC_OPUS:
+ if (p_input->p_fmt->audio.i_channels > 8) {
+ msg_Err(p_mux, "Too many opus channels (%d > 8)",
+ p_input->p_fmt->audio.i_channels);
+ break;
+ }
+ case VLC_CODEC_EAC3:
case VLC_CODEC_DTS:
p_stream->i_stream_type = 0x06;
p_stream->i_stream_id = 0xbd;
//p_stream->i_stream_type = 0x11; /* LOAS/LATM */
p_stream->i_stream_type = 0x0f; /* ADTS */
p_stream->i_stream_id = 0xc0;
- p_sys->i_mpeg4_streams++;
p_stream->i_es_id = p_stream->i_pid;
break;
if (p_stream->i_stream_type == -1)
{
+ msg_Warn( p_mux, "rejecting stream with unsupported codec %4.4s",
+ (char*)&p_stream->i_codec );
free( p_stream );
return VLC_EGENERIC;
}
return VLC_SUCCESS;
oom:
- free(p_stream->lang);
- free(p_stream);
+ if(p_stream)
+ {
+ free(p_stream->lang);
+ free(p_stream);
+ }
return VLC_ENOMEM;
}
return VLC_SUCCESS;
}
+static void SetHeader( sout_buffer_chain_t *c,
+ int depth )
+{
+ block_t *p_ts = BufferChainPeek( c );
+ while( depth > 0 )
+ {
+ p_ts = p_ts->p_next;
+ depth--;
+ }
+ p_ts->i_flags |= BLOCK_FLAG_HEADER;
+}
+
+static block_t *Pack_Opus(block_t *p_data)
+{
+ lldiv_t d = lldiv(p_data->i_buffer, 255);
+ p_data = block_Realloc(p_data, 2 + d.quot + 1, p_data->i_buffer);
+ if (p_data) { /* no flags */
+ p_data->p_buffer[0] = 0x7f;
+ p_data->p_buffer[1] = 0xe0;
+ memset(&p_data->p_buffer[2], 0xff, d.quot);
+ p_data->p_buffer[2+d.quot] = d.rem;
+ }
+
+ return p_data;
+}
+
/* returns true if needs more data */
static bool MuxStreams(sout_mux_t *p_mux )
{
int64_t i_spu_delay = p_spu->i_dts - p_pcr_stream->i_pes_dts;
if( ( i_spu_delay > i_shaping_delay ) &&
- ( i_spu_delay < INT64_C(100000000) ) )
+ ( i_spu_delay < 100 * CLOCK_FREQ ) )
continue;
- if ( ( i_spu_delay >= INT64_C(100000000) ) ||
- ( i_spu_delay < INT64_C(10000) ) )
+ if ( ( i_spu_delay >= 100 * CLOCK_FREQ ) ||
+ ( i_spu_delay < CLOCK_FREQ / 100 ) )
{
BufferChainClean( &p_stream->chain_pes );
p_stream->i_pes_dts = 0;
block_t *p_data;
if( p_stream == p_pcr_stream || p_sys->b_data_alignment
- || p_input->p_fmt->i_codec != VLC_CODEC_MPGA )
+ || ((p_input->p_fmt->i_codec != VLC_CODEC_MPGA ) &&
+ (p_input->p_fmt->i_codec != VLC_CODEC_MP3) ) )
{
p_data = block_FifoGet( p_input->p_fifo );
+ if (p_data->i_pts <= VLC_TS_INVALID)
+ p_data->i_pts = p_data->i_dts;
if( p_input->p_fmt->i_codec == VLC_CODEC_MP4A )
p_data = Add_ADTS( p_data, p_input->p_fmt );
+ else if( p_input->p_fmt->i_codec == VLC_CODEC_OPUS )
+ p_data = Pack_Opus( p_data );
}
else
p_data = FixPES( p_mux, p_input->p_fifo );
VLC_CODEC_SUBT )
p_data->i_length = 1000;
+ if (p_sys->first_dts == 0)
+ p_sys->first_dts = p_data->i_dts;
+
if( ( p_pcr_stream->i_pes_dts > 0 &&
- p_data->i_dts - 10000000 > p_pcr_stream->i_pes_dts +
+ p_data->i_dts - 10 * CLOCK_FREQ > p_pcr_stream->i_pes_dts +
p_pcr_stream->i_pes_length ) ||
p_data->i_dts < p_stream->i_pes_dts ||
( p_stream->i_pes_dts > 0 &&
p_input->p_fmt->i_cat != SPU_ES &&
- p_data->i_dts - 10000000 > p_stream->i_pes_dts +
+ p_data->i_dts - 10 * CLOCK_FREQ > p_stream->i_pes_dts +
p_stream->i_pes_length ) )
{
msg_Warn( p_mux, "packet with too strange dts "
if( p_data->i_length > 0 &&
( p_data->i_buffer != 1 || *p_data->p_buffer != ' ' ) )
{
- block_t *p_spu = block_New( p_mux, 3 );
+ block_t *p_spu = block_Alloc( 3 );
p_spu->i_dts = p_data->i_dts + p_data->i_length;
p_spu->i_pts = p_spu->i_dts;
p_spu->p_buffer[1] = 1;
p_spu->p_buffer[2] = ' ';
- EStoPES( &p_spu, p_spu, p_input->p_fmt,
- p_stream->i_stream_id, 1, 0, 0, 0 );
+ EStoPES( &p_spu, p_input->p_fmt,
+ p_stream->i_stream_id, 1, 0, 0, 0, p_sys->first_dts );
p_data->p_next = p_spu;
}
break;
i_max_pes_size = INT_MAX;
}
- EStoPES ( &p_data, p_data, p_input->p_fmt, p_stream->i_stream_id,
+ EStoPES ( &p_data, p_input->p_fmt, p_stream->i_stream_id,
1, b_data_alignment, i_header_size,
- i_max_pes_size );
+ i_max_pes_size, p_sys->first_dts );
BufferChainAppend( &p_stream->chain_pes, p_data );
/* 3: mux PES into TS */
BufferChainInit( &chain_ts );
/* append PAT/PMT -> FIXME with big pcr delay it won't have enough pat/pmt */
+ bool pat_was_previous = true; //This is to prevent unnecessary double PAT/PMT insertions
GetPAT( p_mux, &chain_ts );
GetPMT( p_mux, &chain_ts );
int i_packet_pos = 0;
}
i_packet_pos++;
+ /* Write PAT/PMT before every keyframe if use-key-frames is enabled,
+ * this helps to do segmenting with livehttp-output so it can cut segment
+ * and start new one with pat,pmt,keyframe*/
+ if( ( p_sys->b_use_key_frames ) && ( p_ts->i_flags & BLOCK_FLAG_TYPE_I ) )
+ {
+ if( likely( !pat_was_previous ) )
+ {
+ int startcount = chain_ts.i_depth;
+ GetPAT( p_mux, &chain_ts );
+ GetPMT( p_mux, &chain_ts );
+ SetHeader( &chain_ts, startcount );
+ i_packet_count += (chain_ts.i_depth - startcount );
+ } else {
+ SetHeader( &chain_ts, 0); //We just inserted pat/pmt,so just flag it instead of adding new one
+ }
+ }
+ pat_was_previous = false;
+
/* */
BufferChainAppend( &chain_ts, p_ts );
}
}
else if( i_size > STD_PES_PAYLOAD )
{
- block_t *p_new = block_New( p_mux, STD_PES_PAYLOAD );
+ block_t *p_new = block_Alloc( STD_PES_PAYLOAD );
memcpy( p_new->p_buffer, p_data->p_buffer, STD_PES_PAYLOAD );
p_new->i_pts = p_data->i_pts;
p_new->i_dts = p_data->i_dts;
int i_channels = (p_extra[i_index == 0x0f ? 4 : 1] >> 3) & 0x0f;
- /* keep a copy in case block_Realloc() fails */
- block_t *p_bak_block = block_Duplicate( p_data );
- if( !p_bak_block ) /* OOM, block_Realloc() is likely to lose our block */
- return p_data; /* the frame isn't correct but that's the best we have */
-
block_t *p_new_block = block_Realloc( p_data, ADTS_HEADER_SIZE,
p_data->i_buffer );
- if( !p_new_block )
- return p_bak_block; /* OOM, send the (incorrect) original frame */
-
- block_Release( p_bak_block ); /* we don't need the copy anymore */
-
-
uint8_t *p_buffer = p_new_block->p_buffer;
/* fixed header */
if( p_ts->i_flags & BLOCK_FLAG_CLOCK )
{
/* msg_Dbg( p_mux, "pcr=%lld ms", p_ts->i_dts / 1000 ); */
- TSSetPCR( p_ts, p_ts->i_dts - p_sys->i_dts_delay );
+ TSSetPCR( p_ts, p_ts->i_dts - p_sys->i_dts_delay - p_sys->first_dts );
}
if( p_ts->i_flags & BLOCK_FLAG_SCRAMBLED )
{
b_adaptation_field = true;
}
- block_t *p_ts = block_New( p_mux, 188 );
+ block_t *p_ts = block_Alloc( 188 );
if (b_new_pes && !(p_pes->i_flags & BLOCK_FLAG_NO_KEYFRAME) && p_pes->i_flags & BLOCK_FLAG_TYPE_I)
{
p_ts->i_flags |= BLOCK_FLAG_CLOCK;
p_ts->p_buffer[4] = 7 + i_stuffing;
- p_ts->p_buffer[5] = 0x10; /* flags */
+ p_ts->p_buffer[5] = 1 << 4; /* PCR_flag */
if( p_stream->b_discontinuity )
{
p_ts->p_buffer[5] |= 0x80; /* flag TS dicontinuity */
p_stream->b_discontinuity = false;
}
- p_ts->p_buffer[6] = 0 &0xff;
- p_ts->p_buffer[7] = 0 &0xff;
- p_ts->p_buffer[8] = 0 &0xff;
- p_ts->p_buffer[9] = 0 &0xff;
- p_ts->p_buffer[10]= ( 0 &0x80 ) | 0x7e;
- p_ts->p_buffer[11]= 0;
-
- for (int i = 12; i < 12 + i_stuffing; i++ )
- {
- p_ts->p_buffer[i] = 0xff;
- }
+ memset(&p_ts->p_buffer[12], 0xff, i_stuffing);
}
else
{
- p_ts->p_buffer[4] = i_stuffing - 1;
- if( i_stuffing > 1 )
+ p_ts->p_buffer[4] = --i_stuffing;
+ if( i_stuffing-- )
{
- p_ts->p_buffer[5] = 0x00;
- for (int i = 6; i < 6 + i_stuffing - 2; i++ )
- {
- p_ts->p_buffer[i] = 0xff;
- }
+ p_ts->p_buffer[5] = 0;
+ memset(&p_ts->p_buffer[6], 0xff, i_stuffing);
}
}
}
p_ts->p_buffer[7] = ( i_pcr >> 17 )&0xff;
p_ts->p_buffer[8] = ( i_pcr >> 9 )&0xff;
p_ts->p_buffer[9] = ( i_pcr >> 1 )&0xff;
- p_ts->p_buffer[10]|= ( i_pcr << 7 )&0x80;
-}
-
-static void PEStoTS( sout_buffer_chain_t *c, block_t *p_pes,
- ts_stream_t *p_stream )
-{
- /* get PES total size */
- uint8_t *p_data = p_pes->p_buffer;
- int i_size = p_pes->i_buffer;
-
- bool b_new_pes = true;
-
- for (;;)
- {
- /* write header
- * 8b 0x47 sync byte
- * 1b transport_error_indicator
- * 1b payload_unit_start
- * 1b transport_priority
- * 13b pid
- * 2b transport_scrambling_control
- * 2b if adaptation_field 0x03 else 0x01
- * 4b continuity_counter
- */
-
- int i_copy = __MIN( i_size, 184 );
- bool b_adaptation_field = i_size < 184;
- block_t *p_ts = block_Alloc( 188 );
-
- p_ts->p_buffer[0] = 0x47;
- p_ts->p_buffer[1] = ( b_new_pes ? 0x40 : 0x00 )|
- ( ( p_stream->i_pid >> 8 )&0x1f );
- p_ts->p_buffer[2] = p_stream->i_pid & 0xff;
- p_ts->p_buffer[3] = ( b_adaptation_field ? 0x30 : 0x10 )|
- p_stream->i_continuity_counter;
-
- b_new_pes = false;
- p_stream->i_continuity_counter = (p_stream->i_continuity_counter+1)%16;
-
- if( b_adaptation_field )
- {
- int i_stuffing = 184 - i_copy;
-
- p_ts->p_buffer[4] = i_stuffing - 1;
- if( i_stuffing > 1 )
- {
- p_ts->p_buffer[5] = 0x00;
- if( p_stream->b_discontinuity )
- {
- p_ts->p_buffer[5] |= 0x80;
- p_stream->b_discontinuity = false;
- }
- for (int i = 6; i < 6 + i_stuffing - 2; i++ )
- {
- p_ts->p_buffer[i] = 0xff;
- }
- }
- }
- /* copy payload */
- memcpy( &p_ts->p_buffer[188 - i_copy], p_data, i_copy );
- p_data += i_copy;
- i_size -= i_copy;
-
- BufferChainAppend( c, p_ts );
-
- if( i_size <= 0 )
- {
- block_t *p_next = p_pes->p_next;
-
- p_pes->p_next = NULL;
- block_Release( p_pes );
- if( p_next == NULL )
- return;
-
- b_new_pes = true;
- p_pes = p_next;
- i_size = p_pes->i_buffer;
- p_data = p_pes->p_buffer;
- }
- }
+ p_ts->p_buffer[10] = ( i_pcr << 7 )&0x80;
+ p_ts->p_buffer[10] |= 0x7e;
+ p_ts->p_buffer[11] = 0; /* we don't set PCR extension */
}
static block_t *WritePSISection( dvbpsi_psi_section_t* p_section )
(p_section->b_syntax_indicator ? 4 : 0);
p_psi = block_Alloc( i_size + 1 );
+ if( !p_psi )
+ goto error;
p_psi->i_pts = 0;
p_psi->i_dts = 0;
p_psi->i_length = 0;
}
return( p_first );
+
+error:
+ if( p_first )
+ block_ChainRelease( p_first );
+ return NULL;
}
static void GetPAT( sout_mux_t *p_mux,
dvbpsi_PATAddProgram( &pat, p_sys->i_pmt_program_number[i],
p_sys->pmt[i].i_pid );
+#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
+ p_section = dvbpsi_pat_sections_generate( p_sys->p_dvbpsi, &pat, 0 );
+#else
p_section = dvbpsi_GenPATSections( &pat, 0 /* max program per section */ );
-
+#endif
p_pat = WritePSISection( p_section );
- PEStoTS( c, p_pat, &p_sys->pat );
+ PEStoTS( c, (PEStoTSCallback)BufferChainAppend, p_pat, p_sys->pat.i_pid,
+ &p_sys->pat.b_discontinuity, &p_sys->pat.i_continuity_counter );
dvbpsi_DeletePSISections( p_section );
dvbpsi_EmptyPAT( &pat );
psz_sdt_desc[ 2 + provlen ] = (char)servlen;
memcpy( &psz_sdt_desc[3+provlen], psz_sdtserv, servlen );
+#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
+ dvbpsi_sdt_service_descriptor_add( p_service, 0x48,
+ (3 + provlen + servlen),
+ psz_sdt_desc );
+#else
dvbpsi_SDTServiceAddDescriptor( p_service, 0x48,
3 + provlen + servlen, psz_sdt_desc );
+#endif
}
if( p_sys->i_mpeg4_streams > 0 )
for (int i_stream = 0; i_stream < p_mux->i_nb_inputs; i_stream++ )
{
- ts_stream_t *p_stream = (ts_stream_t*)p_mux->pp_inputs[i_stream]->p_sys;
+ sout_input_t *p_input = p_mux->pp_inputs[i_stream];
+ ts_stream_t *p_stream = (ts_stream_t*)p_input->p_sys;
- int i_pidinput = p_mux->pp_inputs[i_stream]->p_fmt->i_id;
+ int i_pidinput = p_input->p_fmt->i_id;
pmt_map_t *p_usepid = bsearch( &i_pidinput, p_sys->pmtmap,
p_sys->i_pmtslots, sizeof(pmt_map_t), intcompare );
uint8_t data[1] = { 0x00 };
dvbpsi_PMTESAddDescriptor( p_es, 0x7a, 1, data );
}
+ else if( p_stream->i_codec == VLC_CODEC_OPUS )
+ {
+ uint8_t data[2] = {
+ 0x80, /* tag extension */
+ p_input->p_fmt->audio.i_channels
+ };
+ dvbpsi_PMTESAddDescriptor( p_es, 0x7f, 2, data );
+ uint8_t format[4] = { 'O', 'p', 'u', 's'};
+ /* "registration" descriptor : "Opus" */
+ dvbpsi_PMTESAddDescriptor( p_es, 0x05, 4, format );
+ }
else if( p_stream->i_codec == VLC_CODEC_TELETEXT )
{
if( p_stream->i_extra )
for (unsigned i = 0; i < p_sys->i_num_pmt; i++ )
{
- dvbpsi_psi_section_t *sect = dvbpsi_GenPMTSections( &p_sys->dvbpmt[i] );
+ dvbpsi_psi_section_t *sect;
+#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
+ sect = dvbpsi_pmt_sections_generate( p_sys->p_dvbpsi, &p_sys->dvbpmt[i] );
+#else
+ sect = dvbpsi_GenPMTSections( &p_sys->dvbpmt[i] );
+#endif
block_t *pmt = WritePSISection( sect );
- PEStoTS( c, pmt, &p_sys->pmt[i] );
+ PEStoTS( c, (PEStoTSCallback)BufferChainAppend, pmt, p_sys->pmt[i].i_pid,
+ &p_sys->pmt[i].b_discontinuity, &p_sys->pmt[i].i_continuity_counter );
dvbpsi_DeletePSISections(sect);
dvbpsi_EmptyPMT( &p_sys->dvbpmt[i] );
}
if( p_sys->b_sdt )
{
- dvbpsi_psi_section_t *sect = dvbpsi_GenSDTSections( &sdt );
+ dvbpsi_psi_section_t *sect;
+#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
+ sect = dvbpsi_sdt_sections_generate( p_sys->p_dvbpsi, &sdt );
+#else
+ sect = dvbpsi_GenSDTSections( &sdt );
+#endif
block_t *p_sdt = WritePSISection( sect );
- PEStoTS( c, p_sdt, &p_sys->sdt );
+ PEStoTS( c, (PEStoTSCallback)BufferChainAppend, p_sdt, p_sys->sdt.i_pid,
+ &p_sys->sdt.b_discontinuity, &p_sys->sdt.i_continuity_counter );
dvbpsi_DeletePSISections( sect );
dvbpsi_EmptySDT( &sdt );
}