]> git.sesse.net Git - vlc/commitdiff
* modules/demux/ogg.c, modules/codec/vorbis.c: seeking in an ogg stream is
authorGildas Bazin <gbazin@videolan.org>
Sat, 2 Nov 2002 18:13:22 +0000 (18:13 +0000)
committerGildas Bazin <gbazin@videolan.org>
Sat, 2 Nov 2002 18:13:22 +0000 (18:13 +0000)
   working fine now, + misc other improvements.

modules/codec/vorbis.c
modules/demux/ogg.c

index 2888051edfb34af747fdcc5abd8754b99b1604d8..1830c9eff5aee957a767d6e3d028949b37fc922c 100644 (file)
@@ -2,7 +2,7 @@
  * vorbis.c: vorbis decoder module making use of libvorbis.
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: vorbis.c,v 1.2 2002/10/27 16:58:14 gbazin Exp $
+ * $Id: vorbis.c,v 1.3 2002/11/02 18:13:22 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
@@ -188,14 +188,6 @@ static int RunDecoder( decoder_fifo_t * p_fifo )
         goto error;
     }
 
-    /* Take care of the first pts we receive. We need to be careful as a pts
-     * in vorbis language does in fact correspond to the presentation time of
-     * the _next_ packet to receive */
-    if( i_pts > 0 && i_pts != aout_DateGet( &p_dec->end_date ) )
-    {
-        aout_DateSet( &p_dec->end_date, i_pts );
-    }
-
     /* vorbis decoder thread's main loop */
     while( (!p_dec->p_fifo->b_die) && (!p_dec->p_fifo->b_error) )
     {
@@ -243,10 +235,14 @@ static void DecodePacket( dec_thread_t *p_dec )
         return;
     }
 
+    /* Date management */
+    if( i_pts > 0 && i_pts != aout_DateGet( &p_dec->end_date ) )
+    {
+        aout_DateSet( &p_dec->end_date, i_pts );
+    }
+
     if( vorbis_synthesis( &p_dec->vb, &oggpacket ) == 0 )
         vorbis_synthesis_blockin( &p_dec->vd, &p_dec->vb );
-    else
-        msg_Err( p_dec->p_fifo, "vorbis_synthesis error" );
 
     /* **pp_pcm is a multichannel float vector. In stereo, for
      * example, pp_pcm[0] is left, and pp_pcm[1] is right. i_samples is
@@ -277,16 +273,6 @@ static void DecodePacket( dec_thread_t *p_dec )
         p_aout_buffer->end_date = aout_DateIncrement( &p_dec->end_date,
                                                       i_samples );
 
-        if( i_pts > 0 && i_pts != aout_DateGet( &p_dec->end_date ) )
-        {
-            aout_DateSet( &p_dec->end_date, i_pts );
-            p_aout_buffer->end_date = aout_DateGet( &p_dec->end_date );
-        }
-        else
-        {
-            aout_DateSet( &p_dec->end_date, p_aout_buffer->end_date );
-        }
-
         aout_DecPlay( p_dec->p_aout, p_dec->p_aout_input, p_aout_buffer );
     }
 
index 79a1356648cbe8d10ed20d3973d5859d9db8b6cd..8fde9de4da03a697bc3a5b90fa5bc91af5672d49 100644 (file)
@@ -2,7 +2,7 @@
  * ogg.c : ogg stream input module for vlc
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: ogg.c,v 1.2 2002/10/27 16:59:30 gbazin Exp $
+ * $Id: ogg.c,v 1.3 2002/11/02 18:13:22 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  * 
@@ -54,10 +54,14 @@ typedef struct logical_stream_s
     es_descriptor_t  *p_es;   
     int              b_selected;                           /* newly selected */
 
-    /* info for vorbis logical streams */
+    /* program clock reference (in units of 90kHz) derived from the previous
+     * granulepos */
+    mtime_t i_pcr;
+
+    /* info from logical streams */
     int i_rate;
-    int i_channels;
     int i_bitrate;
+    int b_reinit;
 
 } logical_stream_t;
 
@@ -72,9 +76,14 @@ struct demux_sys_t
     logical_stream_t *p_stream_video;
     logical_stream_t *p_stream_audio;
 
