]> git.sesse.net Git - vlc/blobdiff - modules/demux/ogg.c
* sdp : begin to play rtsp stream (as well as sdp). MPEG4 Audio/Video,
[vlc] / modules / demux / ogg.c
index 3c5feb72226182d5cdd8b918605567c527597c44..fa6e612340bd1a532ed8f74022c386afd2d0cadc 100644 (file)
@@ -2,7 +2,7 @@
  * ogg.c : ogg stream input module for vlc
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: ogg.c,v 1.13 2002/11/26 17:38:33 gbazin Exp $
+ * $Id: ogg.c,v 1.33 2003/09/07 22:48:29 fenrir Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  * 
@@ -70,6 +70,7 @@ typedef struct logical_stream_s
     /* info from logical streams */
     double f_rate;
     int i_bitrate;
+    int i_channels;
     int b_reinit;
 
     /* codec specific stuff */
@@ -94,8 +95,8 @@ 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;
 
-    mtime_t i_length;
     int     b_seekable;
     int     b_reinit;
 };
@@ -144,22 +145,6 @@ typedef struct stream_header
 #define PACKET_LEN_BITS2     0x02
 #define PACKET_IS_SYNCPOINT  0x08
 
-/* Some functions to manipulate memory */
-static uint16_t GetWLE( uint8_t *p_buff )
-{
-    return( (p_buff[0]) + ( p_buff[1] <<8 ) );
-}
-
-static uint32_t GetDWLE( uint8_t *p_buff )
-{
-    return( p_buff[0] + ( p_buff[1] <<8 ) +
-            ( p_buff[2] <<16 ) + ( p_buff[3] <<24 ) );
-}
-
-static uint64_t GetQWLE( uint8_t *p_buff )
-{
-    return( GetDWLE( p_buff ) + ( ((uint64_t)GetDWLE( p_buff + 4 )) << 32 ) );
-}
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -184,7 +169,7 @@ static int  Ogg_FindLogicalStreams( input_thread_t *p_input,
  * Module descriptor
  *****************************************************************************/
 vlc_module_begin();
-    set_description( _("ogg stream demux" ) );
+    set_description( _("ogg stream demuxer" ) );
     set_capability( "demux", 50 );
     set_callbacks( Activate, Deactivate );
     add_shortcut( "ogg" );
@@ -381,6 +366,7 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
         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;
 
@@ -416,9 +402,11 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
         input_DeletePES( p_input->p_method_data, p_pes );
         return;
     }
+    p_data->p_payload_end = p_data->p_payload_start + p_oggpacket->bytes;
 
     /* Convert the pcr into a pts */
