]> git.sesse.net Git - vlc/blobdiff - modules/demux/ogg.c
+ modules/misc/freetype.c: fixed a couple of typos
[vlc] / modules / demux / ogg.c
index 18baabd3800cff7f8abafee73a6828cfd0fca423..35e72e010e84b8ab5a92d57f1b1597d570040f6e 100644 (file)
@@ -2,15 +2,15 @@
  * ogg.c : ogg stream input module for vlc
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: ogg.c,v 1.38 2003/10/01 17:44:25 gbazin Exp $
+ * $Id: ogg.c,v 1.44 2003/11/18 00:57:04 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -39,7 +39,7 @@
 #define OGG_BLOCK_SIZE 4096
 
 /*****************************************************************************
- * Definitions of structures and functions used by this plugins 
+ * Definitions of structures and functions used by this plugins
  *****************************************************************************/
 typedef struct logical_stream_s
 {
@@ -96,9 +96,10 @@ struct demux_sys_t
      * the sub-streams */
     mtime_t i_pcr;
     int     b_reinit;
+    int     i_prev_sync_state;
 
     /* stream state */
-    int     b_eos;
+    int     i_eos;
 };
 
 /* OggDS headers for the new header format (used in ogm files) */
@@ -107,7 +108,7 @@ typedef struct stream_header_video
     ogg_int32_t width;
     ogg_int32_t height;
 } stream_header_video;