-    mtime_t i_time;
+    /* stream we use as a time reference for demux reading speed */
+    logical_stream_t *p_stream_timeref;
+
+    /* program clock reference (in units of 90kHz) derived from the pcr of
+     * one of the sub-streams (p_stream_timeref) */
+    mtime_t i_pcr;
+
     mtime_t i_length;
-    mtime_t i_pcr; 
     int     b_seekable;
 };
 
@@ -231,6 +240,7 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
 {
     pes_packet_t  *p_pes;
     data_packet_t *p_data;
+    demux_sys_t *p_ogg = p_input->p_demux_data;
 
     if( !( p_pes = input_NewPES( p_input->p_method_data ) ) )
     {
@@ -248,12 +258,28 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
     p_pes->i_pes_size = p_oggpacket->bytes;
     p_pes->i_dts = p_oggpacket->granulepos;
 
-    /* Convert the granule into a pts */
-    p_pes->i_pts = (p_oggpacket->granulepos < 0) ? 0 :
-        p_oggpacket->granulepos * 90000 / p_stream->i_rate;
-    p_pes->i_pts = (p_oggpacket->granulepos < 0) ? 0 :
+    /* Convert the pcr into a pts */
+    p_pes->i_pts = ( p_stream->i_pcr < 0 ) ? 0 :
         input_ClockGetTS( p_input, p_input->stream.p_selected_program,
-                          p_pes->i_pts );
+                          p_stream->i_pcr );
+
+    /* Convert the next granule into a pcr */
+    p_stream->i_pcr = ( p_oggpacket->granulepos < 0 ) ? -1 :
+                           p_oggpacket->granulepos * 90000 / p_stream->i_rate;
+
+    /* Update the main pcr */
+    if( p_stream == p_ogg->p_stream_timeref )
+    {
+        if( p_ogg->p_stream_timeref->i_pcr >= 0 )
+        {
+            p_ogg->i_pcr = p_ogg->p_stream_timeref->i_pcr;
+        }
+        else
+        {
+            p_ogg->i_pcr += ( p_oggpacket->bytes * 90000
+                              / p_stream->i_bitrate / 8 );
+        }
+    }
 
     memcpy( p_data->p_payload_start, p_oggpacket->packet, p_oggpacket->bytes );
 
@@ -300,6 +326,10 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                 p_stream->i_serial_no = ogg_page_serialno( &oggpage );
                 ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
 
+                /* The first stream we find is our timeref (might be changed
+                 * later on) */
+                p_ogg->p_stream_timeref = p_stream;
+
                 /* Extract the initial header from the first page and verify
                  * the codec type of tis Ogg bitstream */
                 if( ogg_stream_pagein( &p_stream->os, &oggpage ) < 0 )
@@ -325,8 +355,7 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
 
                     /* Cheat and get additionnal info ;) */
                     oggpack_readinit( &opb, oggpacket.packet, oggpacket.bytes);
-                    oggpack_adv( &opb, 88 );
-                    p_stream->i_channels = oggpack_read( &opb, 8 );
+                    oggpack_adv( &opb, 96 );
                     p_stream->i_rate = oggpack_read( &opb, 32 );
                     oggpack_adv( &opb, 32 );
                     p_stream->i_bitrate = oggpack_read( &opb, 32 );
@@ -389,8 +418,8 @@ static int Activate( vlc_object_t * p_this )
     memset( p_ogg, 0, sizeof( demux_sys_t ) );
     p_input->p_demux_data = p_ogg;
 
-    p_ogg->i_time = 0;
     p_ogg->i_pcr  = 0;
+    p_ogg->p_stream_timeref = NULL;
     p_ogg->b_seekable = ( ( p_input->stream.b_seekable )
                         &&( p_input->stream.i_method == INPUT_METHOD_FILE ) );
 
@@ -467,6 +496,7 @@ static int Activate( vlc_object_t * p_this )
                 if( (p_ogg->p_stream_audio == NULL) )
                 {
                     p_ogg->p_stream_audio = p_stream;
+                    p_ogg->p_stream_timeref = p_stream;
                     Ogg_StreamStart( p_input, p_ogg, i_stream );
                 }
                 break;
@@ -490,6 +520,11 @@ static int Activate( vlc_object_t * p_this )
     p_input->stream.p_selected_program->b_is_ok = 1;
     vlc_mutex_unlock( &p_input->stream.stream_lock );
 
+    /* Call the pace control */
+    input_ClockManageRef( p_input,
+                          p_input->stream.p_selected_program,
+                          p_ogg->i_pcr );
+
     return 0;
 
  error:
@@ -530,7 +565,7 @@ static void Deactivate( vlc_object_t *p_this )
  *****************************************************************************/
 static int Demux( input_thread_t * p_input )
 {
-    int i, i_stream, b_eos;
+    int i, i_stream, b_eos = 0;
     ogg_page    oggpage;
     ogg_packet  oggpacket;
     demux_sys_t *p_ogg  = (demux_sys_t *)p_input->p_demux_data;
@@ -555,7 +590,7 @@ static int Demux( input_thread_t * p_input )
         }
     }
 