-    if( p_stream->i_cat != SPU_ES )
+    if( p_stream->i_fourcc == VLC_FOURCC( 'v','o','r','b' ) ||
+        p_stream->i_fourcc == VLC_FOURCC( 't','h','e','o' ) )
     {
         p_pes->i_pts = ( p_stream->i_pcr < 0 ) ? 0 :
             input_ClockGetTS( p_input, p_input->stream.p_selected_program,
@@ -457,7 +445,7 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
     if( p_stream->i_fourcc == VLC_FOURCC( 't','a','r','k' ) )
     {
         /* FIXME: the biggest hack I've ever done */
-        msg_Warn( p_input, "tark pts: %lli, granule: %i",
+        msg_Warn( p_input, "tark pts: "I64Fd", granule: "I64Fd,
                   p_pes->i_pts, p_pes->i_dts );
         msleep(10000);
     }
@@ -541,10 +529,25 @@ 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, 96 );
+                    oggpack_adv( &opb, 88 );
+                    p_stream->i_channels = oggpack_read( &opb, 8 );
                     p_stream->f_rate = oggpack_read( &opb, 32 );
                     oggpack_adv( &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"), _("Vorbis") );
+                        input_AddInfo( p_cat, _("Sample Rate"), "%f",
+                                       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 Theora header */
                 else if( oggpacket.bytes >= 7 &&
@@ -562,6 +565,11 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                     p_stream->i_cat = VIDEO_ES;
                     p_stream->i_fourcc = VLC_FOURCC( 't','h','e','o' );
 
+                    /* 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 ;) */
                     oggpackB_readinit(&opb, oggpacket.packet, oggpacket.bytes);
                     oggpackB_adv( &opb, 56 );
@@ -570,13 +578,19 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                     oggpackB_read( &opb, 8 ); /* subminor version num */
                     oggpackB_read( &opb, 16 ) /*<< 4*/; /* width */
                     oggpackB_read( &opb, 16 ) /*<< 4*/; /* height */
+                    oggpackB_read( &opb, 24 ); /* frame width */
+                    oggpackB_read( &opb, 24 ); /* frame height */
+                    oggpackB_read( &opb, 8 ); /* x offset */
+                    oggpackB_read( &opb, 8 ); /* y offset */
+
                     i_fps_numerator = oggpackB_read( &opb, 32 );
                     i_fps_denominator = oggpackB_read( &opb, 32 );
                     oggpackB_read( &opb, 24 ); /* aspect_numerator */
                     oggpackB_read( &opb, 24 ); /* aspect_denominator */
                     i_keyframe_frequency_force = 1 << oggpackB_read( &opb, 5 );
+                    oggpackB_read( &opb, 8 ); /* colorspace */
                     p_stream->i_bitrate = oggpackB_read( &opb, 24 );
-                    oggpackB_read(&opb,6); /* quality */
+                    oggpackB_read( &opb, 6 ); /* quality */
 
                     /* granule_shift = i_log( frequency_force -1 ) */
                     p_stream->i_theora_keyframe_granule_shift = 0;
@@ -587,11 +601,23 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                         i_keyframe_frequency_force >>= 1;
                     }
 
-                    p_stream->f_rate = (float)i_fps_numerator /
+                    p_stream->f_rate = ((float)i_fps_numerator) /
                                                 i_fps_denominator;
                     msg_Dbg( p_input,
                              "found theora header, bitrate: %i, rate: %f",
                              p_stream->i_bitrate, p_stream->f_rate );
+                    {
+                        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"), _("Video") );
+                        input_AddInfo( p_cat, _("Codec"), _("Theora") );
+                        input_AddInfo( p_cat, _("Frame Rate"), "%f",
+                                       p_stream->f_rate );
+                        input_AddInfo( p_cat, _("Bit Rate"), "%d",
+                                       p_stream->i_bitrate );
+                    }
 #else /* HAVE_OGGPACKB */
                     msg_Dbg( p_input, "the ogg demuxer has been compiled "
                              "without support for the oggpackB extension."
@@ -620,6 +646,193 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                     msg_Dbg( p_input,
                              "found tarkin header, bitrate: %i, rate: %f",
                              p_stream->i_bitrate, p_stream->f_rate );
+                                        {
+                        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"), _("Video") );
+                        input_AddInfo( p_cat, _("Codec"), _("tarkin") );
+                        input_AddInfo( p_cat, _("Sample Rate"), "%f",
+                                       p_stream->f_rate );
+                        input_AddInfo( p_cat, _("Bit Rate"), "%d",
+                                       p_stream->i_bitrate );
+                    }
+
+                }
+                else if( oggpacket.bytes >= 142 &&
+                         !strncmp( &oggpacket.packet[1],
+                                   "Direct Show Samples embedded in Ogg", 35 ))
+                {
+                    /* Old header type */
+
+                    /* Check for video header (old format) */
+                    if( GetDWLE((oggpacket.packet+96)) == 0x05589f80 &&
+                        oggpacket.bytes >= 184 )
+                    {
+                        p_stream->i_cat = VIDEO_ES;
+
+                        p_stream->p_bih = (BITMAPINFOHEADER *)
+                            malloc( sizeof(BITMAPINFOHEADER) );
+                        if( !p_stream->p_bih )
+                        {
+                            /* Mem allocation error, just ignore the stream */
+                            free( p_stream );
+                            p_ogg->i_streams--;
+                            continue;
+                        }
+                        p_stream->p_bih->biSize = sizeof(BITMAPINFOHEADER);
+                        p_stream->p_bih->biCompression= p_stream->i_fourcc =
+                            VLC_FOURCC( oggpacket.packet[68],
+                                        oggpacket.packet[69],
+                                        oggpacket.packet[70],
+                                        oggpacket.packet[71] );
+                        msg_Dbg( p_input, "found video header of type: %.4s",
+                                 (char *)&p_stream->i_fourcc );
+
+                        p_stream->f_rate = 10000000.0 /
+                            GetQWLE((oggpacket.packet+164));
+                        p_stream->p_bih->biBitCount =
+                            GetWLE((oggpacket.packet+182));
+                        if( !p_stream->p_bih->biBitCount )
+                            p_stream->p_bih->biBitCount=24; // hack, FIXME
+                        p_stream->p_bih->biWidth =
+                            GetDWLE((oggpacket.packet+176));
+                        p_stream->p_bih->biHeight =
+                            GetDWLE((oggpacket.packet+180));
+                        p_stream->p_bih->biPlanes= 1 ;
+                        p_stream->p_bih->biSizeImage =
+                            (p_stream->p_bih->biBitCount >> 3) *
+                            p_stream->p_bih->biWidth *
+                            p_stream->p_bih->biHeight;
+
+                        msg_Dbg( p_input,
+                             "fps: %f, width:%i; height:%i, bitcount:%i",
+                            p_stream->f_rate, p_stream->p_bih->biWidth,
+                            p_stream->p_bih->biHeight,
+                            p_stream->p_bih->biBitCount);
+                        {
+                            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"), _("Video") );
+                            input_AddInfo( p_cat, _("Codec"), "%.4s",
+                                           (char *)&p_stream->i_fourcc );
+                            input_AddInfo( p_cat, _("Frame Rate"), "%f",
+                                           p_stream->f_rate );
+                            input_AddInfo( p_cat, _("Bit Count"), "%d",
+                                           p_stream->p_bih->biBitCount );
+                            input_AddInfo( p_cat, _("Width"), "%d",
+                                           p_stream->p_bih->biWidth );
+                            input_AddInfo( p_cat, _("Height"), "%d",
+                                           p_stream->p_bih->biHeight );
+                        }
+                        p_stream->i_bitrate = 0;
+                    }
+                    /* Check for audio header (old format) */
+                    else if( GetDWLE((oggpacket.packet+96)) == 0x05589F81 )
+                    {
+                        unsigned int i_extra_size;
+
+                        p_stream->i_cat = AUDIO_ES;
+
+                        i_extra_size = GetWLE((oggpacket.packet+140));
+
+                        p_stream->p_wf = (WAVEFORMATEX *)
+                            malloc( sizeof(WAVEFORMATEX) + i_extra_size );
+                        if( !p_stream->p_wf )
+                        {
+                            /* Mem allocation error, just ignore the stream */
+                            free( p_stream );
+                            p_ogg->i_streams--;
+                            continue;
+                        }
+
+                        p_stream->p_wf->wFormatTag =
+                            GetWLE((oggpacket.packet+124));
+                        p_stream->p_wf->nChannels =
+                            GetWLE((oggpacket.packet+126));
+                        p_stream->f_rate = p_stream->p_wf->nSamplesPerSec =
+                            GetDWLE((oggpacket.packet+128));
+                        p_stream->i_bitrate = p_stream->p_wf->nAvgBytesPerSec =
+                            GetDWLE((oggpacket.packet+132));
+                        p_stream->i_bitrate *= 8;
+                        p_stream->p_wf->nBlockAlign =
+                            GetWLE((oggpacket.packet+136));
+                        p_stream->p_wf->wBitsPerSample =
+                            GetWLE((oggpacket.packet+138));
+                        p_stream->p_wf->cbSize = i_extra_size;
+
+                        if( i_extra_size > 0 )
+                            memcpy( p_stream->p_wf+sizeof(WAVEFORMATEX),
+                                    oggpacket.packet+142, i_extra_size );
+
+                        switch( p_stream->p_wf->wFormatTag )
+                        {
+                        case WAVE_FORMAT_PCM:
+                            p_stream->i_fourcc =
+                                VLC_FOURCC( 'a', 'r', 'a', 'w' );
+                            break;
+                        case WAVE_FORMAT_MPEG:
+                        case WAVE_FORMAT_MPEGLAYER3:
+                            p_stream->i_fourcc =
+                                VLC_FOURCC( 'm', 'p', 'g', 'a' );
+                            break;
+                        case WAVE_FORMAT_A52:
+                            p_stream->i_fourcc =
+                                VLC_FOURCC( 'a', '5', '2', ' ' );
+                            break;
+                        case WAVE_FORMAT_WMA1:
+                            p_stream->i_fourcc =
+                                VLC_FOURCC( 'w', 'm', 'a', '1' );
+                            break;
+                        case WAVE_FORMAT_WMA2:
+                            p_stream->i_fourcc =
+                                VLC_FOURCC( 'w', 'm', 'a', '2' );
+                            break;
+                        default:
+                            p_stream->i_fourcc = VLC_FOURCC( 'm', 's',
+                                ( p_stream->p_wf->wFormatTag >> 8 ) & 0xff,
+                                p_stream->p_wf->wFormatTag & 0xff );
+                        }
+
+                        msg_Dbg( p_input, "found audio header of type: %.4s",
+                                 (char *)&p_stream->i_fourcc );
+                        msg_Dbg( p_input, "audio:0x%4.4x channels:%d %dHz "
+                                 "%dbits/sample %dkb/s",
+                                 p_stream->p_wf->wFormatTag,
+                                 p_stream->p_wf->nChannels,
+                                 p_stream->p_wf->nSamplesPerSec,
+                                 p_stream->p_wf->wBitsPerSample,
+                                 p_stream->p_wf->nAvgBytesPerSec * 8 / 1024 );
+                        {
+                            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"), "%.4s", 
+                                           (char *)&p_stream->i_fourcc );
+                            input_AddInfo( p_cat, _("Sample Rate"), "%d",
+                                           p_stream->p_wf->nSamplesPerSec );
+                            input_AddInfo( p_cat, _("Bit Rate"), "%d",
+                                           p_stream->p_wf->nAvgBytesPerSec * 8
+                                              / 1024 );
+                            input_AddInfo( p_cat, _("Channels"), "%d",
+                                           p_stream->p_wf->nChannels );
+                            input_AddInfo( p_cat, _("Bits per Sample"), "%d",
+                                           p_stream->p_wf->wBitsPerSample );
+                        }
+
+                    }
+                    else
+                    {
+                        msg_Dbg( p_input, "stream %d has an old header "
+                            "but is of an unknown type", p_ogg->i_streams-1 );
+                        free( p_stream );
+                        p_ogg->i_streams--;
+                    }
                 }
                 else if( (*oggpacket.packet & PACKET_TYPE_BITS )
                          == PACKET_TYPE_HEADER && 
@@ -654,13 +867,13 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                                  (char *)&p_stream->i_fourcc );
 
                         p_stream->f_rate = 10000000.0 /
-                            GetQWLE((uint8_t *)&st->time_unit);
+                            GetQWLE(&st->time_unit);
                         p_stream->p_bih->biBitCount =
-                            GetWLE((uint8_t *)&st->bits_per_sample);
+                            GetWLE(&st->bits_per_sample);
                         p_stream->p_bih->biWidth =
-                            GetDWLE((uint8_t *)&st->sh.video.width);
+                            GetDWLE(&st->sh.video.width);
                         p_stream->p_bih->biHeight =
-                            GetDWLE((uint8_t *)&st->sh.video.height);
+                            GetDWLE(&st->sh.video.height);
                         p_stream->p_bih->biPlanes= 1 ;
                         p_stream->p_bih->biSizeImage =
                             (p_stream->p_bih->biBitCount >> 3) *
@@ -673,6 +886,23 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                             p_stream->p_bih->biHeight,
                             p_stream->p_bih->biBitCount);
 
+                        {
+                            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"), _("Video") );
+                            input_AddInfo( p_cat, _("Codec"), "%.4s",
+                                           (char *)&p_stream->i_fourcc );
+                            input_AddInfo( p_cat, _("Frame Rate"), "%f",
+                                           p_stream->f_rate );
+                            input_AddInfo( p_cat, _("Bit Count"), "%d",
+                                           p_stream->p_bih->biBitCount );
+                            input_AddInfo( p_cat, _("Width"), "%d",
+                                           p_stream->p_bih->biWidth );
+                            input_AddInfo( p_cat, _("Height"), "%d",
+                                           p_stream->p_bih->biHeight );
+                        }
                         p_stream->i_bitrate = 0;
                     }
                     /* Check for audio header (new format) */
@@ -699,16 +929,16 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                         p_buffer[4] = '\0';
                         p_stream->p_wf->wFormatTag = strtol(p_buffer,NULL,16);
                         p_stream->p_wf->nChannels =
-                            GetWLE((uint8_t *)&st->sh.audio.channels);
+                            GetWLE(&st->sh.audio.channels);
                         p_stream->f_rate = p_stream->p_wf->nSamplesPerSec =
-                            GetQWLE((uint8_t *)&st->samples_per_unit);
+                            GetQWLE(&st->samples_per_unit);
                         p_stream->i_bitrate = p_stream->p_wf->nAvgBytesPerSec =
-                            GetDWLE((uint8_t *)&st->sh.audio.avgbytespersec);
+                            GetDWLE(&st->sh.audio.avgbytespersec);
                         p_stream->i_bitrate *= 8;
                         p_stream->p_wf->nBlockAlign =
-                            GetWLE((uint8_t *)&st->sh.audio.blockalign);
+                            GetWLE(&st->sh.audio.blockalign);
                         p_stream->p_wf->wBitsPerSample =
-                            GetWLE((uint8_t *)&st->bits_per_sample);
+                            GetWLE(&st->bits_per_sample);
                         p_stream->p_wf->cbSize = 0;
 
                         switch( p_stream->p_wf->wFormatTag )
@@ -749,6 +979,24 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                                  p_stream->p_wf->nSamplesPerSec,
                                  p_stream->p_wf->wBitsPerSample,
                                  p_stream->p_wf->nAvgBytesPerSec * 8 / 1024 );
