]> git.sesse.net Git - vlc/commitdiff
* modules/demux/ogg.c: reworked a bit. Ogg web radios should work again, vorbis audio...
authorGildas Bazin <gbazin@videolan.org>
Thu, 25 Sep 2003 23:09:41 +0000 (23:09 +0000)
committerGildas Bazin <gbazin@videolan.org>
Thu, 25 Sep 2003 23:09:41 +0000 (23:09 +0000)
* modules/mux/ogg.c: attempt at supporting theora.

modules/demux/ogg.c
modules/mux/ogg.c

index fa6e612340bd1a532ed8f74022c386afd2d0cadc..12eef1ac1fdd0de64c06222aebb756038218b029 100644 (file)
@@ -2,7 +2,7 @@
  * ogg.c : ogg stream input module for vlc
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: ogg.c,v 1.33 2003/09/07 22:48:29 fenrir Exp $
+ * $Id: ogg.c,v 1.34 2003/09/25 23:09:41 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  * 
@@ -66,6 +66,7 @@ typedef struct logical_stream_s
      * granulepos */
     mtime_t          i_pcr;
     mtime_t          i_interpolated_pcr;
+    mtime_t          i_previous_pcr;
 
     /* info from logical streams */
     double f_rate;
@@ -95,7 +96,6 @@ struct demux_sys_t
     /* program clock reference (in units of 90kHz) derived from the pcr of
      * the sub-streams */
     mtime_t i_pcr;
-    mtime_t i_old_pcr;
 
     int     b_seekable;
     int     b_reinit;
