]> git.sesse.net Git - vlc/commitdiff
* ALL: I did add these files, but forgot to commit them ( ouarf ouarf :)
authorGildas Bazin <gbazin@videolan.org>
Thu, 24 Oct 2002 09:30:48 +0000 (09:30 +0000)
committerGildas Bazin <gbazin@videolan.org>
Thu, 24 Oct 2002 09:30:48 +0000 (09:30 +0000)
modules/codec/vorbis.c [new file with mode: 0644]
modules/demux/ogg.c [new file with mode: 0644]

diff --git a/modules/codec/vorbis.c b/modules/codec/vorbis.c
new file mode 100644 (file)
index 0000000..e1fe7f4
--- /dev/null
@@ -0,0 +1,354 @@
+/*****************************************************************************
+ * vorbis.c: vorbis decoder module making use of libvorbis.
+ *****************************************************************************
+ * Copyright (C) 1999-2001 VideoLAN
+ * $Id: vorbis.c,v 1.1 2002/10/24 09:30:47 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>                                    /* memcpy(), memset() */
+
+#include <vlc/vlc.h>
+#include <vlc/aout.h>
+#include <vlc/decoder.h>
+#include <input_ext-dec.h>
+
+#include <vlc/input.h>
+
+#include <ogg/ogg.h>
+#include <vorbis/codec.h>
+
+/*****************************************************************************
+ * dec_thread_t : vorbis decoder thread descriptor
+ *****************************************************************************/
+typedef struct dec_thread_t
+{
+    /*
+     * Thread properties
+     */
+    vlc_thread_t        thread_id;                /* id for thread functions */
+
+    /*
+     * Vorbis properties
+     */
+    vorbis_info      vi; /* struct that stores all the static vorbis bitstream
+                            settings */
+    vorbis_comment   vc; /* struct that stores all the bitstream user
+                          * comments */
+    vorbis_dsp_state vd; /* central working state for the packet->PCM
+                          * decoder */
+    vorbis_block     vb; /* local working space for packet->PCM decode */
+
+    /*
+     * Input properties
+     */
+    decoder_fifo_t *    p_fifo;                /* stores the PES stream data */
+
+    /*
+     * Output properties
+     */
+    aout_instance_t        *p_aout;
+    aout_input_t           *p_aout_input;
+    audio_sample_format_t   output_format;
+    audio_date_t            end_date;
+
+} dec_thread_t;
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int  OpenDecoder  ( vlc_object_t * );
+static int  RunDecoder   ( decoder_fifo_t * );
+static void CloseDecoder ( dec_thread_t * );
+
+static void DecodePacket ( dec_thread_t * );
+static int  GetOggPacket ( dec_thread_t *, ogg_packet *, mtime_t *, int );
+
+static void Interleave   ( float *, const float **, int, int );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("Vorbis decoder module") );
+    set_capability( "decoder", 100 );
+    set_callbacks( OpenDecoder, NULL );
+vlc_module_end();
+
+/*****************************************************************************
+ * OpenDecoder: probe the decoder and return score
+ *****************************************************************************/
+static int OpenDecoder( vlc_object_t *p_this )
+{
+    decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
+
+    if( p_fifo->i_fourcc != VLC_FOURCC('v','o','r','b') )
+    {
+        return VLC_EGENERIC;
+    }
+
+    p_fifo->pf_run = RunDecoder;
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * RunDecoder: the vorbis decoder
+ *****************************************************************************/
+static int RunDecoder( decoder_fifo_t * p_fifo )
+{
+    dec_thread_t *p_dec;
+    ogg_packet oggpacket;
+    mtime_t i_pts;
+
+    /* Allocate the memory needed to store the thread's structure */
+    if( (p_dec = (dec_thread_t *)malloc (sizeof(dec_thread_t)) )
+            == NULL)
+    {
+        msg_Err( p_fifo, "out of memory" );
+        goto error;
+    }
+
+    /* Initialize the thread properties */
+    p_dec->p_fifo = p_fifo;
+
+    /* Take care of the initial Vorbis header */
+    vorbis_info_init( &p_dec->vi );
+    vorbis_comment_init( &p_dec->vc );
+
+    if( GetOggPacket( p_dec, &oggpacket, &i_pts, 0 ) != VLC_SUCCESS )
+        goto error;
+
+    oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
+    if( vorbis_synthesis_headerin( &p_dec->vi, &p_dec->vc, &oggpacket ) < 0 )
+    {
+        msg_Err( p_dec->p_fifo, "This bitstream does not contain Vorbis "
+                 "audio data");
+        goto error;
+    }
+
+    /* The next two packets in order are the comment and codebook headers.
+       We need to watch out that these packets are not missing as a
+       missing or corrupted header is fatal. */
+    if( GetOggPacket( p_dec, &oggpacket, &i_pts, 1 ) != VLC_SUCCESS )
+        goto error;
+
+    if( vorbis_synthesis_headerin( &p_dec->vi, &p_dec->vc, &oggpacket ) < 0 )
+    {
+        msg_Err( p_dec->p_fifo, "2nd Vorbis header is corrupted" );
+        goto error;
+    }
+
+    if( GetOggPacket( p_dec, &oggpacket, &i_pts, 1 ) != VLC_SUCCESS )
+        goto error;
+
+    if( vorbis_synthesis_headerin( &p_dec->vi, &p_dec->vc, &oggpacket ) < 0 )
+    {
+        msg_Err( p_dec->p_fifo, "3rd Vorbis header is corrupted" );
+        goto error;
+    }
+
+    /* Initialize the Vorbis packet->PCM decoder */
+    vorbis_synthesis_init( &p_dec->vd, &p_dec->vi );
+    vorbis_block_init( &p_dec->vd, &p_dec->vb );
+
+    p_dec->output_format.i_format = VLC_FOURCC('f','l','3','2');
+    p_dec->output_format.i_channels = p_dec->vi.channels;
+    p_dec->output_format.i_rate = p_dec->vi.rate;
+
+    aout_DateInit( &p_dec->end_date, p_dec->vi.rate );
+    p_dec->p_aout = NULL;
+    p_dec->p_aout_input = aout_DecNew( p_dec->p_fifo,
+                                       &p_dec->p_aout,
+                                       &p_dec->output_format );
+
+    if( p_dec->p_aout_input == NULL )
+    {
+        msg_Err( p_dec->p_fifo, "failed to create aout 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) )
+    {
+        DecodePacket( p_dec );
+    }
+
+    /* If b_error is set, the vorbis decoder thread enters the error loop */
+    if( p_dec->p_fifo->b_error )
+    {
+        DecoderError( p_dec->p_fifo );
+    }
+
+    /* End of the vorbis decoder thread */
+    CloseDecoder( p_dec );
+
+    return 0;
+
+ error:
+    if( p_dec )
+    {
+        if( p_dec->p_fifo )
+            p_dec->p_fifo->b_error = 1;
+        free( p_dec );
+    }
+
+    DecoderError( p_fifo );
+    return -1;
+
+}
+
+/*****************************************************************************
+ * DecodePacket: decodes a Vorbis packet.
+ *****************************************************************************/
+static void DecodePacket( dec_thread_t *p_dec )
+{
+    aout_buffer_t *p_aout_buffer;
+    ogg_packet    oggpacket;
+    float         **pp_pcm;
+    int           i_samples;
+    mtime_t       i_pts;
+
+    if( GetOggPacket( p_dec, &oggpacket, &i_pts, 1 ) != VLC_SUCCESS )
+    {
+        /* This should mean an eos */
+        return;
+    }
+
+    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
+     * the size of each channel. Convert the float values
+     * (-1.<=range<=1.) to whatever PCM format and write it out */
+
+    while( ( i_samples = vorbis_synthesis_pcmout( &p_dec->vd, &pp_pcm ) ) > 0 )
+    {
+
+        p_aout_buffer = aout_DecNewBuffer( p_dec->p_aout, p_dec->p_aout_input,
+                                           i_samples );
+        if( !p_aout_buffer )
+        {
+            msg_Err( p_dec->p_fifo, "cannot get aout buffer" );
+            p_dec->p_fifo->b_error = 1;
+            return;
+        }
+
+        /* Interleave the samples */
+        Interleave( (float *)p_aout_buffer->p_buffer, (const float **)pp_pcm,
+                    p_dec->vi.channels, i_samples );
+
+        /* Tell libvorbis how many samples we actually consumed */
+        vorbis_synthesis_read( &p_dec->vd, i_samples );
+
+        /* Date management */
+        p_aout_buffer->start_date = aout_DateGet( &p_dec->end_date );
+        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 );
+    }
+
+}
+
+/*****************************************************************************
+ * GetOggPacket: get the following vorbis packet from the stream and send back
+ *               the result in an ogg packet (for easy decoding by libvorbis).
+ *****************************************************************************
+ * Returns VLC_EGENERIC in case of eof.
+ *****************************************************************************/
+static int GetOggPacket( dec_thread_t *p_dec, ogg_packet *p_oggpacket,
+                         mtime_t *p_pts, int b_next )
+{
+    pes_packet_t *p_pes;
+
+    if( b_next ) NextPES( p_dec->p_fifo );
+    p_pes = GetPES( p_dec->p_fifo );
+
+    p_oggpacket->packet = p_pes->p_first->p_payload_start;
+    p_oggpacket->bytes = p_pes->i_pes_size;
+    p_oggpacket->granulepos = p_pes->i_dts;
+    p_oggpacket->b_o_s = 0;
+    p_oggpacket->e_o_s = 0;
+    p_oggpacket->packetno = 0;
+
+    *p_pts = p_pes->i_pts;
+
+    return p_pes ? VLC_SUCCESS : VLC_EGENERIC;
+}
+
+/*****************************************************************************
+ * Interleave: helper function to interleave channels
+ *****************************************************************************/
+static void Interleave( float *p_out, const float **pp_in, int i_channels,
+                        int i_samples )
+{
+    int i, j;
+
+    for ( j = 0; j < i_samples; j++ )
+    {
+        for ( i = 0; i < i_channels; i++ )
+        {
+            p_out[j * i_channels + i] = pp_in[i][j];
+        }
+    }
+}
+
+/*****************************************************************************
+ * CloseDecoder: vorbis decoder destruction
+ *****************************************************************************/
+static void CloseDecoder( dec_thread_t * p_dec )
+{
+    if( p_dec->p_aout_input != NULL )
+    {
+        aout_DecDelete( p_dec->p_aout, p_dec->p_aout_input );
+    }
+
+    if( p_dec )
+    {
+        vorbis_block_clear( &p_dec->vb );
+        vorbis_dsp_clear( &p_dec->vd );
+        vorbis_comment_clear( &p_dec->vc );
+        vorbis_info_clear( &p_dec->vi );  /* must be called last */
+        free( p_dec );
+    }
+}
diff --git a/modules/demux/ogg.c b/modules/demux/ogg.c
new file mode 100644 (file)
index 0000000..9d38ddc
--- /dev/null
@@ -0,0 +1,650 @@
+/*****************************************************************************
+ * ogg.c : ogg stream input module for vlc
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: ogg.c,v 1.1 2002/10/24 09:30:48 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+
+#include <sys/types.h>
+
+#include <ogg/ogg.h>
+
+#define OGG_BLOCK_SIZE 4096
+#define PAGES_READ_ONCE 1
+
+/*****************************************************************************
+ * Definitions of structures and functions used by this plugins 
+ *****************************************************************************/
+typedef struct logical_stream_s
+{
+    ogg_stream_state os;                        /* logical stream of packets */
+
+    int              i_serial_no;
+    int              i_pages_read;
+    int              i_cat;                            /* AUDIO_ES, VIDEO_ES */
+    int              i_activated;
+    vlc_fourcc_t     i_fourcc;
+    vlc_fourcc_t     i_codec;
+
+    es_descriptor_t  *p_es;   
+    int              b_selected;                           /* newly selected */
+
+    /* info for vorbis logical streams */
+    int i_rate;
+    int i_channels;
+    int i_bitrate;
+
+} logical_stream_t;
+
+struct demux_sys_t
+{
+    ogg_sync_state oy;        /* sync and verify incoming physical bitstream */
+
+    int i_streams;                           /* number of logical bitstreams */
+    logical_stream_t **pp_stream;  /* pointer to an array of logical streams */
+
+    /* current audio and video es */
+    logical_stream_t *p_stream_video;
+    logical_stream_t *p_stream_audio;
+
+    mtime_t i_time;
+    mtime_t i_length;
+    mtime_t i_pcr; 
+    int     b_seekable;
+};
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int  Activate  ( vlc_object_t * );
+static void Deactivate( vlc_object_t * );
+static int  Demux     ( input_thread_t * );
+
+/* Stream managment */
+static int  Ogg_StreamStart  ( input_thread_t *, demux_sys_t *, int );
+static int  Ogg_StreamSeek   ( input_thread_t *, demux_sys_t *, int, mtime_t );
+static void Ogg_StreamStop   ( input_thread_t *, demux_sys_t *, int );
+
+/* Bitstream manipulation */
+static int  Ogg_Check        ( input_thread_t *p_input );
+static int  Ogg_ReadPage     ( input_thread_t *, demux_sys_t *, ogg_page * );
+static void Ogg_DecodePacket ( input_thread_t *p_input,
+                               logical_stream_t *p_stream,
+                               ogg_packet *p_oggpacket );
+static int  Ogg_FindLogicalStreams( input_thread_t *p_input,
+                                    demux_sys_t *p_ogg );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("ogg stream demux" ) );
+    set_capability( "demux", 50 );
+    set_callbacks( Activate, Deactivate );
+    add_shortcut( "ogg" );
+vlc_module_end();
+
+/*****************************************************************************
+ * Stream managment
+ *****************************************************************************/
+static int Ogg_StreamStart( input_thread_t *p_input,
+                            demux_sys_t *p_ogg, int i_stream )
+{
+#define p_stream p_ogg->pp_stream[i_stream]
+    if( !p_stream->p_es )
+    {
+        msg_Warn( p_input, "stream[%d] unselectable", i_stream );
+        return( 0 );
+    }
+    if( p_stream->i_activated )
+    {
+        msg_Warn( p_input, "stream[%d] already selected", i_stream );
+        return( 1 );
+    }
+
+    if( !p_stream->p_es->p_decoder_fifo )
+    {
+        vlc_mutex_lock( &p_input->stream.stream_lock );
+        input_SelectES( p_input, p_stream->p_es );
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+    }
+    p_stream->i_activated = p_stream->p_es->p_decoder_fifo ? 1 : 0;
+
+    //Ogg_StreamSeek( p_input, p_ogg, i_stream, p_ogg->i_time );
+
+    return( p_stream->i_activated );
+#undef  p_stream
+}
+
+static void Ogg_StreamStop( input_thread_t *p_input,
+                            demux_sys_t *p_ogg, int i_stream )
+{
+#define p_stream    p_ogg->pp_stream[i_stream]
+
+    if( !p_stream->i_activated )
+    {
+        msg_Warn( p_input, "stream[%d] already unselected", i_stream );
+        return;
+    }
+
+    if( p_stream->p_es->p_decoder_fifo )
+    {
+        vlc_mutex_lock( &p_input->stream.stream_lock );
+        input_UnselectES( p_input, p_stream->p_es );
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+    }
+
+    p_stream->i_activated = 0;
+
+#undef  p_stream
+}
+
+static int Ogg_StreamSeek( input_thread_t *p_input, demux_sys_t  *p_ogg,
+                           int i_stream, mtime_t i_date )
+{
+#define p_stream    p_ogg->pp_stream[i_stream]
+
+    /* FIXME: todo */
+
+    return 1;
+#undef p_stream
+}
+
+/****************************************************************************
+ * Ogg_Check: Check we are dealing with an ogg stream.
+ ****************************************************************************/
+static int Ogg_Check( input_thread_t *p_input )
+{
+    u8 *p_peek;
+    int i_size = input_Peek( p_input, &p_peek, 4 );
+
+    /* Check for the Ogg capture pattern */
+    if( !(i_size>3) || !(p_peek[0] == 'O') || !(p_peek[1] == 'g') ||
+        !(p_peek[2] == 'g') || !(p_peek[3] == 'S') )
+        return VLC_EGENERIC;
+
+    /* FIXME: Capture pattern might not be enough so we can also check for the
+     * the first complete page */
+
+    return VLC_SUCCESS;
+}
+
+/****************************************************************************
+ * Ogg_ReadPage: Read a full Ogg page from the physical bitstream.
+ ****************************************************************************
+ * Returns VLC_SUCCESS if a page has been read. An error might happen if we
+ * are at the end of stream.
+ ****************************************************************************/
+static int Ogg_ReadPage( input_thread_t *p_input, demux_sys_t *p_ogg,
+                         ogg_page *p_oggpage )
+{
+    int i_read = 0;
+    data_packet_t *p_data;
+    byte_t *p_buffer;
+
+    while( ogg_sync_pageout( &p_ogg->oy, p_oggpage ) != 1 )
+    {
+        i_read = input_SplitBuffer( p_input, &p_data, OGG_BLOCK_SIZE );
+        if( i_read <= 0 )
+            return VLC_EGENERIC;
+
+        p_buffer = ogg_sync_buffer( &p_ogg->oy, i_read );
+        p_input->p_vlc->pf_memcpy( p_buffer, p_data->p_payload_start, i_read );
+        ogg_sync_wrote( &p_ogg->oy, i_read );
+        input_DeletePacket( p_input->p_method_data, p_data );
+    }
+
+    return VLC_SUCCESS;
+}
+
+/****************************************************************************
+ * Ogg_DecodePacket: Decode an Ogg packet.
+ ****************************************************************************/
+static void Ogg_DecodePacket( input_thread_t *p_input,
+                              logical_stream_t *p_stream,
+                              ogg_packet *p_oggpacket )
+{
+    pes_packet_t  *p_pes;
+    data_packet_t *p_data;
+
+    if( !( p_pes = input_NewPES( p_input->p_method_data ) ) )
+    {
+        return;
+    }
+    if( !( p_data = input_NewPacket( p_input->p_method_data,
+                                     p_oggpacket->bytes ) ) )
+    {
+        input_DeletePES( p_input->p_method_data, p_pes );
+        return;
+    }
+
+    p_pes->p_first = p_pes->p_last = p_data;
+    p_pes->i_nb_data = 1;
+    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 :
+        input_ClockGetTS( p_input, p_input->stream.p_selected_program,
+                          p_pes->i_pts );
+
+    memcpy( p_data->p_payload_start, p_oggpacket->packet, p_oggpacket->bytes );
+
+    input_DecodePES( p_stream->p_es->p_decoder_fifo, p_pes );
+}
+
+/****************************************************************************
+ * Ogg_FindLogicalStreams: Find the logical streams embedded in the physical
+ *                         stream and fill p_ogg.
+ *****************************************************************************
+ * The initial page of a logical stream is marked as a 'bos' page.
+ * Furthermore, the Ogg specification mandates that grouped bitstreams begin
+ * together and all of the initial pages must appear before any data pages.
+ *
+ * On success this function returns VLC_SUCCESS.
+ ****************************************************************************/
+static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
+{
+    ogg_packet oggpacket;
+    ogg_page oggpage;
+    int i_stream;
+
+    while( Ogg_ReadPage( p_input, p_ogg, &oggpage ) == VLC_SUCCESS )
+    {
+        if( ogg_page_bos( &oggpage ) )
+        {
+
+            /* All is wonderful in our fine fine little world.
+             * We found the beginning of our first logical stream. */
+            while( ogg_page_bos( &oggpage ) )
+            {
+                p_ogg->i_streams++;
+                p_ogg->pp_stream =
+                    realloc( p_ogg->pp_stream, p_ogg->i_streams *
+                             sizeof(logical_stream_t *) );
+
+#define p_stream p_ogg->pp_stream[p_ogg->i_streams - 1]
+
+                p_stream = malloc( sizeof(logical_stream_t) );
+                memset( p_stream, 0, sizeof(logical_stream_t) );
+
+                /* Setup the logical stream */
+                p_stream->i_pages_read++;
+                p_stream->i_serial_no = ogg_page_serialno( &oggpage );
+                ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
+
+                /* 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 )
+                {
+                    /* error. stream version mismatch perhaps */
+                    msg_Err( p_input, "Error reading first page of "
+                             "Ogg bitstream data" );
+                    return VLC_EGENERIC;
+                }
+
+                /* FIXME: check return value */
+                ogg_stream_packetpeek( &p_stream->os, &oggpacket );
+
+                /* Check for Vorbis header */
+                if( oggpacket.bytes >= 7 &&
+                    ! strncmp( &oggpacket.packet[1], "vorbis", 6 ) )
+                {
+                    oggpack_buffer opb;
+
+                    msg_Dbg( p_input, "found vorbis header" );
+                    p_stream->i_cat = AUDIO_ES;
+                    p_stream->i_fourcc = VLC_FOURCC( 'v','o','r','b' );
+
+                    /* Cheat and get additionnal info ;) */
+                    oggpack_readinit( &opb, oggpacket.packet, oggpacket.bytes);
+                    oggpack_adv( &opb, 88 );
+                    p_stream->i_channels = oggpack_read( &opb, 8 );
+                    p_stream->i_rate = oggpack_read( &opb, 32 );
+                    oggpack_adv( &opb, 32 );
+                    p_stream->i_bitrate = oggpack_read( &opb, 32 );
+                }
+                else
+                {
+                    msg_Dbg( p_input, "found unknown codec" );
+                    ogg_stream_destroy( &p_stream->os );
+                    free( p_stream );
+                    p_ogg->i_streams--;
+                }
+
+#undef p_stream
+
+                if( Ogg_ReadPage( p_input, p_ogg, &oggpage ) != VLC_SUCCESS )
+                    return VLC_EGENERIC;
+            }
+
+            /* This is the first data page, which means we are now finished
+             * with the initial pages. We just need to store it in the relevant
+             * bitstream. */
+            for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
+            {
+                if( ogg_stream_pagein( &p_ogg->pp_stream[i_stream]->os,
+                                       &oggpage ) == 0 )
+                {
+                    p_ogg->pp_stream[i_stream]->i_pages_read++;
+                    break;
+                }
+            }
+            return VLC_SUCCESS;
+        }
+    }
+    return VLC_EGENERIC;
+}
+
+/*****************************************************************************
+ * Activate: initializes ogg demux structures
+ *****************************************************************************/
+static int Activate( vlc_object_t * p_this )
+{
+    int i_stream, b_forced;
+    demux_sys_t    *p_ogg;
+    input_thread_t *p_input = (input_thread_t *)p_this;
+
+    p_input->p_demux_data = NULL;
+    b_forced = ( ( *p_input->psz_demux )&&
+                 ( !strncmp( p_input->psz_demux, "ogg", 10 ) ) ) ? 1 : 0;
+
+    /* Check if we are dealing with an ogg stream */
+    if( !b_forced && ( Ogg_Check( p_input ) != VLC_SUCCESS ) )
+        return -1;
+
+    /* Allocate p_ogg */
+    if( !( p_ogg = malloc( sizeof( demux_sys_t ) ) ) )
+    {
+        msg_Err( p_input, "out of memory" );
+        goto error;
+    }
+    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->b_seekable = ( ( p_input->stream.b_seekable )
+                        &&( p_input->stream.i_method == INPUT_METHOD_FILE ) );
+
+    /* Initialize the Ogg physical bitstream parser */
+    ogg_sync_init( &p_ogg->oy );
+
+    /* Find the logical streams embedded in the physical stream and
+     * initialize our p_ogg structure. */
+    if( Ogg_FindLogicalStreams( p_input, p_ogg ) != VLC_SUCCESS )
+    {
+        msg_Err( p_input, "couldn't find an ogg logical stream" );
+        goto error;
+    }
+
+    /* Set the demux function */
+    p_input->pf_demux = Demux;
+
+    /* Initialize access plug-in structures. */
+    if( p_input->i_mtu == 0 )
+    {
+        /* Improve speed. */
+        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
+    }
+
+    /* Create one program */
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    if( input_InitStream( p_input, 0 ) == -1)
+    {
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        msg_Err( p_input, "cannot init stream" );
+        goto error;
+    }    
+    if( input_AddProgram( p_input, 0, 0) == NULL )
+    {
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        msg_Err( p_input, "cannot add program" );
+        goto error;
+    }
+    p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
+    vlc_mutex_unlock( &p_input->stream.stream_lock ); 
+
+    for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
+    {
+#define p_stream p_ogg->pp_stream[i_stream]
+        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 );
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        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;
+#undef p_stream
+    }
+
+    vlc_mutex_lock( &p_input->stream.stream_lock ); 
+    p_input->stream.i_mux_rate = 0;
+    vlc_mutex_unlock( &p_input->stream.stream_lock ); 
+
+    for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
+    {
+#define p_stream  p_ogg->pp_stream[i_stream]
+        switch( p_stream->p_es->i_cat )
+        {
+            case( VIDEO_ES ):
+
+                if( (p_ogg->p_stream_video == NULL) )
+                {
+                    p_ogg->p_stream_video = p_stream;
+                    /* TODO add test to see if a decoder has been found */
+                    Ogg_StreamStart( p_input, p_ogg, i_stream );
+                }
+                break;
+
+            case( AUDIO_ES ):
+                if( (p_ogg->p_stream_audio == NULL) ) 
+                {
+                    p_ogg->p_stream_audio = p_stream;
+                    Ogg_StreamStart( p_input, p_ogg, i_stream );
+                }
+                break;
+
+            default:
+                break;
+        }
+#undef p_stream
+    }
+
+    /* we select the first audio and video ES */
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    if( !p_ogg->p_stream_video )
+    {
+        msg_Warn( p_input, "no video stream found" );
+    }
+    if( !p_ogg->p_stream_audio )
+    {
+        msg_Warn( p_input, "no audio stream found!" );
+    }
+    p_input->stream.p_selected_program->b_is_ok = 1;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+    return 0;
+
+ error:
+    Deactivate( (vlc_object_t *)p_input );
+    return -1;
+
+}
+
+/*****************************************************************************
+ * Deactivate: frees unused data
+ *****************************************************************************/
+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  ; 
+    int i;
+
+    if( p_ogg )
+    {
+        /* Cleanup the bitstream parser */
+        ogg_sync_clear( &p_ogg->oy );
+
+        for( i = 0; i < p_ogg->i_streams; i++ )
+        {
+            ogg_stream_clear( &p_ogg->pp_stream[i]->os );
+            free( p_ogg->pp_stream[i] );
+        }
+        if( p_ogg->pp_stream ) free( p_ogg->pp_stream );
+
+        free( p_ogg );
+    }
+}
+
+/*****************************************************************************
+ * Demux: reads and demuxes data packets
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
+static int Demux( input_thread_t * p_input )
+{
+    int i, i_stream, b_eos;
+    ogg_page    oggpage;
+    ogg_packet  oggpacket;
+    demux_sys_t *p_ogg  = (demux_sys_t *)p_input->p_demux_data;
+
+#define p_stream p_ogg->pp_stream[i_stream]
+    /* detect new selected/unselected streams */
+    for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
+    {
+        if( p_stream->p_es )
+        {
+            if( p_stream->p_es->p_decoder_fifo &&
+                !p_stream->i_activated )
+            {
+                Ogg_StreamStart( p_input, p_ogg, i_stream );
+            }
+            else
+            if( !p_stream->p_es->p_decoder_fifo &&
+                p_stream->i_activated )
+            {
+                Ogg_StreamStop( p_input, p_ogg, i_stream );
+            }
+        }
+    }
+
+    /* search new video and audio stream selected
+     * if current have been unselected */
+    if( ( !p_ogg->p_stream_video )
+            || ( !p_ogg->p_stream_video->p_es->p_decoder_fifo ) )
+    {
+        p_ogg->p_stream_video = NULL;
+        for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
+        {
+            if( ( p_stream->i_cat == VIDEO_ES )
+                  &&( p_stream->p_es->p_decoder_fifo ) )
+            {
+                p_ogg->p_stream_video = p_stream;
+                break;
+            }
+        }
+    }
+    if( ( !p_ogg->p_stream_audio )
+            ||( !p_ogg->p_stream_audio->p_es->p_decoder_fifo ) )
+    {
+        p_ogg->p_stream_audio = NULL;
+        for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
+        {
+            if( ( p_stream->i_cat == AUDIO_ES )
+                  &&( p_stream->p_es->p_decoder_fifo ) )
+            {
+                p_ogg->p_stream_audio = 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) )
+    {
+        msg_Warn( p_input, "synchro reinit" );
+        p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK;
+    }
+
+    /* 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++ )
+    {
+        if( Ogg_ReadPage(p_input, p_ogg, &oggpage ) != VLC_SUCCESS )
+        {
+            b_eos = 1;
+            break;
+        }
+
+        for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ )
+        {
+            /* FIXME: we already read the header */
+
+            if( ogg_stream_pagein( &p_stream->os, &oggpage ) != 0 )
+                continue;
+
+            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);
+
+                Ogg_DecodePacket( p_input, p_stream, &oggpacket );
+            }
+        }
+#undef p_stream
+    }
+
+    /* Did we reach the end of stream ? */
+    return( b_eos ? 0 : 1 );
+}