+                        {
+                            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"), "%.4s", 
+                                           (char *)&p_stream->i_fourcc );
+                            input_AddInfo( p_cat, _("Sample Rate"), "%d",
+                                           p_stream->p_wf->nSamplesPerSec );
+                            input_AddInfo( p_cat, _("Bit Rate"), "%d",
+                                           p_stream->p_wf->nAvgBytesPerSec * 8
+                                              / 1024 );
+                            input_AddInfo( p_cat, _("Channels"), "%d",
+                                           p_stream->p_wf->nChannels );
+                            input_AddInfo( p_cat, _("Bits per Sample"), "%d",
+                                           p_stream->p_wf->wBitsPerSample );
+                        }
                     }
                     /* Check for text (subtitles) header */
                     else if( !strncmp(st->streamtype, "text", 4) )
@@ -844,6 +1092,7 @@ static int Activate( vlc_object_t * p_this )
 
     /* Set the demux function */
     p_input->pf_demux = Demux;
+    p_input->pf_demux_control = demux_vaControlDefault;
 
     /* Initialize access plug-in structures. */
     if( p_input->i_mtu == 0 )
@@ -876,14 +1125,14 @@ static int Activate( vlc_object_t * p_this )
         vlc_mutex_lock( &p_input->stream.stream_lock );
         p_stream->p_es = input_AddES( p_input,
                                       p_input->stream.p_selected_program,
-                                      p_ogg->i_streams + 1, 0 );
+                                      i_stream,
+                                      p_stream->i_cat, NULL, 0 );
         p_input->stream.i_mux_rate += (p_stream->i_bitrate / ( 8 * 50 ));
         vlc_mutex_unlock( &p_input->stream.stream_lock );
-        p_stream->p_es->i_stream_id = p_stream->p_es->i_id = i_stream;
+        p_stream->p_es->i_stream_id = i_stream;
         p_stream->p_es->i_fourcc = p_stream->i_fourcc;
-        p_stream->p_es->i_cat = p_stream->i_cat;
-        p_stream->p_es->p_demux_data = p_stream->p_bih ?
-            (void *)p_stream->p_bih : (void *)p_stream->p_wf;
+        p_stream->p_es->p_waveformatex      = (void*)p_stream->p_wf;
+        p_stream->p_es->p_bitmapinfoheader  = (void*)p_stream->p_bih;
 #undef p_stream
     }
 
@@ -1140,17 +1389,23 @@ 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++ )
     {
         if( p_stream->i_cat == SPU_ES )
             continue;
 
-        if( p_stream->i_interpolated_pcr < p_ogg->i_pcr )
+        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;
     }
 #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;
 
     /* Call the pace control */
     input_ClockManageRef( p_input, p_input->stream.p_selected_program,