-    /* search new video and audio stream selected
+    /* search for new video and audio stream to select
      * if current have been unselected */
     if( ( !p_ogg->p_stream_video )
             || ( !p_ogg->p_stream_video->p_es->p_decoder_fifo ) )
@@ -581,33 +616,34 @@ static int Demux( input_thread_t * p_input )
                   &&( p_stream->p_es->p_decoder_fifo ) )
             {
                 p_ogg->p_stream_audio = p_stream;
+                p_ogg->p_stream_timeref = p_stream;
                 break;
             }
         }
     }
 
-    /* Update program clock reference */
-    p_ogg->i_pcr = p_ogg->i_time * 9 / 100;
-
-    if( (p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT)
-         || (input_ClockManageControl( p_input,
-                                      p_input->stream.p_selected_program,
-                                      (mtime_t)0 ) == PAUSE_S) )
+    if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
     {
         msg_Warn( p_input, "synchro reinit" );
-        p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK;
+
+        /* An ogg packet does only contain the starting date of the next
+         * packet, not its own starting date.
+         * As a quick work around, we just skip an oggpage */
+
+        for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
+        {
+            /* we'll trash all the data until we find the next pcr */
+            p_stream->b_reinit = 1;
+            p_ogg->i_pcr = 0;
+        }
     }
 
-    /* Call the pace control. */
-    input_ClockManageRef( p_input,
-                          p_input->stream.p_selected_program,
-                          p_ogg->i_pcr );
 
     /* Demux ogg pages from the stream */
-    b_eos = 0;
-    for( i = 0; i < PAGES_READ_ONCE; i++ )
+    for( i = 0; (i < PAGES_READ_ONCE) || p_ogg->p_stream_timeref->b_reinit;
+         i++ )
     {
-        if( Ogg_ReadPage(p_input, p_ogg, &oggpage ) != VLC_SUCCESS )
+        if( Ogg_ReadPage( p_input, p_ogg, &oggpage ) != VLC_SUCCESS )
         {
             b_eos = 1;
             break;
@@ -622,27 +658,46 @@ static int Demux( input_thread_t * p_input )
 
             while( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
             {
-                /* FIXME: handle discontinuity */
-
                 if( !p_stream->p_es ||
                     !p_stream->p_es->p_decoder_fifo )
                 {
                     break;
                 }
 
-                if( oggpacket.granulepos >= 0 )
-                    p_ogg->i_time = oggpacket.granulepos * 1000000
-                        / p_stream->i_rate;
-                else
-                    p_ogg->i_time += (oggpacket.bytes * 1000000
-                        / p_stream->i_bitrate);
+                if( p_stream->b_reinit )
+                {
+                    if( oggpacket.granulepos >= 0 )
+                    {
+                        p_stream->b_reinit = 0;
+                        p_stream->i_pcr = oggpacket.granulepos
+                            * 90000 / p_stream->i_rate;
+
+                        if( !p_ogg->i_pcr ||
+                            (p_stream == p_ogg->p_stream_timeref) )
+                        {
+                            /* Call the pace control to reinitialize
+                             * the system clock */
+                            p_ogg->i_pcr = p_stream->i_pcr;
+                            input_ClockManageRef( p_input,
+                               p_input->stream.p_selected_program,
+                               p_ogg->i_pcr );
+                        }
+                    }
+                    continue;
+                }
 
                 Ogg_DecodePacket( p_input, p_stream, &oggpacket );
+
             }
         }
 #undef p_stream
     }
 
+    /* Call the pace control */
+    if( !b_eos ) input_ClockManageRef( p_input,
+                                       p_input->stream.p_selected_program,
+                                       p_ogg->i_pcr );
+
     /* Did we reach the end of stream ? */
     return( b_eos ? 0 : 1 );
 }