@@ -207,6 +207,11 @@ static int Ogg_StreamStart( input_thread_t *p_input,
         int i;
         for( i = 0; i < p_stream->i_packets_backup; i++ )
         {
+            /* Set correct starting date in the last header packet */
+            if( i == p_stream->i_packets_backup -1 )
+                p_stream->p_packets_backup[i].granulepos =
+                    p_stream->i_interpolated_pcr * p_stream->f_rate / 90000;
+
             Ogg_DecodePacket( p_input, p_stream,
                               &p_stream->p_packets_backup[i] );
         }
@@ -293,8 +298,7 @@ static int Ogg_ReadPage( input_thread_t *p_input, demux_sys_t *p_ogg,
 static void Ogg_UpdatePCR( logical_stream_t *p_stream,
                            ogg_packet *p_oggpacket )
 {
-
-    /* Convert the next granulepos into a pcr */
+    /* Convert the granulepos into a pcr */
     if( p_oggpacket->granulepos >= 0 )
     {
         if( p_stream->i_fourcc != VLC_FOURCC( 't','h','e','o' ) )
@@ -317,16 +321,14 @@ static void Ogg_UpdatePCR( logical_stream_t *p_stream,
     }
     else
     {
-        /* FIXME: ffmpeg doesn't like null pts */
-        if( p_stream->i_cat == VIDEO_ES )
-            /* 1 frame per packet */
-            p_stream->i_pcr += (90000 / p_stream->f_rate);
-        else
-            p_stream->i_pcr = -1;
+        p_stream->i_pcr = -1;
 
         /* no granulepos available, try to interpolate the pcr.
          * If we can't then don't touch the old value. */
-        if( p_stream->i_bitrate )
+        if( p_stream->i_cat == VIDEO_ES )
+            /* 1 frame per packet */
+            p_stream->i_interpolated_pcr += (90000 / p_stream->f_rate);
+        else if( p_stream->i_bitrate )
             p_stream->i_interpolated_pcr += ( p_oggpacket->bytes * 90000
                                               / p_stream->i_bitrate / 8 );
     }
@@ -346,9 +348,21 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
 
     if( p_stream->b_force_backup )
     {
-        /* Backup the ogg packet (likely an header packet) */
         ogg_packet *p_packet_backup;
         p_stream->i_packets_backup++;
+        switch( p_stream->i_fourcc )
+        {
+        case VLC_FOURCC( 'v','o','r','b' ):
+        case VLC_FOURCC( 't','h','e','o' ):
+          if( p_stream->i_packets_backup == 3 ) p_stream->b_force_backup = 0;
+          break;
+
+        default:
+          p_stream->b_force_backup = 0;
+          break;
+        }
+
+        /* Backup the ogg packet (likely an header packet) */
         p_stream->p_packets_backup =
             realloc( p_stream->p_packets_backup, p_stream->i_packets_backup *
                      sizeof(ogg_packet) );
@@ -357,23 +371,12 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
             &p_stream->p_packets_backup[p_stream->i_packets_backup - 1];
 
         p_packet_backup->bytes = p_oggpacket->bytes;
+        if( p_stream->b_force_backup ) p_oggpacket->granulepos = -1;
         p_packet_backup->granulepos = p_oggpacket->granulepos;
         p_packet_backup->packet = malloc( p_oggpacket->bytes );
         if( !p_packet_backup->packet ) return;
         memcpy( p_packet_backup->packet, p_oggpacket->packet,
                 p_oggpacket->bytes );
-
-        switch( p_stream->i_fourcc )
-        {
-        case VLC_FOURCC( 'v','o','r','b' ):
-        case VLC_FOURCC( 't','h','e','o' ):
-          if( p_stream->i_packets_backup == 3 ) p_stream->b_force_backup = 0;
-          break;
-
-        default:
-          p_stream->b_force_backup = 0;
-          break;
-        }
     }
 
     vlc_mutex_lock( &p_input->stream.control.control_lock );
@@ -387,6 +390,26 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
     {
         /* This stream isn't currently selected so we don't need to decode it,
          * but we do need to store its pcr as it might be selected later on. */
+
+        if( p_stream->i_pcr >= 0 )
+        {
+            /* This is for streams where the granulepos of the header packets
+             * doesn't match these of the data packets (eg. ogg web radios). */
+            if( p_stream->i_previous_pcr == 0 &&
+                p_stream->i_pcr  > 3 * DEFAULT_PTS_DELAY * 9/100 )
+                p_input->stream.p_selected_program->i_synchro_state =
+                    SYNCHRO_REINIT;
+
+            p_stream->i_previous_pcr = p_stream->i_pcr;
+
+            /* Call the pace control */
+            if( p_input->stream.p_selected_program->i_synchro_state ==
+                SYNCHRO_REINIT )
+            input_ClockManageRef( p_input,
+                                  p_input->stream.p_selected_program,
+                                  p_stream->i_pcr );
+        }
+
         Ogg_UpdatePCR( p_stream, p_oggpacket );
 
         return;
@@ -405,27 +428,67 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
     p_data->p_payload_end = p_data->p_payload_start + p_oggpacket->bytes;
 
     /* Convert the pcr into a pts */
-    if( p_stream->i_fourcc == VLC_FOURCC( 'v','o','r','b' ) ||
-        p_stream->i_fourcc == VLC_FOURCC( 't','h','e','o' ) )
+    if( p_stream->i_fourcc == VLC_FOURCC( 'v','o','r','b' ) )
     {
+        if( p_stream->i_pcr >= 0 )
+        {
+            /* This is for streams where the granulepos of the header packets
+             * doesn't match these of the data packets (eg. ogg web radios). */
+            if( p_stream->i_previous_pcr == 0 &&
+                p_stream->i_pcr  > 3 * DEFAULT_PTS_DELAY * 9/100 )
+                p_input->stream.p_selected_program->i_synchro_state =
+                    SYNCHRO_REINIT;
+
+            p_stream->i_previous_pcr = p_stream->i_pcr;
+
+            /* Call the pace control */
+            if( p_input->stream.p_selected_program->i_synchro_state ==
+                SYNCHRO_REINIT )
+            input_ClockManageRef( p_input,
+                                  p_input->stream.p_selected_program,
+                                  p_stream->i_pcr );
+        }
+
+        /* The granulepos is the end date of the sample */
         p_pes->i_pts = ( p_stream->i_pcr < 0 ) ? 0 :
             input_ClockGetTS( p_input, p_input->stream.p_selected_program,
                               p_stream->i_pcr );
+
+        /* Convert the granulepos into the next pcr */
+        Ogg_UpdatePCR( p_stream, p_oggpacket );
     }
     else
     {
-        /* Of course subtitles had to be different! */
-        p_pes->i_pts = ( p_oggpacket->granulepos < 0 ) ? 0 :
+        /* Convert the granulepos into the current pcr */
+        Ogg_UpdatePCR( p_stream, p_oggpacket );
+
+        if( p_stream->i_pcr >= 0 )
+        {
+            /* This is for streams where the granulepos of the header packets
+             * doesn't match these of the data packets (eg. ogg web radios). */
+            if( p_stream->i_previous_pcr == 0 &&
+                p_stream->i_pcr  > 3 * DEFAULT_PTS_DELAY * 9/100 )
+                p_input->stream.p_selected_program->i_synchro_state =
+                    SYNCHRO_REINIT;
+
+            p_stream->i_previous_pcr = p_stream->i_pcr;
+
+            /* Call the pace control */
+            if( p_input->stream.p_selected_program->i_synchro_state ==
+                SYNCHRO_REINIT )
+            input_ClockManageRef( p_input,
+                                  p_input->stream.p_selected_program,
+                                  p_stream->i_pcr );
+        }
+
+        /* The granulepos is the start date of the sample */
+        p_pes->i_pts = ( p_stream->i_pcr < 0 ) ? 0 :
             input_ClockGetTS( p_input, p_input->stream.p_selected_program,
-                              p_oggpacket->granulepos * 90000 /
-                              p_stream->f_rate );
+                              p_stream->i_pcr );
     }
 
-    /* Convert the next granulepos into a pcr */
-    Ogg_UpdatePCR( p_stream, p_oggpacket );
-
     p_pes->i_nb_data = 1;
-    p_pes->i_dts = p_oggpacket->granulepos;
+    p_pes->i_dts = p_pes->i_pts;
     p_pes->p_first = p_pes->p_last = p_data;
     p_pes->i_pes_size = p_oggpacket->bytes;
 
@@ -439,7 +502,6 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
         i_header_len++;
 
         p_pes->i_pes_size -= i_header_len;
-        p_pes->i_dts = 0;
     }
 
     if( p_stream->i_fourcc == VLC_FOURCC( 't','a','r','k' ) )
@@ -1075,7 +1137,6 @@ 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_pcr  = 0;
     p_ogg->b_seekable = ( ( p_input->stream.b_seekable )
                         &&( p_input->stream.i_method == INPUT_METHOD_FILE ) );
 
@@ -1090,9 +1151,8 @@ static int Activate( vlc_object_t * p_this )
         goto error;
     }
 
-    /* Set the demux function */
+    /* Set exported function */
     p_input->pf_demux = Demux;
-    p_input->pf_demux_control = demux_vaControlDefault;
 
     /* Initialize access plug-in structures. */
     if( p_input->i_mtu == 0 )
@@ -1133,6 +1193,8 @@ static int Activate( vlc_object_t * p_this )
         p_stream->p_es->i_fourcc = p_stream->i_fourcc;
         p_stream->p_es->p_waveformatex      = (void*)p_stream->p_wf;
         p_stream->p_es->p_bitmapinfoheader  = (void*)p_stream->p_bih;
+
+        p_stream->i_pcr  = p_stream->i_previous_pcr = -1;
 #undef p_stream
     }
 
@@ -1201,11 +1263,6 @@ 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:
@@ -1258,7 +1315,7 @@ static void Deactivate( vlc_object_t *p_this )
  *****************************************************************************/
 static int Demux( input_thread_t * p_input )
 {
-    int i, i_stream, b_eos = 0;
+    int i, i_stream, b_pcr = 0, b_eos = 0;
     ogg_page    oggpage;
     ogg_packet  oggpacket;
     demux_sys_t *p_ogg  = (demux_sys_t *)p_input->p_demux_data;
@@ -1318,10 +1375,6 @@ static int Demux( input_thread_t * p_input )
     {
         msg_Warn( p_input, "synchro reinit" );
 
-        /* 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 */
@@ -1358,30 +1411,21 @@ static int Demux( input_thread_t * p_input )
 
                 if( p_stream->b_reinit )
                 {
-                    if( oggpacket.granulepos >= 0 )
+                    /* Convert the granulepos into a pcr */
+                    Ogg_UpdatePCR( p_stream, &oggpacket );
+
+                    if( p_stream->i_pcr >= 0 )
                     {
                         p_stream->b_reinit = 0;
-
-                        /* Convert the next granulepos into a pcr */
-                        Ogg_UpdatePCR( p_stream, &oggpacket );
-
-                        /* Call the pace control to reinitialize
-                         * the system clock */
-                         input_ClockManageRef( p_input,
-                             p_input->stream.p_selected_program,
-                             p_stream->i_pcr );
-
-                         if( (!p_ogg->p_stream_video ||
-                              !p_ogg->p_stream_video->b_reinit) &&
-                             (!p_ogg->p_stream_audio ||
-                              !p_ogg->p_stream_audio->b_reinit) )
-                         {
-                             p_ogg->b_reinit = 0;
-                         }
                     }
-                    continue;
+                    else continue;
+
+                    /* An Ogg/vorbis packet contains an end date granulepos */
+                    if( p_stream->i_fourcc == VLC_FOURCC( 'v','o','r','b' ) )
+                        continue;
                 }
 
+                p_ogg->b_reinit = 0;
                 Ogg_DecodePacket( p_input, p_stream, &oggpacket );
 
             }
@@ -1389,7 +1433,6 @@ static int Demux( input_thread_t * p_input )
     }
 
     i_stream = 0;
-    p_ogg->i_old_pcr = p_ogg->i_pcr;
     p_ogg->i_pcr = p_stream->i_interpolated_pcr;
     for( ; i_stream < p_ogg->i_streams; i_stream++ )
     {
@@ -1399,17 +1442,17 @@ static int Demux( input_thread_t * p_input )
         if( p_stream->i_interpolated_pcr > 0
             && p_stream->i_interpolated_pcr < p_ogg->i_pcr )
             p_ogg->i_pcr = p_stream->i_interpolated_pcr;
+
+        if( p_stream->i_pcr >= 0 ) b_pcr = VLC_TRUE;
     }
-#undef p_stream
 
-    /* This is for streams where the granulepos of the header packets
-     * don't match these of the data packets (eg. ogg web radios). */
-    if( p_ogg->i_old_pcr == 0 && p_ogg->i_pcr > 3 * DEFAULT_PTS_DELAY * 9/100 )
-        p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_REINIT;
+    if( b_pcr )
+    {
+        input_ClockManageRef( p_input, p_input->stream.p_selected_program,
+                              p_ogg->i_pcr );
+    }
 
-    /* Call the pace control */
-    input_ClockManageRef( p_input, p_input->stream.p_selected_program,
-                          p_ogg->i_pcr );
+#undef p_stream
 
     /* Did we reach the end of stream ? */
     return( b_eos ? 0 : 1 );
index fa34f69ea2300426c6b8efe137a21dae655a4819..9d95a5b756a2d33a6c4f8a3622d7914637d89dc1 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************
- * ogg.c
+ * ogg.c: ogg muxer module for vlc
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: ogg.c,v 1.8 2003/07/01 17:14:58 sam Exp $
+ * $Id: ogg.c,v 1.9 2003/09/25 23:09:41 gbazin Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Gildas Bazin <gbazin@netcourrier.com>
@@ -262,11 +262,16 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
                      p_input->p_fmt->i_height );
             break;
 
