#include "bits.h"
#include "pes.h"
#include "csa.h"
+#include "tsutil.h"
# include <dvbpsi/dvbpsi.h>
# include <dvbpsi/demux.h>
int64_t i_pcr_delay;
int64_t i_dts_delay;
+ mtime_t first_dts;
bool b_use_key_frames;
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;
- p_mux->p_sys = p_sys;
return VLC_SUCCESS;
}
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;
}
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)
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 "
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 );
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 )
{
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 )
#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 );
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 )
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] );
}
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 );
}