-        
+
 typedef struct stream_header_audio
 {
     ogg_int16_t channels;
@@ -251,7 +252,7 @@ static void Ogg_ElemStreamStop( input_thread_t *p_input,
  ****************************************************************************/
 static int Ogg_Check( input_thread_t *p_input )
 {
-    u8 *p_peek;
+    uint8_t *p_peek;
     int i_size = input_Peek( p_input, &p_peek, 4 );
 
     /* Check for the Ogg capture pattern */
@@ -356,10 +357,57 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
         switch( p_stream->i_fourcc )
         {
         case VLC_FOURCC( 'v','o','r','b' ):
+        case VLC_FOURCC( 's','p','x',' ' ):
         case VLC_FOURCC( 't','h','e','o' ):
           if( p_stream->i_packets_backup == 3 ) p_stream->b_force_backup = 0;
           break;
 
+        case VLC_FOURCC( 'f','l','a','c' ):
+          if( p_stream->i_packets_backup == 2 )
+          {
+#ifdef HAVE_OGGPACKB
+              oggpack_buffer opb;
+              char title[sizeof("Stream") + 10];
+              input_info_category_t *p_cat;
+
+              sprintf( title, "Stream %d", p_stream->i_serial_no );
+              p_cat = input_InfoCategory( p_input, title );
+              input_AddInfo( p_cat, _("Type"), _("Audio") );
+              input_AddInfo( p_cat, _("Codec"), _("Flac") );
+
+              /* Parse the STREAMINFO metadata */
+              oggpackB_readinit(&opb, p_oggpacket->packet, p_oggpacket->bytes);
+              oggpackB_adv( &opb, 1 );
+              if( oggpackB_read( &opb, 7 ) == 0 )
+              {
+                  if( oggpackB_read( &opb, 24 ) >= 34 /*size STREAMINFO*/ )
+                  {
+                      oggpackB_adv( &opb, 80 );
+                      p_stream->f_rate = oggpackB_read( &opb, 20 );
+                      p_stream->i_channels = oggpackB_read( &opb, 3 ) + 1;
+
+                      input_AddInfo( p_cat, _("Sample Rate"), "%d",
+                                     (int)p_stream->f_rate );
+                      input_AddInfo( p_cat, _("Channels"), "%d",
+                                     p_stream->i_channels );
+                      msg_Dbg( p_input, "Flac header, channels: %i, rate: %i",
+                               p_stream->i_channels, (int)p_stream->f_rate );
+                  }
+                  else
+                  {
+                      msg_Dbg( p_input, "FLAC STREAMINFO metadata too short" );
+                  }
+              }
+              else
+              {
+                  /* This ain't a STREAMINFO metadata */
+                  msg_Dbg( p_input, "Invalid FLAC STREAMINFO metadata" );
+              }
+#endif
+              p_stream->b_force_backup = 0;
+          }
+          break;
+
         default:
           p_stream->b_force_backup = 0;
           break;
@@ -398,7 +446,9 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
     vlc_mutex_unlock( &p_input->stream.control.control_lock );
 
     /* Convert the pcr into a pts */
-    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( 's','p','x',' ' ) ||
+        p_stream->i_fourcc == VLC_FOURCC( 'f','l','a','c' ) )
     {
         if( p_stream->i_pcr >= 0 )
         {
@@ -484,6 +534,8 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
     if( p_stream->i_cat == SPU_ES ) p_pes->i_dts = 0;
 
     if( p_stream->i_fourcc != VLC_FOURCC( 'v','o','r','b' ) &&
+        p_stream->i_fourcc != VLC_FOURCC( 's','p','x',' ' ) &&
+        p_stream->i_fourcc != VLC_FOURCC( 'f','l','a','c' ) &&
         p_stream->i_fourcc != VLC_FOURCC( 't','a','r','k' ) &&
         p_stream->i_fourcc != VLC_FOURCC( 't','h','e','o' ) )
     {
@@ -594,14 +646,72 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                         p_cat = input_InfoCategory( p_input, title );
                         input_AddInfo( p_cat, _("Type"), _("Audio") );
                         input_AddInfo( p_cat, _("Codec"), _("Vorbis") );
-                        input_AddInfo( p_cat, _("Sample Rate"), "%f",
-                                       p_stream->f_rate );
+                        input_AddInfo( p_cat, _("Sample Rate"), "%d",
+                                       (int)p_stream->f_rate );
                         input_AddInfo( p_cat, _("Channels"), "%d",
                                        p_stream->i_channels );
                         input_AddInfo( p_cat, _("Bit Rate"), "%d",
                                        p_stream->i_bitrate );
                     }
                 }
+                /* Check for Speex header */
+                else if( oggpacket.bytes >= 7 &&
+                    ! strncmp( &oggpacket.packet[0], "Speex", 5 ) )
+                {
+                    oggpack_buffer opb;
+
+                    p_stream->i_cat = AUDIO_ES;
+                    p_stream->i_fourcc = VLC_FOURCC( 's','p','x',' ' );
+
+                    /* Signal that we want to keep a backup of the vorbis
+                     * stream headers. They will be used when switching between
+                     * audio streams. */
+                    p_stream->b_force_backup = 1;
+
+                    /* Cheat and get additionnal info ;) */
+                    oggpack_readinit( &opb, oggpacket.packet, oggpacket.bytes);
+                    oggpack_adv( &opb, 224 );
+                    oggpack_adv( &opb, 32 ); /* speex_version_id */
+                    oggpack_adv( &opb, 32 ); /* header_size */
+                    p_stream->f_rate = oggpack_read( &opb, 32 );
+                    oggpack_adv( &opb, 32 ); /* mode */
+                    oggpack_adv( &opb, 32 ); /* mode_bitstream_version */
+                    p_stream->i_channels = oggpack_read( &opb, 32 );
+                    p_stream->i_bitrate = oggpack_read( &opb, 32 );
+                    {
+                        char title[sizeof("Stream") + 10];
+                        input_info_category_t *p_cat;
+                        sprintf( title, "Stream %d", p_ogg->i_streams );
+                        p_cat = input_InfoCategory( p_input, title );
+                        input_AddInfo( p_cat, _("Type"), _("Audio") );
+                        input_AddInfo( p_cat, _("Codec"), _("Speex") );
+                        input_AddInfo( p_cat, _("Sample Rate"), "%d",
+                                       (int)p_stream->f_rate );
+                        input_AddInfo( p_cat, _("Channels"), "%d",
+                                       p_stream->i_channels );
+                        input_AddInfo( p_cat, _("Bit Rate"), "%d",
+                                       p_stream->i_bitrate );
+                        msg_Dbg( p_input, "found speex header, channels: %i, "
+                                 "rate: %i,  bitrate: %i",
+                                 p_stream->i_channels,
+                                 (int)p_stream->f_rate, p_stream->i_bitrate );
+                    }
+                }
+                /* Check for Flac header */
+                else if( oggpacket.bytes >= 4 &&
+                    ! strncmp( &oggpacket.packet[0], "fLaC", 4 ) )
+                {
+                    msg_Dbg( p_input, "found Flac header" );
+
+                    /* Grrrr!!!! Did they really have to put all the
+                     * important info in the second header packet!!!
+                     * (STREAMINFO metadata is in the following packet) */
+                    p_stream->b_force_backup = 1;
+
+                    p_stream->i_cat = AUDIO_ES;
+                    p_stream->i_fourcc = VLC_FOURCC( 'f','l','a','c' );
+                    p_stream->i_bitrate = 0;
+                }
                 /* Check for Theora header */
                 else if( oggpacket.bytes >= 7 &&
                          ! strncmp( &oggpacket.packet[1], "theora", 6 ) )
@@ -666,7 +776,7 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                         p_cat = input_InfoCategory( p_input, title );
                         input_AddInfo( p_cat, _("Type"), _("Video") );
                         input_AddInfo( p_cat, _("Codec"), _("Theora") );
-                        input_AddInfo( p_cat, _("Frame Rate"), "%f",
+                        input_AddInfo( p_cat, _("Frame Rate"), "%.2f",
                                        p_stream->f_rate );
                         input_AddInfo( p_cat, _("Bit Rate"), "%d",
                                        p_stream->i_bitrate );
@@ -677,7 +787,6 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                              "The theora stream won't be decoded." );
                     free( p_stream );
                     p_ogg->i_streams--;
-                    continue;
 #endif /* HAVE_OGGPACKB */
                 }
                 /* Check for Tarkin header */
@@ -706,8 +815,8 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                         p_cat = input_InfoCategory( p_input, title );
                         input_AddInfo( p_cat, _("Type"), _("Video") );
                         input_AddInfo( p_cat, _("Codec"), _("tarkin") );
-                        input_AddInfo( p_cat, _("Sample Rate"), "%f",
-                                       p_stream->f_rate );
+                        input_AddInfo( p_cat, _("Sample Rate"), "%d",
+                                       (int)p_stream->f_rate );
                         input_AddInfo( p_cat, _("Bit Rate"), "%d",
                                        p_stream->i_bitrate );
                     }
@@ -732,7 +841,7 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                             /* Mem allocation error, just ignore the stream */
                             free( p_stream );
                             p_ogg->i_streams--;
-                            continue;
+                            break;
                         }
                         p_stream->p_bih->biSize = sizeof(BITMAPINFOHEADER);
                         p_stream->p_bih->biCompression= p_stream->i_fourcc =
@@ -772,7 +881,7 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                             input_AddInfo( p_cat, _("Type"), _("Video") );
                             input_AddInfo( p_cat, _("Codec"), "%.4s",
                                            (char *)&p_stream->i_fourcc );
-                            input_AddInfo( p_cat, _("Frame Rate"), "%f",
+                            input_AddInfo( p_cat, _("Frame Rate"), "%.2f",
                                            p_stream->f_rate );
                             input_AddInfo( p_cat, _("Bit Count"), "%d",
                                            p_stream->p_bih->biBitCount );
@@ -799,7 +908,7 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                             /* Mem allocation error, just ignore the stream */
                             free( p_stream );
                             p_ogg->i_streams--;
-                            continue;
+                            break;
                         }
 
                         p_stream->p_wf->wFormatTag =
@@ -865,7 +974,7 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                             sprintf( title, "Stream %d", p_ogg->i_streams );
                             p_cat = input_InfoCategory( p_input, title );
                             input_AddInfo( p_cat, _("Type"), _("Audio") );
-                            input_AddInfo( p_cat, _("Codec"), "%.4s", 
+                            input_AddInfo( p_cat, _("Codec"), "%.4s",
                                            (char *)&p_stream->i_fourcc );
                             input_AddInfo( p_cat, _("Sample Rate"), "%d",
                                            p_stream->p_wf->nSamplesPerSec );
@@ -888,7 +997,7 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                     }
                 }
                 else if( (*oggpacket.packet & PACKET_TYPE_BITS )
-                         == PACKET_TYPE_HEADER && 
+                         == PACKET_TYPE_HEADER &&
                          oggpacket.bytes >= (int)sizeof(stream_header)+1 )
                 {
                     stream_header *st = (stream_header *)(oggpacket.packet+1);
@@ -908,7 +1017,7 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                             /* Mem allocation error, just ignore the stream */
                             free( p_stream );
                             p_ogg->i_streams--;
-                            continue;
+                            break;
                         }
                         p_stream->p_bih->biSize = sizeof(BITMAPINFOHEADER);
                         p_stream->p_bih->biCompression=
