[vlc-commits] demux: ogg: rework block/queuing/pcr

Francois Cartegnie git at videolan.org
Thu May 31 18:47:58 CEST 2018


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Thu May 31 11:54:03 2018 +0200| [4c79ba453ca89099c6e74c4085acf79291aec687] | committer: Francois Cartegnie

demux: ogg: rework block/queuing/pcr

and lots of fixes
part 2 of the cleanup/simplification

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

 modules/demux/ogg.c         | 514 ++++++++++++++++++++------------------------
 modules/demux/ogg.h         |  14 +-
 modules/demux/ogg_granule.c |  17 +-
 3 files changed, 249 insertions(+), 296 deletions(-)

diff --git a/modules/demux/ogg.c b/modules/demux/ogg.c
index cfeb239974..ebca534026 100644
--- a/modules/demux/ogg.c
+++ b/modules/demux/ogg.c
@@ -128,7 +128,8 @@ static int  Control( demux_t *, int, va_list );
 static int  Ogg_ReadPage     ( demux_t *, ogg_page * );
 static void Ogg_DecodePacket ( demux_t *, logical_stream_t *, ogg_packet * );
 static unsigned Ogg_OpusPacketDuration( ogg_packet * );
-static void Ogg_SendOrQueueBlocks( demux_t *, logical_stream_t *, block_t * );
+static void Ogg_QueueBlocks( demux_t *, logical_stream_t *, block_t * );
+static void Ogg_SendQueuedBlocks( demux_t *, logical_stream_t * );
 
 static void Ogg_CreateES( demux_t *p_demux );
 static int Ogg_BeginningOfStream( demux_t *p_demux );
@@ -136,6 +137,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux );
 static void Ogg_EndOfStream( demux_t *p_demux );
 
 /* */
+static void Ogg_LogicalStreamInit( logical_stream_t *p_stream );
 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 );
 static void Ogg_ResetStream( logical_stream_t *p_stream );
@@ -196,10 +198,6 @@ static void fill_channels_info(audio_format_t *audio)
         audio->i_physical_channels = pi_channels_map[chans];
 }
 
-/* Special TS value: don't send or derive any pts/pcr from it.
-   Represents TS state prior first known valid timestamp */
-#define VLC_TS_UNKNOWN (VLC_TS_INVALID + 1)
-
 /*****************************************************************************
  * Open: initializes ogg demux structures
  *****************************************************************************/
@@ -236,9 +234,6 @@ static int Open( vlc_object_t * p_this )
     p_sys->i_length = -1;
     p_sys->b_preparsing_done = false;
 
-    vlc_stream_Control( p_demux->s, STREAM_GET_PTS_DELAY,
-                        &p_sys->i_access_delay );
-
     /* Set exported functions */
     p_demux->pf_demux = Demux;
     p_demux->pf_control = Control;
@@ -278,7 +273,7 @@ static void Close( vlc_object_t *p_this )
 }
 
 
-static void Ogg_GeneratePCR( demux_t * p_demux )
+static mtime_t Ogg_GeneratePCR( demux_t * p_demux )
 {
     demux_sys_t *p_sys = p_demux->p_sys;
     /* We will consider the lowest PCR among tracks, because the audio core badly
@@ -293,12 +288,10 @@ static void Ogg_GeneratePCR( demux_t * p_demux )
             continue;
         if( p_stream->fmt.i_codec == VLC_CODEC_OGGSPOTS )
             continue;
-        if( p_stream->i_pcr <= VLC_TS_UNKNOWN )
+        if( p_stream->i_pcr == VLC_TS_INVALID )
             continue;
         if ( p_stream->b_finished || p_stream->b_initializing )
             continue;
-        if ( p_stream->p_preparse_block )
-            continue;
         if( i_pcr_candidate == VLC_TS_INVALID
             || p_stream->i_pcr <= i_pcr_candidate )
         {
@@ -306,24 +299,7 @@ static void Ogg_GeneratePCR( demux_t * p_demux )
         }
     }
 
-    if ( i_pcr_candidate != VLC_TS_INVALID && p_sys->i_pcr != i_pcr_candidate )
-    {
-        if ( p_sys->i_streams == 1 && p_sys->i_access_delay )
-        {
-            int64_t i_pcr_jitter = i_pcr_candidate - p_sys->i_pcr;
-            if ( i_pcr_jitter > p_sys->i_pcr_jitter )
-            {
-                p_sys->i_pcr_jitter = i_pcr_jitter;
-                if ( p_sys->i_access_delay < i_pcr_jitter )
-                    msg_Warn( p_demux, "Consider increasing access caching variable from %"PRId64" to >%"PRId64,
-                              p_sys->i_access_delay / 1000, i_pcr_jitter / 1000 );
-            }
-        }
-
-        p_sys->i_pcr = i_pcr_candidate;
-        if( likely( !p_sys->b_slave ) )
-            es_out_SetPCR( p_demux->out, p_sys->i_pcr );
-    }
+    return i_pcr_candidate;
 }
 
 /*****************************************************************************
@@ -336,7 +312,6 @@ static int Demux( demux_t * p_demux )
     demux_sys_t *p_sys = p_demux->p_sys;
     ogg_packet  oggpacket;
     int         i_stream;
-    bool b_skipping = false;
     bool b_canseek;
 
     int i_active_streams = p_sys->i_streams;
@@ -454,12 +429,6 @@ static int Demux( demux_t * p_demux )
         }
     }
 
-    b_skipping = false;
-    for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
-    {
-        b_skipping |= p_sys->pp_stream[i_stream]->i_skip_frames;
-    }
-
     for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
     {
         logical_stream_t *p_stream = p_sys->pp_stream[i_stream];
@@ -498,43 +467,8 @@ static int Demux( demux_t * p_demux )
                     p_sys->current_page.body_len )
         );
 
-        const int i_page_packets = ogg_page_packets( &p_sys->current_page );
-        bool b_doprepcr = false;
-
-        if ( p_stream->i_pcr < VLC_TS_0 && ogg_page_granulepos( &p_sys->current_page ) > 0 )
-        {
-            // PASS 0
-            if ( p_stream->fmt.i_codec == VLC_CODEC_OPUS ||
-                 p_stream->fmt.i_codec == VLC_CODEC_VORBIS ||
-                 p_stream->fmt.i_codec == VLC_CODEC_SPEEX ||
-                 p_stream->fmt.i_cat == VIDEO_ES )
-            {
-                assert( p_stream->prepcr.pp_blocks == NULL );
-                b_doprepcr = true;
-            }
-        }
-
-        int i_real_page_packets = 0;
         while( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
         {
-            i_real_page_packets++;
-            int i_max_packets = __MAX(i_page_packets, i_real_page_packets);
-            if ( b_doprepcr && p_stream->prepcr.i_size < i_max_packets )
-            {
-                /* always double alloc for performance */
-                i_max_packets = __MAX( i_max_packets << 1, 255 );
-                /* alloc or realloc */
-                block_t **pp_realloc = realloc( p_stream->prepcr.pp_blocks,
-                                                sizeof(block_t *) * i_max_packets );
-                if ( !pp_realloc )
-                {
-                    /* drop it then */
-                    continue;
-                }
-                p_stream->prepcr.i_size = i_max_packets;
-                p_stream->prepcr.pp_blocks = pp_realloc;
-            }
-
             /* Read info from any secondary header packets, if there are any */
             if( p_stream->i_secondary_header_packets > 0 )
             {
@@ -565,11 +499,6 @@ static int Demux( demux_t * p_demux )
                 p_stream->i_data_start = vlc_stream_Tell( p_demux->s );
             }
 
-            /* If any streams have i_skip_frames, only decode (pre-roll)
-             *  for those streams, but don't skip headers */
-            if ( b_skipping && p_stream->i_skip_frames == 0
-                 && p_stream->i_secondary_header_packets ) continue;
-
             if( p_stream->b_reinit )
             {
                 p_stream->b_reinit = false;
@@ -582,109 +511,6 @@ static int Demux( demux_t * p_demux )
             Ogg_DecodePacket( p_demux, p_stream, &oggpacket );
         }
 
-        if ( p_stream->prepcr.pp_blocks )
-        {
-            mtime_t i_end = Ogg_GranuleToTime( p_stream,
-                                               ogg_page_granulepos(  &p_sys->current_page ),
-                                               false, false );
-            mtime_t i_end_backup = i_end;
-
-#ifdef HAVE_LIBVORBIS
-            int i_prev_blocksize = 0;
-#endif
-            // PASS 1
-            for( int i=0; i<p_stream->prepcr.i_used; i++ )
-            {
-                block_t *p_block = p_stream->prepcr.pp_blocks[i];
-                ogg_packet dumb_packet;
-                dumb_packet.bytes = p_block->i_buffer;
-                dumb_packet.packet = p_block->p_buffer;
-
-                switch( p_stream->fmt.i_codec )
-                {
-                case VLC_CODEC_SPEEX:
-                    p_block->i_nb_samples = p_stream->special.speex.i_framesize *
-                            p_stream->special.speex.i_framesperpacket;
-                    break;
-                case VLC_CODEC_OPUS:
-                    p_block->i_nb_samples = Ogg_OpusPacketDuration( &dumb_packet );
-                    break;
-#ifdef HAVE_LIBVORBIS
-                case VLC_CODEC_VORBIS:
-                {
-                    if( !VORBIS_HEADERS_VALID(p_stream) )
-                    {
-                        msg_Err( p_demux, "missing vorbis headers, can't compute block size" );
-                        break;
-                    }
-                    long i_blocksize = vorbis_packet_blocksize(
-                                p_stream->special.vorbis.p_info, &dumb_packet );
-                    if ( i_prev_blocksize )
-                        p_block->i_nb_samples = ( i_blocksize + i_prev_blocksize ) / 4;
-                    else
-                        p_block->i_nb_samples = i_blocksize / 2;
-                    i_prev_blocksize = i_blocksize;
-                }
-#endif
-                }
-            }
-
-            // PASS 2
-            bool b_fixed = false;
-            date_t d = p_stream->dts;
-            date_Set( &d, p_sys->i_nzpcr_offset + i_end - VLC_TS_0 );
-            for( int i=p_stream->prepcr.i_used - 1; i>=0; i-- )
-            {
-                block_t *p_block = p_stream->prepcr.pp_blocks[i];
-                switch( p_stream->fmt.i_codec )
-                {
-                case VLC_CODEC_SPEEX:
-                case VLC_CODEC_OPUS:
-                case VLC_CODEC_VORBIS:
-                    if( i_end != VLC_TS_INVALID )
-                    {
-                        date_Decrement( &d, p_block->i_nb_samples );
-                        p_block->i_pts = date_Get( &d ) + VLC_TS_0;
-                    }
-                    else
-                    {
-                        p_block->i_pts = VLC_TS_INVALID;
-                        if( p_sys->i_nzpcr_offset == 0 ) /* not on chained streams */
-                            p_block->i_flags |= BLOCK_FLAG_PREROLL;
-                    }
-                    b_fixed = true;
-                    break;
-                default:
-                    if ( p_stream->fmt.i_cat == VIDEO_ES )
-                    {
-                        if( i_end != VLC_TS_INVALID )
-                        {
-                            date_Decrement( &d, 1 );
-                            p_block->i_pts = date_Get( &d ) + VLC_TS_0;
-                        }
-                        b_fixed = true;
-                    }
-                }
-            }
-
-            if ( b_fixed )
-            {
-                i_end = i_end_backup; /* as set above */
-                if( i_end != VLC_TS_INVALID )
-                    p_stream->i_pcr = i_end + p_sys->i_nzpcr_offset;
-            }
-
-            FREENULL(p_stream->prepcr.pp_blocks);
-            p_stream->prepcr.i_used = 0;
-
-            Ogg_SendOrQueueBlocks( p_demux, p_stream, NULL );
-        }
-
-        mtime_t i_pcr = Ogg_GranuleToTime( p_stream,
-                                           ogg_page_granulepos( &p_sys->current_page ),
-                                           !p_stream->b_contiguous, false );
-        if ( i_pcr != VLC_TS_INVALID )
-            p_stream->i_pcr = p_sys->i_nzpcr_offset + i_pcr;
 
         if( !p_sys->b_page_waiting )
             break;
@@ -712,8 +538,37 @@ static int Demux( demux_t * p_demux )
         }
     }
 
-    if( !b_skipping && p_sys->b_preparsing_done )
-        Ogg_GeneratePCR( p_demux );
+    if( p_sys->b_preparsing_done )
+    {
+        mtime_t i_pcr;
+
+        /* Generate First PCR */
+        if( p_sys->i_pcr == VLC_TS_INVALID )
+        {
+            i_pcr = Ogg_GeneratePCR( p_demux );
+            if( i_pcr != VLC_TS_INVALID && i_pcr != p_sys->i_pcr )
+            {
+                p_sys->i_pcr = i_pcr;
+                if( likely( !p_sys->b_slave ) )
+                    es_out_SetPCR( p_demux->out, p_sys->i_pcr );
+            }
+        }
+
+        if( p_sys->i_pcr != VLC_TS_INVALID )
+        {
+            for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
+                Ogg_SendQueuedBlocks( p_demux, p_sys->pp_stream[i_stream] );
+
+            /* Generate Current PCR */
+            i_pcr = Ogg_GeneratePCR( p_demux );
+            if( i_pcr != VLC_TS_INVALID && i_pcr != p_sys->i_pcr )
+            {
+                p_sys->i_pcr = i_pcr;
+                if( likely( !p_sys->b_slave ) )
+                    es_out_SetPCR( p_demux->out, p_sys->i_pcr );
+            }
+        }
+    }
 
     return VLC_DEMUXER_SUCCESS;
 }
@@ -728,21 +583,25 @@ static void Ogg_ResetStream( logical_stream_t *p_stream )
 #endif
     /* we'll trash all the data until we find the next pcr */
     p_stream->b_reinit = true;
-    p_stream->i_pcr = VLC_TS_UNKNOWN;
+    p_stream->i_pcr = VLC_TS_INVALID;
+    p_stream->i_next_block_flags = 0;
     date_Set( &p_stream->dts, VLC_TS_INVALID );
     ogg_stream_reset( &p_stream->os );
