Commit 29be1e00 authored by Gildas Bazin's avatar Gildas Bazin

* modules/mux/mpeg/ps.c: make sure the data blocks containing the pack and...

* modules/mux/mpeg/ps.c: make sure the data blocks containing the pack and system headers are timestamped correctly. Added an --sout-ps-dts-delay option.
parent 60568b2c
...@@ -7,8 +7,7 @@ ...@@ -7,8 +7,7 @@
* *
* Authors: Laurent Aimar <fenrir@via.ecp.fr> * Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Eric Petit <titer@videolan.org> * Eric Petit <titer@videolan.org>
* Gildas Bazin <gbazin@netcourrier.com> * Gildas Bazin <gbazin@videolan.org>
*
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -38,25 +37,31 @@ ...@@ -38,25 +37,31 @@
#include "bits.h" #include "bits.h"
#include "pes.h" #include "pes.h"
/* TODO:
* - test support of DTS, LPCM
*
*/
/***************************************************************************** /*****************************************************************************
* Module descriptor * Module descriptor
*****************************************************************************/ *****************************************************************************/
#define DTS_TEXT N_("DTS delay (ms)")
#define DTS_LONGTEXT N_("This option will delay the DTS (decoding time " \
"stamps) and PTS (presentation timestamps) of the data in the " \
"stream, compared to the SCRs. This allows for some buffering inside " \
"the client decoder.")
static int Open ( vlc_object_t * ); static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * ); static void Close ( vlc_object_t * );
#define SOUT_CFG_PREFIX "sout-ps-"
vlc_module_begin(); vlc_module_begin();
set_description( _("PS muxer") ); set_description( _("PS muxer") );
set_capability( "sout mux", 50 ); set_capability( "sout mux", 50 );
add_shortcut( "ps" ); add_shortcut( "ps" );
add_shortcut( "mpeg1" ); add_shortcut( "mpeg1" );
add_shortcut( "dvd" );
set_callbacks( Open, Close ); set_callbacks( Open, Close );
vlc_module_end();
add_integer( SOUT_CFG_PREFIX "dts-delay", 200, NULL, DTS_TEXT,
DTS_LONGTEXT, VLC_TRUE );
vlc_module_end();
/***************************************************************************** /*****************************************************************************
* Exported prototypes * Exported prototypes
...@@ -66,14 +71,13 @@ static int AddStream( sout_mux_t *, sout_input_t * ); ...@@ -66,14 +71,13 @@ static int AddStream( sout_mux_t *, sout_input_t * );
static int DelStream( sout_mux_t *, sout_input_t * ); static int DelStream( sout_mux_t *, sout_input_t * );
static int Mux ( sout_mux_t * ); static int Mux ( sout_mux_t * );
/***************************************************************************** /*****************************************************************************
* Local prototypes * Local prototypes
*****************************************************************************/ *****************************************************************************/
static int MuxGetStream ( sout_mux_t *, int *, mtime_t * ); static int MuxGetStream ( sout_mux_t *, int *, mtime_t * );
static void MuxWritePackHeader ( sout_mux_t *, block_t **, mtime_t ); static void MuxWritePackHeader ( sout_mux_t *, block_t **, mtime_t );
static void MuxWriteSystemHeader( sout_mux_t *, block_t ** ); static void MuxWriteSystemHeader( sout_mux_t *, block_t **, mtime_t );
static void StreamIdInit ( vlc_bool_t *id, int i_range ); static void StreamIdInit ( vlc_bool_t *id, int i_range );
static int StreamIdGet ( vlc_bool_t *id, int i_id_min, int i_id_max ); static int StreamIdGet ( vlc_bool_t *id, int i_id_min, int i_id_max );
...@@ -95,26 +99,30 @@ struct sout_mux_sys_t ...@@ -95,26 +99,30 @@ struct sout_mux_sys_t
vlc_bool_t stream_id_dts[8]; /* 0x88 -> 0x8f */ vlc_bool_t stream_id_dts[8]; /* 0x88 -> 0x8f */
vlc_bool_t stream_id_lpcm[16]; /* 0xa0 -> 0xaf */ vlc_bool_t stream_id_lpcm[16]; /* 0xa0 -> 0xaf */
int i_audio_bound; int i_audio_bound;
int i_video_bound; int i_video_bound;
int i_pes_count;
int i_system_header;
int i_dts_delay;
int i_pes_count; vlc_bool_t b_mpeg2;
int i_system_header;
vlc_bool_t b_mpeg2;
}; };
static const char *ppsz_sout_options[] = {
"dts-delay", NULL
};
/***************************************************************************** /*****************************************************************************
* Open: * Open:
*****************************************************************************/ *****************************************************************************/
static int Open( vlc_object_t *p_this ) static int Open( vlc_object_t *p_this )
{ {
sout_mux_t *p_mux = (sout_mux_t*)p_this; sout_mux_t *p_mux = (sout_mux_t*)p_this;
sout_mux_sys_t *p_sys; sout_mux_sys_t *p_sys;
vlc_value_t val;
msg_Info( p_mux, "Open" ); msg_Info( p_mux, "Open" );
sout_CfgParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
p_mux->pf_control = Control; p_mux->pf_control = Control;
p_mux->pf_addstream = AddStream; p_mux->pf_addstream = AddStream;
...@@ -137,6 +145,9 @@ static int Open( vlc_object_t *p_this ) ...@@ -137,6 +145,9 @@ static int Open( vlc_object_t *p_this )
p_sys->b_mpeg2 = !(p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mpeg1" )); p_sys->b_mpeg2 = !(p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mpeg1" ));
var_Get( p_mux, SOUT_CFG_PREFIX "dts-delay", &val );
p_sys->i_dts_delay = (int64_t)val.i_int * 1000;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -199,9 +210,10 @@ static int Control( sout_mux_t *p_mux, int i_query, va_list args ) ...@@ -199,9 +210,10 @@ static int Control( sout_mux_t *p_mux, int i_query, va_list args )
static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
{ {
sout_mux_sys_t *p_sys = p_mux->p_sys; sout_mux_sys_t *p_sys = p_mux->p_sys;
ps_stream_t *p_stream; ps_stream_t *p_stream;
msg_Dbg( p_mux, "adding input codec=%4.4s", (char*)&p_input->p_fmt->i_codec ); msg_Dbg( p_mux, "adding input codec=%4.4s",
(char*)&p_input->p_fmt->i_codec );
p_input->p_sys = p_stream = malloc( sizeof( ps_stream_t ) ); p_input->p_sys = p_stream = malloc( sizeof( ps_stream_t ) );
...@@ -209,22 +221,28 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) ...@@ -209,22 +221,28 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
switch( p_input->p_fmt->i_codec ) switch( p_input->p_fmt->i_codec )
{ {
case VLC_FOURCC( 'm', 'p', 'g', 'v' ): case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
p_stream->i_stream_id = StreamIdGet( p_sys->stream_id_mpgv, 0xe0, 0xef ); p_stream->i_stream_id =
StreamIdGet( p_sys->stream_id_mpgv, 0xe0, 0xef );
break; break;
case VLC_FOURCC( 'l', 'p', 'c', 'm' ): case VLC_FOURCC( 'l', 'p', 'c', 'm' ):
p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_lpcm, 0xa0, 0xaf ); p_stream->i_stream_id =
0xbd00 | StreamIdGet( p_sys->stream_id_lpcm, 0xa0, 0xaf );
break; break;
case VLC_FOURCC( 'd', 't', 's', ' ' ): case VLC_FOURCC( 'd', 't', 's', ' ' ):
p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_dts, 0x88, 0x8f ); p_stream->i_stream_id =
0xbd00 | StreamIdGet( p_sys->stream_id_dts, 0x88, 0x8f );
break; break;
case VLC_FOURCC( 'a', '5', '2', ' ' ): case VLC_FOURCC( 'a', '5', '2', ' ' ):
p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_a52, 0x80, 0x87 ); p_stream->i_stream_id =
0xbd00 | StreamIdGet( p_sys->stream_id_a52, 0x80, 0x87 );
break; break;
case VLC_FOURCC( 'm', 'p', 'g', 'a' ): case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
p_stream->i_stream_id = StreamIdGet( p_sys->stream_id_mpga, 0xc0, 0xcf ); p_stream->i_stream_id =
StreamIdGet( p_sys->stream_id_mpga, 0xc0, 0xcf );
break; break;
case VLC_FOURCC( 's', 'p', 'u', ' ' ): case VLC_FOURCC( 's', 'p', 'u', ' ' ):
p_stream->i_stream_id = 0xbd00|StreamIdGet( p_sys->stream_id_spu, 0x20, 0x3f ); p_stream->i_stream_id =
0xbd00 | StreamIdGet( p_sys->stream_id_spu, 0x20, 0x3f );
break; break;
default: default:
goto error; goto error;
...@@ -256,29 +274,35 @@ error: ...@@ -256,29 +274,35 @@ error:
*****************************************************************************/ *****************************************************************************/
static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input ) static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
{ {
sout_mux_sys_t *p_sys = p_mux->p_sys; sout_mux_sys_t *p_sys = p_mux->p_sys;
ps_stream_t *p_stream =(ps_stream_t*)p_input->p_sys; ps_stream_t *p_stream =(ps_stream_t*)p_input->p_sys;
msg_Dbg( p_mux, "removing input" ); msg_Dbg( p_mux, "removing input" );
switch( p_input->p_fmt->i_codec ) switch( p_input->p_fmt->i_codec )
{ {
case VLC_FOURCC( 'm', 'p', 'g', 'v' ): case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
StreamIdRelease( p_sys->stream_id_mpgv, 0xe0, p_stream->i_stream_id); StreamIdRelease( p_sys->stream_id_mpgv, 0xe0,
p_stream->i_stream_id );
break; break;
case VLC_FOURCC( 'l', 'p', 'c', 'm' ): case VLC_FOURCC( 'l', 'p', 'c', 'm' ):
StreamIdRelease( p_sys->stream_id_lpcm, 0xa0, p_stream->i_stream_id&0xff ); StreamIdRelease( p_sys->stream_id_lpcm, 0xa0,
p_stream->i_stream_id&0xff );
break; break;
case VLC_FOURCC( 'd', 't', 's', ' ' ): case VLC_FOURCC( 'd', 't', 's', ' ' ):
StreamIdRelease( p_sys->stream_id_dts, 0x88, p_stream->i_stream_id&0xff ); StreamIdRelease( p_sys->stream_id_dts, 0x88,
p_stream->i_stream_id&0xff );
break; break;
case VLC_FOURCC( 'a', '5', '2', ' ' ): case VLC_FOURCC( 'a', '5', '2', ' ' ):
StreamIdRelease( p_sys->stream_id_a52, 0x80, p_stream->i_stream_id&0xff ); StreamIdRelease( p_sys->stream_id_a52, 0x80,
p_stream->i_stream_id&0xff );
break; break;
case VLC_FOURCC( 'm', 'p', 'g', 'a' ): case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
StreamIdRelease( p_sys->stream_id_mpga, 0xc0, p_stream->i_stream_id ); StreamIdRelease( p_sys->stream_id_mpga, 0xc0,
p_stream->i_stream_id );
break; break;
case VLC_FOURCC( 's', 'p', 'u', ' ' ): case VLC_FOURCC( 's', 'p', 'u', ' ' ):
StreamIdRelease( p_sys->stream_id_spu, 0x20, p_stream->i_stream_id&0xff ); StreamIdRelease( p_sys->stream_id_spu, 0x20,
p_stream->i_stream_id&0xff );
break; break;
default: default:
/* Never reached */ /* Never reached */
...@@ -320,6 +344,7 @@ static int Mux( sout_mux_t *p_mux ) ...@@ -320,6 +344,7 @@ static int Mux( sout_mux_t *p_mux )
{ {
return VLC_SUCCESS; return VLC_SUCCESS;
} }
p_input = p_mux->pp_inputs[i_stream]; p_input = p_mux->pp_inputs[i_stream];
p_stream = (ps_stream_t*)p_input->p_sys; p_stream = (ps_stream_t*)p_input->p_sys;
p_ps = NULL; p_ps = NULL;
...@@ -335,7 +360,7 @@ static int Mux( sout_mux_t *p_mux ) ...@@ -335,7 +360,7 @@ static int Mux( sout_mux_t *p_mux )
{ {
block_t *p_pk; block_t *p_pk;
MuxWriteSystemHeader( p_mux, &p_ps ); MuxWriteSystemHeader( p_mux, &p_ps, i_dts );
/* For MPEG1 streaming, set HEADER flag */ /* For MPEG1 streaming, set HEADER flag */
for( p_pk = p_ps; p_pk != NULL; p_pk = p_pk->p_next ) for( p_pk = p_ps; p_pk != NULL; p_pk = p_pk->p_next )
...@@ -346,12 +371,11 @@ static int Mux( sout_mux_t *p_mux ) ...@@ -346,12 +371,11 @@ static int Mux( sout_mux_t *p_mux )
/* Get and mux a packet */ /* Get and mux a packet */
p_data = block_FifoGet( p_input->p_fifo ); p_data = block_FifoGet( p_input->p_fifo );
E_( EStoPES )( p_mux->p_sout, E_( EStoPES )( p_mux->p_sout, &p_data, p_data, p_stream->i_stream_id,
&p_data, p_data,
p_stream->i_stream_id,
p_mux->p_sys->b_mpeg2 ); p_mux->p_sys->b_mpeg2 );
block_ChainAppend( &p_ps, p_data ); block_ChainAppend( &p_ps, p_data );
sout_AccessOutWrite( p_mux->p_access, p_ps ); sout_AccessOutWrite( p_mux->p_access, p_ps );
/* Increase counter */ /* Increase counter */
...@@ -361,11 +385,10 @@ static int Mux( sout_mux_t *p_mux ) ...@@ -361,11 +385,10 @@ static int Mux( sout_mux_t *p_mux )
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/***************************************************************************** /*****************************************************************************
* *
*****************************************************************************/ *****************************************************************************/
static void StreamIdInit ( vlc_bool_t *id, int i_range ) static void StreamIdInit( vlc_bool_t *id, int i_range )
{ {
int i; int i;
...@@ -374,7 +397,7 @@ static void StreamIdInit ( vlc_bool_t *id, int i_range ) ...@@ -374,7 +397,7 @@ static void StreamIdInit ( vlc_bool_t *id, int i_range )
id[i] = VLC_TRUE; id[i] = VLC_TRUE;
} }
} }
static int StreamIdGet ( vlc_bool_t *id, int i_id_min, int i_id_max ) static int StreamIdGet( vlc_bool_t *id, int i_id_min, int i_id_max )
{ {
int i; int i;
...@@ -395,19 +418,21 @@ static void StreamIdRelease( vlc_bool_t *id, int i_id_min, int i_id ) ...@@ -395,19 +418,21 @@ static void StreamIdRelease( vlc_bool_t *id, int i_id_min, int i_id )
} }
static void MuxWritePackHeader( sout_mux_t *p_mux, block_t **p_buf, static void MuxWritePackHeader( sout_mux_t *p_mux, block_t **p_buf,
mtime_t i_dts ) mtime_t i_dts )
{ {
block_t *p_hdr; sout_mux_sys_t *p_sys = p_mux->p_sys;
bits_buffer_t bits; bits_buffer_t bits;
mtime_t i_src; block_t *p_hdr;
mtime_t i_scr;
i_src = i_dts * 9 / 100; i_scr = (i_dts - p_sys->i_dts_delay) * 9 / 100;
p_hdr = block_New( p_mux, 18 ); p_hdr = block_New( p_mux, 18 );
p_hdr->i_pts = p_hdr->i_dts = i_dts;
bits_initwrite( &bits, 14, p_hdr->p_buffer ); bits_initwrite( &bits, 14, p_hdr->p_buffer );
bits_write( &bits, 32, 0x01ba ); bits_write( &bits, 32, 0x01ba );
if( p_mux->p_sys->b_mpeg2 ) if( p_sys->b_mpeg2 )
{ {
bits_write( &bits, 2, 0x01 ); bits_write( &bits, 2, 0x01 );
} }
...@@ -416,14 +441,14 @@ static void MuxWritePackHeader( sout_mux_t *p_mux, block_t **p_buf, ...@@ -416,14 +441,14 @@ static void MuxWritePackHeader( sout_mux_t *p_mux, block_t **p_buf,
bits_write( &bits, 4, 0x02 ); bits_write( &bits, 4, 0x02 );
} }
bits_write( &bits, 3, ( i_src >> 30 )&0x07 ); bits_write( &bits, 3, ( i_scr >> 30 )&0x07 );
bits_write( &bits, 1, 1 ); bits_write( &bits, 1, 1 );
bits_write( &bits, 15, ( i_src >> 15 )&0x7fff ); bits_write( &bits, 15, ( i_scr >> 15 )&0x7fff );
bits_write( &bits, 1, 1 ); bits_write( &bits, 1, 1 );
bits_write( &bits, 15, i_src&0x7fff ); bits_write( &bits, 15, i_scr&0x7fff );
bits_write( &bits, 1, 1 ); bits_write( &bits, 1, 1 );
if( p_mux->p_sys->b_mpeg2 ) if( p_sys->b_mpeg2 )
{ {
bits_write( &bits, 9, 0 ); // src extention bits_write( &bits, 9, 0 ); // src extention
} }
...@@ -432,19 +457,20 @@ static void MuxWritePackHeader( sout_mux_t *p_mux, block_t **p_buf, ...@@ -432,19 +457,20 @@ static void MuxWritePackHeader( sout_mux_t *p_mux, block_t **p_buf,
bits_write( &bits, 22, 1000/8/50); // FIXME mux rate bits_write( &bits, 22, 1000/8/50); // FIXME mux rate
bits_write( &bits, 1, 1 ); bits_write( &bits, 1, 1 );
if( p_mux->p_sys->b_mpeg2 ) if( p_sys->b_mpeg2 )
{ {
bits_write( &bits, 1, 1 ); bits_write( &bits, 1, 1 );
bits_write( &bits, 5, 0x1f ); // FIXME reserved bits_write( &bits, 5, 0x1f ); // FIXME reserved
bits_write( &bits, 3, 0 ); // stuffing bytes bits_write( &bits, 3, 0 ); // stuffing bytes
} }
p_hdr->i_buffer = p_mux->p_sys->b_mpeg2 ? 14: 12; p_hdr->i_buffer = p_sys->b_mpeg2 ? 14: 12;
block_ChainAppend( p_buf, p_hdr ); block_ChainAppend( p_buf, p_hdr );
} }
static void MuxWriteSystemHeader( sout_mux_t *p_mux, block_t **p_buf ) static void MuxWriteSystemHeader( sout_mux_t *p_mux, block_t **p_buf,
mtime_t i_dts )
{ {
sout_mux_sys_t *p_sys = p_mux->p_sys; sout_mux_sys_t *p_sys = p_mux->p_sys;
block_t *p_hdr; block_t *p_hdr;
...@@ -467,9 +493,11 @@ static void MuxWriteSystemHeader( sout_mux_t *p_mux, block_t **p_buf ) ...@@ -467,9 +493,11 @@ static void MuxWriteSystemHeader( sout_mux_t *p_mux, block_t **p_buf )
} }
/* Private stream are declared only one time */ /* Private stream are declared only one time */
i_nb_stream = p_mux->i_nb_inputs - ( i_nb_private > 0 ? i_nb_private - 1 : 0 ); i_nb_stream = p_mux->i_nb_inputs -
( i_nb_private > 0 ? i_nb_private - 1 : 0 );
p_hdr = block_New( p_mux, 12 + i_nb_stream * 3 ); p_hdr = block_New( p_mux, 12 + i_nb_stream * 3 );
p_hdr->i_dts = p_hdr->i_pts = i_dts;
bits_initwrite( &bits, 12 + i_nb_stream * 3, p_hdr->p_buffer ); bits_initwrite( &bits, 12 + i_nb_stream * 3, p_hdr->p_buffer );
bits_write( &bits, 32, 0x01bb ); bits_write( &bits, 32, 0x01bb );
...@@ -539,9 +567,7 @@ static void MuxWriteSystemHeader( sout_mux_t *p_mux, block_t **p_buf ) ...@@ -539,9 +567,7 @@ static void MuxWriteSystemHeader( sout_mux_t *p_mux, block_t **p_buf )
/* /*
* Find stream to be muxed. * Find stream to be muxed.
*/ */
static int MuxGetStream( sout_mux_t *p_mux, static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
int *pi_stream,
mtime_t *pi_dts )
{ {
mtime_t i_dts; mtime_t i_dts;
int i_stream; int i_stream;
...@@ -549,7 +575,7 @@ static int MuxGetStream( sout_mux_t *p_mux, ...@@ -549,7 +575,7 @@ static int MuxGetStream( sout_mux_t *p_mux,
for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ ) for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
{ {
sout_input_t *p_input = p_mux->pp_inputs[i]; sout_input_t *p_input = p_mux->pp_inputs[i];
block_t *p_data; block_t *p_data;
if( p_input->p_fifo->i_depth <= 0 ) if( p_input->p_fifo->i_depth <= 0 )
...@@ -560,13 +586,13 @@ static int MuxGetStream( sout_mux_t *p_mux, ...@@ -560,13 +586,13 @@ static int MuxGetStream( sout_mux_t *p_mux,
/* We need that audio+video fifo contain at least 1 packet */ /* We need that audio+video fifo contain at least 1 packet */
return VLC_EGENERIC; return VLC_EGENERIC;
} }
/* SPU */ /* SPU */
continue; continue;
} }
p_data = block_FifoShow( p_input->p_fifo ); p_data = block_FifoShow( p_input->p_fifo );
if( i_stream == -1 || if( i_stream == -1 || p_data->i_dts < i_dts )
p_data->i_dts < i_dts )
{ {
i_stream = i; i_stream = i;
i_dts = p_data->i_dts; i_dts = p_data->i_dts;
...@@ -578,4 +604,3 @@ static int MuxGetStream( sout_mux_t *p_mux, ...@@ -578,4 +604,3 @@ static int MuxGetStream( sout_mux_t *p_mux,
return VLC_SUCCESS; return VLC_SUCCESS;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment