Commit a6fd6b09 authored by Laurent Aimar's avatar Laurent Aimar

Try to reuse ES through EOS/BOS. Only the special case of 1 vorbis ES is

supported (if the decoder configuration except its meta data is
identifcal) (close #1142).
parent 70ecb609
...@@ -65,6 +65,7 @@ typedef struct logical_stream_s ...@@ -65,6 +65,7 @@ typedef struct logical_stream_s
ogg_stream_state os; /* logical stream of packets */ ogg_stream_state os; /* logical stream of packets */
es_format_t fmt; es_format_t fmt;
es_format_t fmt_old; /* format of old ES is reused */
es_out_id_t *p_es; es_out_id_t *p_es;
double f_rate; double f_rate;
...@@ -103,6 +104,8 @@ struct demux_sys_t ...@@ -103,6 +104,8 @@ struct demux_sys_t
int i_streams; /* number of logical bitstreams */ int i_streams; /* number of logical bitstreams */
logical_stream_t **pp_stream; /* pointer to an array of logical streams */ logical_stream_t **pp_stream; /* pointer to an array of logical streams */
logical_stream_t *p_old_stream; /* pointer to a old logical stream to avoid recreating it */
/* program clock reference (in units of 90kHz) derived from the pcr of /* program clock reference (in units of 90kHz) derived from the pcr of
* the sub-streams */ * the sub-streams */
mtime_t i_pcr; mtime_t i_pcr;
...@@ -175,6 +178,10 @@ static int Ogg_BeginningOfStream( demux_t *p_demux ); ...@@ -175,6 +178,10 @@ static int Ogg_BeginningOfStream( demux_t *p_demux );
static int Ogg_FindLogicalStreams( demux_t *p_demux ); static int Ogg_FindLogicalStreams( demux_t *p_demux );
static void Ogg_EndOfStream( demux_t *p_demux ); static void Ogg_EndOfStream( demux_t *p_demux );
/* */
static void Ogg_LogicalStreamDelete( demux_t *p_demux, logical_stream_t *p_stream );
static bool Ogg_LogicalStreamResetEsFormat( demux_t *p_demux, logical_stream_t *p_stream );
/* Logical bitstream headers */ /* Logical bitstream headers */
static void Ogg_ReadTheoraHeader( logical_stream_t *, ogg_packet * ); static void Ogg_ReadTheoraHeader( logical_stream_t *, ogg_packet * );
static void Ogg_ReadVorbisHeader( logical_stream_t *, ogg_packet * ); static void Ogg_ReadVorbisHeader( logical_stream_t *, ogg_packet * );
...@@ -210,6 +217,7 @@ static int Open( vlc_object_t * p_this ) ...@@ -210,6 +217,7 @@ static int Open( vlc_object_t * p_this )
memset( p_sys, 0, sizeof( demux_sys_t ) ); memset( p_sys, 0, sizeof( demux_sys_t ) );
p_sys->i_bitrate = 0; p_sys->i_bitrate = 0;
p_sys->pp_stream = NULL; p_sys->pp_stream = NULL;
p_sys->p_old_stream = NULL;
/* Begnning of stream, tell the demux to look for elementary streams. */ /* Begnning of stream, tell the demux to look for elementary streams. */
p_sys->i_eos = 0; p_sys->i_eos = 0;
...@@ -233,6 +241,9 @@ static void Close( vlc_object_t *p_this ) ...@@ -233,6 +241,9 @@ static void Close( vlc_object_t *p_this )
Ogg_EndOfStream( p_demux ); Ogg_EndOfStream( p_demux );
if( p_sys->p_old_stream )
Ogg_LogicalStreamDelete( p_demux, p_sys->p_old_stream );
free( p_sys ); free( p_sys );
} }
...@@ -254,11 +265,19 @@ static int Demux( demux_t * p_demux ) ...@@ -254,11 +265,19 @@ static int Demux( demux_t * p_demux )
if( p_sys->i_eos ) if( p_sys->i_eos )
{ {
msg_Dbg( p_demux, "end of a group of logical streams" ); msg_Dbg( p_demux, "end of a group of logical streams" );
/* We keep the ES to try reusing it in Ogg_BeginningOfStream
* only 1 ES is supported (common case for ogg web radio) */
if( p_sys->i_streams == 1 )
{
p_sys->p_old_stream = p_sys->pp_stream[0];
TAB_CLEAN( p_sys->i_streams, p_sys->pp_stream );
}
Ogg_EndOfStream( p_demux ); Ogg_EndOfStream( p_demux );
} }
p_sys->i_eos = 0; p_sys->i_eos = 0;
if( Ogg_BeginningOfStream( p_demux ) != VLC_SUCCESS ) return 0; if( Ogg_BeginningOfStream( p_demux ) != VLC_SUCCESS )
return 0;
msg_Dbg( p_demux, "beginning of a group of logical streams" ); msg_Dbg( p_demux, "beginning of a group of logical streams" );
es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
...@@ -595,8 +614,10 @@ static void Ogg_DecodePacket( demux_t *p_demux, ...@@ -595,8 +614,10 @@ static void Ogg_DecodePacket( demux_t *p_demux,
realloc( p_stream->fmt.p_extra, p_stream->i_headers ); realloc( p_stream->fmt.p_extra, p_stream->i_headers );
memcpy( p_stream->fmt.p_extra, p_stream->p_headers, memcpy( p_stream->fmt.p_extra, p_stream->p_headers,
p_stream->i_headers ); p_stream->i_headers );
es_out_Control( p_demux->out, ES_OUT_SET_FMT,
p_stream->p_es, &p_stream->fmt ); if( Ogg_LogicalStreamResetEsFormat( p_demux, p_stream ) )
es_out_Control( p_demux->out, ES_OUT_SET_FMT,
p_stream->p_es, &p_stream->fmt );
} }
b_selected = false; /* Discard the header packet */ b_selected = false; /* Discard the header packet */
...@@ -797,6 +818,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux ) ...@@ -797,6 +818,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
p_stream->secondary_header_packets = 0; p_stream->secondary_header_packets = 0;
es_format_Init( &p_stream->fmt, 0, 0 ); es_format_Init( &p_stream->fmt, 0, 0 );
es_format_Init( &p_stream->fmt_old, 0, 0 );
/* Setup the logical stream */ /* Setup the logical stream */
p_stream->i_serial_no = ogg_page_serialno( &oggpage ); p_stream->i_serial_no = ogg_page_serialno( &oggpage );
...@@ -1189,6 +1211,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux ) ...@@ -1189,6 +1211,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
static int Ogg_BeginningOfStream( demux_t *p_demux ) static int Ogg_BeginningOfStream( demux_t *p_demux )
{ {
demux_sys_t *p_ogg = p_demux->p_sys ; demux_sys_t *p_ogg = p_demux->p_sys ;
logical_stream_t *p_old_stream = p_ogg->p_old_stream;
int i_stream; int i_stream;
/* Find the logical streams embedded in the physical stream and /* Find the logical streams embedded in the physical stream and
...@@ -1203,8 +1226,26 @@ static int Ogg_BeginningOfStream( demux_t *p_demux ) ...@@ -1203,8 +1226,26 @@ static int Ogg_BeginningOfStream( demux_t *p_demux )
for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ ) for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
{ {
#define p_stream p_ogg->pp_stream[i_stream] logical_stream_t *p_stream = p_ogg->pp_stream[i_stream];
p_stream->p_es = es_out_Add( p_demux->out, &p_stream->fmt );
p_stream->p_es = NULL;
/* Try first to reuse an old ES */
if( p_old_stream &&
p_old_stream->fmt.i_cat == p_stream->fmt.i_cat &&
p_old_stream->fmt.i_codec == p_stream->fmt.i_codec )
{
msg_Dbg( p_demux, "will reuse old stream to avoid glitch" );
p_stream->p_es = p_old_stream->p_es;
es_format_Copy( &p_stream->fmt_old, &p_old_stream->fmt );
p_old_stream->p_es = NULL;
p_old_stream = NULL;
}
if( !p_stream->p_es )
p_stream->p_es = es_out_Add( p_demux->out, &p_stream->fmt );
// TODO: something to do here ? // TODO: something to do here ?
if( p_stream->fmt.i_codec == VLC_FOURCC('c','m','m','l') ) if( p_stream->fmt.i_codec == VLC_FOURCC('c','m','m','l') )
...@@ -1218,9 +1259,15 @@ static int Ogg_BeginningOfStream( demux_t *p_demux ) ...@@ -1218,9 +1259,15 @@ static int Ogg_BeginningOfStream( demux_t *p_demux )
p_stream->i_pcr = p_stream->i_previous_pcr = p_stream->i_pcr = p_stream->i_previous_pcr =
p_stream->i_interpolated_pcr = -1; p_stream->i_interpolated_pcr = -1;
p_stream->b_reinit = 0; p_stream->b_reinit = 0;
#undef p_stream
} }
if( p_ogg->p_old_stream )
{
if( p_ogg->p_old_stream->p_es )
msg_Dbg( p_demux, "old stream not reused" );
Ogg_LogicalStreamDelete( p_demux, p_ogg->p_old_stream );
p_ogg->p_old_stream = NULL;
}
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -1232,27 +1279,80 @@ static void Ogg_EndOfStream( demux_t *p_demux ) ...@@ -1232,27 +1279,80 @@ static void Ogg_EndOfStream( demux_t *p_demux )
demux_sys_t *p_ogg = p_demux->p_sys ; demux_sys_t *p_ogg = p_demux->p_sys ;
int i_stream; int i_stream;
#define p_stream p_ogg->pp_stream[i_stream]
for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ ) for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
Ogg_LogicalStreamDelete( p_demux, p_ogg->pp_stream[i_stream] );
free( p_ogg->pp_stream );
/* Reinit p_ogg */
p_ogg->i_bitrate = 0;
p_ogg->i_streams = 0;
p_ogg->pp_stream = NULL;
}
/**
* This function delete and release all data associated to a logical_stream_t
*/
static void Ogg_LogicalStreamDelete( demux_t *p_demux, logical_stream_t *p_stream )
{
if( p_stream->p_es )
es_out_Del( p_demux->out, p_stream->p_es );
ogg_stream_clear( &p_stream->os );
free( p_stream->p_headers );
es_format_Clean( &p_stream->fmt_old );
es_format_Clean( &p_stream->fmt );
free( p_stream );
}
/**
* This function check if a we need to reset a decoder in case we are
* reusing an old ES
*/
static bool Ogg_IsVorbisFormatCompatible( const es_format_t *p_new, const es_format_t *p_old )
{
int i_new = 0;
int i_old = 0;
int i;
for( i = 0; i < 3; i++ )
{ {
if( p_stream->p_es ) const uint8_t *p_new_extra = ( const uint8_t*)p_new->p_extra + i_new;
es_out_Del( p_demux->out, p_stream->p_es ); const uint8_t *p_old_extra = ( const uint8_t*)p_old->p_extra + i_old;
p_ogg->i_bitrate -= p_stream->fmt.i_bitrate; if( p_new->i_extra < i_new+2 || p_old->i_extra < i_old+2 )
return false;
ogg_stream_clear( &p_ogg->pp_stream[i_stream]->os ); const int i_new_size = GetWBE( &p_new_extra[0] );
free( p_ogg->pp_stream[i_stream]->p_headers ); const int i_old_size = GetWBE( &p_old_extra[0] );
es_format_Clean( &p_stream->fmt ); if( i != 1 ) /* Ignore vorbis comment */
{
if( i_new_size != i_old_size )
return false;
if( memcmp( &p_new_extra[2], &p_old_extra[2], i_new_size ) )
return false;
}
free( p_ogg->pp_stream[i_stream] ); i_new += 2 + i_new_size;
i_old += 2 + i_old_size;
} }
#undef p_stream return true;
}
static bool Ogg_LogicalStreamResetEsFormat( demux_t *p_demux, logical_stream_t *p_stream )
{
bool b_compatible;
if( !p_stream->fmt_old.i_cat || !p_stream->fmt_old.i_codec )
return true;
/* Reinit p_ogg */ /* Only vorbis is supported */
free( p_ogg->pp_stream ); if( p_stream->fmt.i_codec == VLC_FOURCC( 'v','o','r','b' ) )
p_ogg->pp_stream = NULL; b_compatible = Ogg_IsVorbisFormatCompatible( &p_stream->fmt, &p_stream->fmt_old );
p_ogg->i_streams = 0;
if( !b_compatible )
msg_Warn( p_demux, "cannot reuse old stream, resetting the decoder" );
return !b_compatible;
} }
static void Ogg_ReadTheoraHeader( logical_stream_t *p_stream, static void Ogg_ReadTheoraHeader( logical_stream_t *p_stream,
......
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