-    FREENULL( p_stream->prepcr.pp_blocks );
-    p_stream->prepcr.i_size = 0;
-    p_stream->prepcr.i_used = 0;
+    block_ChainRelease( p_stream->queue.p_blocks );
+    p_stream->queue.p_blocks = NULL;
+    p_stream->queue.pp_append = &p_stream->queue.p_blocks;
 }
 
-static void Ogg_ResetStreamsHelper( demux_sys_t *p_sys )
+static void Ogg_PreparePostSeek( demux_sys_t *p_sys )
 {
     for( int i = 0; i < p_sys->i_streams; i++ )
+    {
         Ogg_ResetStream( p_sys->pp_stream[i] );
+        p_sys->pp_stream[i]->i_next_block_flags = BLOCK_FLAG_DISCONTINUITY;
+    }
 
     ogg_sync_reset( &p_sys->oy );
-    p_sys->i_pcr = VLC_TS_UNKNOWN;
+    p_sys->i_pcr = VLC_TS_INVALID;
 }
 
 static logical_stream_t * Ogg_GetSelectedStream( demux_t *p_demux )
@@ -826,7 +685,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
             vlc_stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b );
             if ( Oggseek_BlindSeektoAbsoluteTime( p_demux, p_stream, VLC_TS_0 + i64, b ) )
             {
-                Ogg_ResetStreamsHelper( p_sys );
+                Ogg_PreparePostSeek( p_sys );
                 if( acc )
                     es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
                                     VLC_TS_0 + i64 );
@@ -891,13 +750,13 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
             acc = va_arg( args, int );
             if ( p_sys->i_length <= 0 || !b /* || ! STREAM_CAN_FASTSEEK */ )
             {
-                Ogg_ResetStreamsHelper( p_sys );
+                Ogg_PreparePostSeek( p_sys );
                 return Oggseek_BlindSeektoPosition( p_demux, p_stream, f, b );
             }
 
             assert( p_sys->i_length > 0 );
             i64 = CLOCK_FREQ * p_sys->i_length * f;
-            Ogg_ResetStreamsHelper( p_sys );
+            Ogg_PreparePostSeek( p_sys );
             if ( Oggseek_SeektoAbsolutetime( p_demux, p_stream, VLC_TS_0 + i64 ) >= 0 )
             {
                 if( acc )
@@ -971,7 +830,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
             vlc_stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b );
             if ( Oggseek_BlindSeektoAbsoluteTime( p_demux, p_stream, VLC_TS_0 + i64, b ) )
             {
-                Ogg_ResetStreamsHelper( p_sys );
+                Ogg_PreparePostSeek( p_sys );
                 es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
                                 VLC_TS_0 + i64 );
                 p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
@@ -1092,72 +951,170 @@ static void Ogg_SetNextFrame( demux_t *p_demux, logical_stream_t *p_stream,
     }
 }
 
-static void Ogg_SendOrQueueBlocks( demux_t *p_demux, logical_stream_t *p_stream,
-                                   block_t *p_block )
+static mtime_t Ogg_FixupOutputQueue( demux_t *p_demux, logical_stream_t *p_stream )
 {
-    demux_sys_t *p_ogg = p_demux->p_sys;
-    if ( (!p_stream->p_es || p_stream->prepcr.pp_blocks || p_stream->i_pcr == VLC_TS_UNKNOWN) &&
-         p_ogg->i_nzpcr_offset == 0 /* Not on chained streams */ )
+    mtime_t i_enddts = VLC_TS_INVALID;
+
+#ifdef HAVE_LIBVORBIS
+    long i_prev_blocksize = 0;
+#else
+    VLC_UNUSED(p_demux);
+#endif
+    // PASS 1, set number of samples
+    unsigned i_total_samples = 0;
+    for( block_t *p_block = p_stream->queue.p_blocks; p_block; p_block = p_block->p_next )
     {
-        if ( !p_block ) return;
-        if ( p_stream->prepcr.pp_blocks )
+        if( p_block->i_dts != VLC_TS_INVALID )
         {
-            assert( p_stream->prepcr.i_size );
-            p_stream->prepcr.pp_blocks[p_stream->prepcr.i_used++] = p_block;
+            i_enddts = p_block->i_dts;
+            break;
         }
-        DemuxDebug( msg_Dbg( p_demux, "block prepcr append > pts %"PRId64" spcr %"PRId64" pcr %"PRId64,
-                             p_block->i_pts, p_stream->i_pcr, p_ogg->i_pcr ); )
-        block_ChainAppend( & p_stream->p_preparse_block, p_block );
-    }
-    else
-    {
-        /* Because ES creation is delayed for preparsing */
-        if ( p_stream->p_preparse_block )
+
+        if( p_block->i_flags & BLOCK_FLAG_HEADER )
+            continue;
+
+        ogg_packet dumb_packet;
+        dumb_packet.bytes = p_block->i_buffer;
+        dumb_packet.packet = p_block->p_buffer;
+
+        switch( p_stream->fmt.i_codec )
         {
-            block_t *temp = p_stream->p_preparse_block;
-            while ( temp )
+            case VLC_CODEC_SPEEX:
+                p_block->i_nb_samples = p_stream->special.speex.i_framesize *
+                                        p_stream->special.speex.i_framesperpacket;
+                break;
+            case VLC_CODEC_OPUS:
+                p_block->i_nb_samples = Ogg_OpusPacketDuration( &dumb_packet );
+                break;
+#ifdef HAVE_LIBVORBIS
+            case VLC_CODEC_VORBIS:
             {
-                block_t *tosend = temp;
-                temp = temp->p_next;
-                tosend->p_next = NULL;
-
-                if( tosend->i_dts == VLC_TS_INVALID )
+                if( !VORBIS_HEADERS_VALID(p_stream) )
                 {
-                    tosend->i_dts = tosend->i_pts;
+                    msg_Err( p_demux, "missing vorbis headers, can't compute block size" );
+                    break;
                 }
+                long i_blocksize = vorbis_packet_blocksize( p_stream->special.vorbis.p_info,
+                                                            &dumb_packet );
+                if ( i_prev_blocksize )
+                    p_block->i_nb_samples = ( i_blocksize + i_prev_blocksize ) / 4;
+                else
+                    p_block->i_nb_samples = i_blocksize / 2;
+                i_prev_blocksize = i_blocksize;
+                break;
+            }
+#endif
+            default:
+                break;
+        }
+        i_total_samples += p_block->i_nb_samples;
+    }
 
-                if( tosend->i_dts == VLC_TS_INVALID )
-                {
-                    /* Don't send metadata from chained streams */
-                    block_Release( tosend );
-                    continue;
-                }
+    // PASS 2
+    if( i_enddts != VLC_TS_INVALID )
+    {
+        date_t d = p_stream->dts;
+        date_Set( &d, i_enddts );
+        i_enddts = date_Decrement( &d, i_total_samples );
+        for( block_t *p_block = p_stream->queue.p_blocks; p_block; p_block = p_block->p_next )
+        {
+            if( p_block->i_dts != VLC_TS_INVALID )
+                break;
+            if( p_block->i_flags & BLOCK_FLAG_HEADER )
+                continue;
+            p_block->i_dts = date_Get( &d );
+            date_Increment( &d, p_block->i_nb_samples );
+        }
+    } /* else can't do anything, no timestamped blocks in stream */
 
-                DemuxDebug( msg_Dbg( p_demux, "block sent from preparse > dts %"PRId64" pts %"PRId64" spcr %"PRId64" pcr %"PRId64,
-                         tosend->i_dts, tosend->i_pts, p_stream->i_pcr, p_ogg->i_pcr ); )
+    return i_enddts;
+}
 
-                if ( p_ogg->i_pcr == VLC_TS_INVALID && tosend->i_dts != VLC_TS_INVALID )
-                {
-                    p_ogg->i_pcr = tosend->i_dts;
-                    if( likely( !p_ogg->b_slave ) )
-                        es_out_SetPCR( p_demux->out, p_ogg->i_pcr );
-                }
+static void Ogg_QueueBlocks( demux_t *p_demux, logical_stream_t *p_stream, block_t *p_block )
+{
+    demux_sys_t *p_sys = p_demux->p_sys;
+    VLC_UNUSED(p_sys);
+
+    if( p_block == NULL )
+    {
+        assert( p_block != NULL );
+        return;
+    }
+
+    block_ChainLastAppend( &p_stream->queue.pp_append, p_block );
+
+    if( p_stream->i_pcr == VLC_TS_INVALID && p_block->i_dts != VLC_TS_INVALID )
+    {
+        /* fixup queue */
+        p_stream->i_pcr = Ogg_FixupOutputQueue( p_demux, p_stream );
+    }
+
+    DemuxDebug( msg_Dbg( p_demux, "%4.4s block queued > dts %"PRId64" spcr %"PRId64" pcr %"PRId64,
+                         (char*)&p_stream->fmt.i_codec, p_block->i_dts, p_stream->i_pcr, p_sys->i_pcr ); )
+}
+
+static void Ogg_SendQueuedBlocks( demux_t *p_demux, logical_stream_t *p_stream )
+{
+    demux_sys_t *p_sys = p_demux->p_sys;
+
+    while( p_stream->queue.p_blocks )
+    {
+        block_t *p_queued = p_stream->queue.p_blocks;
+        p_stream->queue.p_blocks = p_queued->p_next;
+        p_queued->p_next = NULL;
+
+        if( p_queued->i_dts == VLC_TS_INVALID )
+            p_queued->i_dts = p_queued->i_pts;
 
-                es_out_Send( p_demux->out, p_stream->p_es, tosend );
+        if( p_queued->i_flags & BLOCK_FLAG_HEADER )
+        {
+            if( p_sys->i_nzpcr_offset > 0 || /* Don't send metadata from chained streams */
+                p_stream->fmt.i_extra > 0 )  /* Don't send metadata if configured by extradata */
+            {
+                block_Release( p_queued );
+                continue;
             }
-            p_stream->p_preparse_block = NULL;
+            p_queued->i_flags &= ~BLOCK_FLAG_HEADER;
         }
 
-        if ( p_block )
+        unsigned i_toskip = 0;
+        if( p_stream->i_skip_frames > 0 )
         {
-            DemuxDebug( msg_Dbg( p_demux, "block sent directly > pts %"PRId64" spcr %"PRId64" pcr %"PRId64,
-                     p_block->i_pts, p_stream->i_pcr, p_ogg->i_pcr ) );
-            if ( p_stream->p_es )
-                es_out_Send( p_demux->out, p_stream->p_es, p_block );
+            if( p_sys->i_nzpcr_offset > 0 )
+            {
+                /* not preskip handling on chained streams */
+                p_stream->i_skip_frames = 0;
+            }
             else
-                block_Release( p_block );
+            {
+                i_toskip = __MIN( p_stream->i_skip_frames, p_queued->i_nb_samples );
+                p_stream->i_skip_frames -= i_toskip;
+                p_queued->i_nb_samples -= i_toskip;
+                if( p_queued->i_nb_samples == 0 )
+                    p_queued->i_flags |= BLOCK_FLAG_PREROLL;
+            }
         }
+
+        p_queued->i_flags |= p_stream->i_next_block_flags;
+        p_stream->i_next_block_flags = 0;
+        p_stream->i_pcr = p_queued->i_dts;
+
+        DemuxDebug( msg_Dbg( p_demux, "%4.4s block sent > dts %"PRId64" pts %"PRId64" spcr %"PRId64" pcr %"PRId64
+                             " samples (%d/%d)",
+                             (char*)&p_stream->fmt.i_codec, p_queued->i_dts,
+                             p_queued->i_pts, p_stream->i_pcr, p_sys->i_pcr,
+                             p_queued->i_nb_samples, i_toskip ); );
+
+        assert( p_sys->i_pcr != VLC_TS_INVALID );
+
+        if( p_stream->p_es )
+            es_out_Send( p_demux->out, p_stream->p_es, p_queued );
+        else
+            block_Release( p_queued );
     }
+
+    assert( p_stream->queue.p_blocks == NULL );
+    p_stream->queue.pp_append = &p_stream->queue.p_blocks;
 }
 
 static bool Ogg_IsHeaderPacket( const logical_stream_t *p_stream,
@@ -1354,13 +1311,20 @@ static void Ogg_DecodePacket( demux_t *p_demux,
         date_Set( &p_stream->dts, i_dts );
 
     /* Write end granule as next start, or do interpolation */
-    if( !Ogg_IsHeaderPacket( p_stream, p_oggpacket ) )
+    bool b_header = Ogg_IsHeaderPacket( p_stream, p_oggpacket );
+    if( !b_header )
         Ogg_SetNextFrame( p_demux, p_stream, p_oggpacket );
 
     if( !b_selected )
     {
         /* This stream isn't currently selected so we don't need to decode it,
          * but we did need to store its pcr as it might be selected later on */
+        if( !b_header && !p_stream->b_initializing )
+        {
+            mtime_t i_pcr = date_Get( &p_stream->dts );
+            if( i_pcr != VLC_TS_INVALID )
+                p_stream->i_pcr = p_sys->i_nzpcr_offset + i_pcr;
+        }
         return;
     }
 
@@ -1385,34 +1349,11 @@ static void Ogg_DecodePacket( demux_t *p_demux,
     if( p_stream->fmt.i_codec == VLC_CODEC_OPUS ) /* also required for trimming */
         p_block->i_nb_samples = Ogg_OpusPacketDuration( p_oggpacket );
 
-    DemuxDebug( msg_Dbg(p_demux, "block set from granule %"PRId64" to pts/pcr %"PRId64" skip %d",
-                        p_oggpacket->granulepos, p_block->i_dts, p_stream->i_skip_frames); )
+    DemuxDebug( msg_Dbg(p_demux, "%4.4s block set from granule %"PRId64" to pts/pcr %"PRId64" skip %d",
+                        (char *) &p_stream->fmt.i_codec, p_oggpacket->granulepos,
+                        p_block->i_dts, p_stream->i_skip_frames); )
 
     /* may need to preroll after a seek or in case of preskip */
-    if ( p_stream->i_skip_frames > 0 )
-    {
-        if( p_stream->fmt.i_codec == VLC_CODEC_OPUS )
-        {
-            if( p_stream->i_skip_frames >= p_block->i_nb_samples )
-            {
-                if( p_sys->i_nzpcr_offset == 0 ) /* not on chained streams */
-                    p_block->i_flags |= BLOCK_FLAG_PREROLL;
-                p_stream->i_skip_frames -= p_block->i_nb_samples;
-                p_block->i_nb_samples = 0;
-            }
-            else
-            {
-                p_block->i_nb_samples -= p_stream->i_skip_frames;
-                p_stream->i_skip_frames = 0;
-            }
-        }
-        else
-        {
-            if( p_sys->i_nzpcr_offset == 0 ) /* not on chained streams */
-                p_block->i_flags |= BLOCK_FLAG_PREROLL;
-            p_stream->i_skip_frames--;
-        }
-    }
 
     /* Conditional block fixes */
     if ( p_stream->fmt.i_cat == VIDEO_ES )
@@ -1489,10 +1430,13 @@ static void Ogg_DecodePacket( demux_t *p_demux,
             p_block->i_buffer = 0;
     }
 
+    if( b_header )
+        p_block->i_flags |= BLOCK_FLAG_HEADER;
+
     memcpy( p_block->p_buffer, p_oggpacket->packet + i_header_len,
             p_oggpacket->bytes - i_header_len );
 
-    Ogg_SendOrQueueBlocks( p_demux, p_stream, p_block );
+    Ogg_QueueBlocks( p_demux, p_stream, p_block );
 }
 
 static unsigned Ogg_OpusPacketDuration( ogg_packet *p_oggpacket )
@@ -1529,21 +1473,18 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
              * We found the beginning of our first logical stream. */
             while( ogg_page_bos( &p_ogg->current_page ) )
             {
-                logical_stream_t *p_stream = calloc( 1, sizeof(logical_stream_t) );
+                logical_stream_t *p_stream = malloc( sizeof(logical_stream_t) );
                 if( unlikely( !p_stream ) )
                     return VLC_ENOMEM;
 
-                TAB_APPEND( p_ogg->i_streams, p_ogg->pp_stream, p_stream );
-
-                es_format_Init( &p_stream->fmt, UNKNOWN_ES, 0 );
-                es_format_Init( &p_stream->fmt_old, UNKNOWN_ES, 0 );
-                p_stream->b_initializing = true;
-                p_stream->b_contiguous = true; /* default */
+                Ogg_LogicalStreamInit( p_stream );
 
                 /* Setup the logical stream */
                 p_stream->i_serial_no = ogg_page_serialno( &p_ogg->current_page );
                 ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
 
+                TAB_APPEND( p_ogg->i_streams, p_ogg->pp_stream, p_stream );
+
                 /* Extract the initial header from the first page and verify
                  * the codec type of this Ogg bitstream */
                 if( ogg_stream_pagein( &p_stream->os, &p_ogg->current_page ) < 0 )
@@ -2190,7 +2131,7 @@ static int Ogg_BeginningOfStream( demux_t *p_demux )
         else
             p_ogg->i_bitrate += p_stream->fmt.i_bitrate;
 
-        p_stream->i_pcr = VLC_TS_UNKNOWN;
+        p_stream->i_pcr = VLC_TS_INVALID;
         p_stream->b_reinit = false;
     }
 
@@ -2256,6 +2197,18 @@ static void Ogg_CleanSpecificData( logical_stream_t *p_stream )
 #endif
 }
 
+static void Ogg_LogicalStreamInit( logical_stream_t *p_stream )
+{
+    memset( p_stream, 0, sizeof(logical_stream_t) );
+    es_format_Init( &p_stream->fmt, UNKNOWN_ES, 0 );
+    es_format_Init( &p_stream->fmt_old, UNKNOWN_ES, 0 );
+    p_stream->i_pcr = VLC_TS_INVALID;
+    date_Set( &p_stream->dts, VLC_TS_INVALID );
+    p_stream->b_initializing = true;
+    p_stream->b_contiguous = true; /* default */
+    p_stream->queue.pp_append = &p_stream->queue.p_blocks;
+}
+
 /**
  * This function delete and release all data associated to a logical_stream_t
  */
@@ -2285,12 +2238,7 @@ static void Ogg_LogicalStreamDelete( demux_t *p_demux, logical_stream_t *p_strea
         p_sys->p_skelstream = NULL;
 
     /* Shouldn't happen */
-    if ( unlikely( p_stream->p_preparse_block ) )
-    {
-        block_ChainRelease( p_stream->p_preparse_block );
-        p_stream->p_preparse_block = NULL;
-    }
-    free( p_stream->prepcr.pp_blocks );
+    block_ChainRelease( p_stream->queue.p_blocks );
 
     free( p_stream );
 }
@@ -3331,6 +3279,8 @@ static int dirac_bool( bs_t *p_bs )
 static bool Ogg_ReadDiracHeader( logical_stream_t *p_stream,
                                  ogg_packet *p_oggpacket )
 {
+    p_stream->special.dirac.b_old = (p_oggpacket->packet[0] == 'K');
+
     static const struct {
         uint32_t u_n /* numerator */, u_d /* denominator */;
     } p_dirac_frate_tbl[] = { /* table 10.3 */
@@ -3347,8 +3297,6 @@ static bool Ogg_ReadDiracHeader( logical_stream_t *p_stream,
 
     bs_t bs;
 
-    p_stream->i_granule_shift = 22; /* not 32 */
-
     /* Backing up stream headers is not required -- seqhdrs are repeated
      * thoughout the stream at suitable decoding start points */
     p_stream->b_force_backup = false;
diff --git a/modules/demux/ogg.h b/modules/demux/ogg.h
index 1914762e41..4517eabb17 100644
--- a/modules/demux/ogg.h
+++ b/modules/demux/ogg.h
@@ -83,6 +83,7 @@ typedef struct logical_stream_s
     bool b_reinit;
     bool b_oggds;
     int i_granule_shift;
+    int i_next_block_flags;
 
     /* Opus has a starting offset in the headers. */
     int i_pre_skip;
@@ -108,12 +109,9 @@ typedef struct logical_stream_s
     /* All blocks which can't be sent because track PCR isn't known yet */
     struct
     {
-        block_t **pp_blocks;
-        uint8_t i_size; /* max 255 */
-        uint8_t i_used;
-    } prepcr;
-    /* All blocks that are queued because ES isn't created yet */
-    block_t *p_preparse_block;
+        block_t *p_blocks;
+        block_t **pp_append;
+    } queue;
 
     union
     {
@@ -134,6 +132,7 @@ typedef struct logical_stream_s
         struct
         {
             bool b_interlaced;
+            bool b_old;
         } dirac;
         struct
         {
@@ -174,9 +173,6 @@ typedef struct
      * the sub-streams */
     mtime_t i_pcr;
     mtime_t i_nzpcr_offset;
-    /* informative only */
-    mtime_t i_pcr_jitter;
-    int64_t i_access_delay;
 
     /* new stream or starting from a chain */
     bool b_chained_boundary;
diff --git a/modules/demux/ogg_granule.c b/modules/demux/ogg_granule.c
index 524533dd87..e29dcfed42 100644
--- a/modules/demux/ogg_granule.c
+++ b/modules/demux/ogg_granule.c
@@ -56,7 +56,10 @@ bool Ogg_IsKeyFrame( const logical_stream_t *p_stream, const ogg_packet *p_packe
         case VLC_CODEC_VP8:
             return ( ( ( p_packet->granulepos >> 3 ) & 0x07FFFFFF ) == 0 );
         case VLC_CODEC_DIRAC:
-            return ( p_packet->granulepos & 0xFF8000FF );
+            if( p_stream->special.dirac.b_old )
+                return (p_packet->granulepos & 0x3FFFFFFF) == 0;
+            else
+                return (p_packet->granulepos & 0xFF8000FF) == 0;
         default:
             return true;
     }
@@ -74,7 +77,10 @@ int64_t Ogg_GetKeyframeGranule( const logical_stream_t *p_stream, int64_t i_gran
         case VLC_CODEC_DAALA:
             return ( i_granule >> p_stream->i_granule_shift ) << p_stream->i_granule_shift;
         case VLC_CODEC_DIRAC:
-            return ( i_granule >> 31 ) << 31;
+            if( p_stream->special.dirac.b_old )
+                return ( i_granule >> 30 ) << 30;
+            else
+                return ( i_granule >> 31 ) << 31;
         default:
             /* No change, that's keyframe */
             return i_granule;
@@ -83,7 +89,7 @@ int64_t Ogg_GetKeyframeGranule( const logical_stream_t *p_stream, int64_t i_gran
 
 static int64_t Ogg_GranuleToSampleDelta( const logical_stream_t *p_stream, int64_t i_granule )
 {
-    if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC )
+    if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC && !p_stream->special.dirac.b_old )
         return (i_granule >> 9) & 0x1fff;
     else
         return -1;
@@ -105,7 +111,10 @@ static int64_t Ogg_GranuleToSample( const logical_stream_t *p_stream, int64_t i_
         case VLC_CODEC_OGGSPOTS:
             return i_granule >> p_stream->i_granule_shift;
         case VLC_CODEC_DIRAC:
-            return (i_granule >> 31);
+            if( p_stream->special.dirac.b_old )
+                return (i_granule >> 30) + (i_granule & 0x3FFFFFFF);
+            else
+                return (i_granule >> 31);
         case VLC_CODEC_OPUS:
         case VLC_CODEC_VORBIS:
         case VLC_CODEC_SPEEX:



More information about the vlc-commits mailing list