@@ -947,7 +1056,7 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                             input_AddInfo( p_cat, _("Type"), _("Video") );
                             input_AddInfo( p_cat, _("Codec"), "%.4s",
                                            (char *)&p_stream->i_fourcc );
-                            input_AddInfo( p_cat, _("Frame Rate"), "%f",
+                            input_AddInfo( p_cat, _("Frame Rate"), "%.2f",
                                            p_stream->f_rate );
                             input_AddInfo( p_cat, _("Bit Count"), "%d",
                                            p_stream->p_bih->biBitCount );
@@ -975,7 +1084,7 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                             /* Mem allocation error, just ignore the stream */
                             free( p_stream );
                             p_ogg->i_streams--;
-                            continue;
+                            break;
                         }
 
                         memcpy( p_buffer, st->subtype, 4 );
@@ -1038,7 +1147,7 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                             sprintf( title, "Stream %d", p_ogg->i_streams );
                             p_cat = input_InfoCategory( p_input, title );
                             input_AddInfo( p_cat, _("Type"), _("Audio") );
-                            input_AddInfo( p_cat, _("Codec"), "%.4s", 
+                            input_AddInfo( p_cat, _("Codec"), "%.4s",
                                            (char *)&p_stream->i_fourcc );
                             input_AddInfo( p_cat, _("Sample Rate"), "%d",
                                            p_stream->p_wf->nSamplesPerSec );
@@ -1164,7 +1273,9 @@ static int Activate( vlc_object_t * p_this )
     vlc_mutex_unlock( &p_input->stream.stream_lock );
 
     /* Begnning of stream, tell the demux to look for elementary streams. */
-    p_ogg->b_eos = VLC_TRUE;
+    p_ogg->i_eos = 0;
+
+    p_ogg->i_prev_sync_state = SYNCHRO_REINIT;
 
     return 0;
 
@@ -1341,7 +1452,7 @@ static void Ogg_EndOfStream( input_thread_t *p_input, demux_sys_t *p_ogg )
 static void Deactivate( vlc_object_t *p_this )
 {
     input_thread_t *p_input = (input_thread_t *)p_this;
-    demux_sys_t *p_ogg = (demux_sys_t *)p_input->p_demux_data  ; 
+    demux_sys_t *p_ogg = (demux_sys_t *)p_input->p_demux_data  ;
 
     if( p_ogg )
     {
@@ -1366,10 +1477,16 @@ static int Demux( input_thread_t * p_input )
     ogg_packet  oggpacket;
     int         i_stream;
 
-    if( p_ogg->b_eos )
+    if( p_ogg->i_eos == p_ogg->i_streams )
     {
+        if( p_ogg->i_eos )
+        {
+            msg_Dbg( p_input, "end of a group of logical streams" );
+            Ogg_EndOfStream( p_input, p_ogg );
+        }
+
         if( Ogg_BeginningOfStream( p_input, p_ogg ) != VLC_SUCCESS ) return 0;
-        p_ogg->b_eos = VLC_FALSE;
+        p_ogg->i_eos = 0;
 
         msg_Dbg( p_input, "beginning of a group of logical streams" );
 
@@ -1440,8 +1557,12 @@ static int Demux( input_thread_t * p_input )
             p_stream->i_pcr = -1;
             p_stream->i_interpolated_pcr = -1;
         }
+        if( p_ogg->i_prev_sync_state != SYNCHRO_REINIT )
+            ogg_sync_reset( &p_ogg->oy );
     }
 
+    p_ogg->i_prev_sync_state =
+        p_input->stream.p_selected_program->i_synchro_state;
 
     /*
      * Demux an ogg page from the stream
@@ -1452,14 +1573,8 @@ static int Demux( input_thread_t * p_input )
     }
 
     /* Test for End of Stream */
-    if( ogg_page_eos( &oggpage ) )
-    {
-        msg_Dbg( p_input, "end of a group of logical streams" );
+    if( ogg_page_eos( &oggpage ) ) p_ogg->i_eos++;
 
-        Ogg_EndOfStream( p_input, p_ogg );
-        p_ogg->b_eos = VLC_TRUE;
-        return 1;
-    }
 
     for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
     {
@@ -1490,12 +1605,19 @@ static int Demux( input_thread_t * p_input )
                 }
 
                 /* An Ogg/vorbis packet contains an end date granulepos */
-                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( 's','p','x',' ' ) ||
+                    p_stream->i_fourcc == VLC_FOURCC( 'f','l','a','c' ) )
                 {
                     if( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
                     {
                         Ogg_DecodePacket( p_input, p_stream, &oggpacket );
                     }
+                    else
+                    {
+                        input_ClockManageRef( p_input,
+                            p_input->stream.p_selected_program, p_ogg->i_pcr );
+                    }
                     continue;
                 }
             }