+        case VLC_FOURCC( 't', 'h', 'e', 'o' ):
+          msg_Dbg( p_mux, "theora stream" );
+          break;
+
         default:
             FREE( p_input->p_sys );
             return( VLC_EGENERIC );
         }
         break;
+
     case AUDIO_ES:
         switch( p_input->p_fmt->i_fourcc )
         {
@@ -300,6 +305,7 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
         case VLC_FOURCC( 'v', 'o', 'r', 'b' ):
           msg_Dbg( p_mux, "vorbis stream" );
           break;
+
         default:
             FREE( p_input->p_sys );
             return( VLC_EGENERIC );
@@ -466,7 +472,8 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
 
         p_stream = (ogg_stream_t*)p_mux->pp_inputs[i]->p_sys;
 
-        if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
+        if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ||
+            p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
         {
             /* Special case, headers are already there in the
              * incoming stream */
@@ -504,7 +511,8 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
 
         p_stream = (ogg_stream_t*)p_mux->pp_inputs[i]->p_sys;
 
-        if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
+        if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ||
+            p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
         {
             /* Special case, headers are already there in the incoming stream.
              * We need to gather them an mark them as headers. */
@@ -644,7 +652,12 @@ static int Mux( sout_mux_t *p_mux )
         }
         else if( p_stream->i_cat == VIDEO_ES )
         {
-            op.granulepos = ( i_dts - p_sys->i_start_dts ) / 1000;
+            if( p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
+            {
+                op.granulepos = op.packetno; /* FIXME */
+            }
+            else
+                op.granulepos = ( i_dts - p_sys->i_start_dts ) / 1000;
         }
 
         ogg_stream_packetin( &p_stream->os, &op );