[vlc-devel] commit: Try to reuse ES through EOS/BOS. Only the special case of 1 vorbis ES is (Laurent Aimar )

git version control git at videolan.org
Sat Aug 2 16:20:17 CEST 2008


vlc | branch: master | Laurent Aimar <fenrir at videolan.org> | Sat Aug  2 16:19:13 2008 +0200| [a6fd6b0968aeb4ed66740976d9b6cc6a86baa1eb] | committer: 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).

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=a6fd6b0968aeb4ed66740976d9b6cc6a86baa1eb
---

 modules/demux/ogg.c |  138 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 119 insertions(+), 19 deletions(-)

diff --git a/modules/demux/ogg.c b/modules/demux/ogg.c
index 9b86a25..46ff4d9 100644
--- a/modules/demux/ogg.c
+++ b/modules/demux/ogg.c
@@ -65,6 +65,7 @@ typedef struct logical_stream_s
     ogg_stream_state os;                        /* logical stream of packets */
 
     es_format_t      fmt;
+    es_format_t      fmt_old;                  /* format of old ES is reused */
     es_out_id_t      *p_es;
     double           f_rate;
 
@@ -103,6 +104,8 @@ struct demux_sys_t
     int i_streams;                           /* number of logical bitstreams */
     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
      * the sub-streams */
     mtime_t i_pcr;
@@ -175,6 +178,10 @@ static int Ogg_BeginningOfStream( demux_t *p_demux );
 static int Ogg_FindLogicalStreams( 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 */
 static void Ogg_ReadTheoraHeader( 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 )
     memset( p_sys, 0, sizeof( demux_sys_t ) );
     p_sys->i_bitrate = 0;
     p_sys->pp_stream = NULL;
+    p_sys->p_old_stream = NULL;
 
     /* Begnning of stream, tell the demux to look for elementary streams. */
     p_sys->i_eos = 0;
@@ -233,6 +241,9 @@ static void Close( vlc_object_t *p_this )
 
     Ogg_EndOfStream( p_demux );
 
+    if( p_sys->p_old_stream )
+        Ogg_LogicalStreamDelete( p_demux, p_sys->p_old_stream );
+
     free( p_sys );
 }
 
@@ -254,11 +265,19 @@ static int Demux( demux_t * p_demux )
         if( p_sys->i_eos )
         {
             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 );
         }
 
         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" );
         es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
@@ -595,8 +614,10 @@ static void Ogg_DecodePacket( demux_t *p_demux,
                 realloc( p_stream->fmt.p_extra, p_stream->i_headers );
             memcpy( p_stream->fmt.p_extra, p_stream->p_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 */
@@ -797,6 +818,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
                 p_stream->secondary_header_packets = 0;
 
                 es_format_Init( &p_stream->fmt, 0, 0 );
+                es_format_Init( &p_stream->fmt_old, 0, 0 );
 
                 /* Setup the logical stream */
                 p_stream->i_serial_no = ogg_page_serialno( &oggpage );
@@ -1189,6 +1211,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
 static int Ogg_BeginningOfStream( demux_t *p_demux )
 {
     demux_sys_t *p_ogg = p_demux->p_sys  ;
+    logical_stream_t *p_old_stream = p_ogg->p_old_stream;
     int i_stream;
 
     /* Find the logical streams embedded in the physical stream and
@@ -1203,8 +1226,26 @@ static int Ogg_BeginningOfStream( demux_t *p_demux )
 
     for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
     {
-#define p_stream p_ogg->pp_stream[i_stream]
-        p_stream->p_es = es_out_Add( p_demux->out, &p_stream->fmt );
+        logical_stream_t *p_stream = p_ogg->pp_stream[i_stream];
+
+        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 ?
         if( p_stream->fmt.i_codec == VLC_FOURCC('c','m','m','l') )
@@ -1218,9 +1259,15 @@ static int Ogg_BeginningOfStream( demux_t *p_demux )
         p_stream->i_pcr = p_stream->i_previous_pcr =
             p_stream->i_interpolated_pcr = -1;
         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;
 }
 
@@ -1232,27 +1279,80 @@ static void Ogg_EndOfStream( demux_t *p_demux )
     demux_sys_t *p_ogg = p_demux->p_sys  ;
     int i_stream;
 
-#define p_stream p_ogg->pp_stream[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 )
-            es_out_Del( p_demux->out, p_stream->p_es );
+        const uint8_t *p_new_extra = ( const uint8_t*)p_new->p_extra + i_new;
+        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 );
-        free( p_ogg->pp_stream[i_stream]->p_headers );
+        const int i_new_size = GetWBE( &p_new_extra[0] );
+        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 */
-    free( p_ogg->pp_stream );
-    p_ogg->pp_stream = NULL;
-    p_ogg->i_streams = 0;
+    /* Only vorbis is supported */
+    if( p_stream->fmt.i_codec == VLC_FOURCC( 'v','o','r','b' ) )
+        b_compatible = Ogg_IsVorbisFormatCompatible( &p_stream->fmt, &p_stream->fmt_old );
+
+    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,




More information about the vlc-devel mailing list