+/*****************************************************************************
+ * Close: frees unused data
+ *****************************************************************************/
+static void Close( vlc_object_t *p_this )
+{
+ demux_t *p_demux = (demux_t *)p_this;
+ demux_sys_t *p_sys = p_demux->p_sys ;
+
+ /* Cleanup the bitstream parser */
+ ogg_sync_clear( &p_sys->oy );
+
+ Ogg_EndOfStream( p_demux );
+
+ free( p_sys );
+}
+
+/*****************************************************************************
+ * Demux: reads and demuxes data packets
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
+static int Demux( demux_t * p_demux )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ ogg_page oggpage;
+ ogg_packet oggpacket;
+ int i_stream;
+
+
+ if( p_sys->i_eos == p_sys->i_streams )
+ {
+ if( p_sys->i_eos )
+ {
+ msg_Dbg( p_demux, "end of a group of logical streams" );
+ Ogg_EndOfStream( p_demux );
+ }
+
+ p_sys->i_eos = 0;
+ if( Ogg_BeginningOfStream( p_demux ) != VLC_SUCCESS ) return 0;
+
+ msg_Dbg( p_demux, "beginning of a group of logical streams" );
+ es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
+ }
+
+ /*
+ * Demux an ogg page from the stream
+ */
+ if( Ogg_ReadPage( p_demux, &oggpage ) != VLC_SUCCESS )
+ {
+ return 0; /* EOF */
+ }
+
+ /* Test for End of Stream */
+ if( ogg_page_eos( &oggpage ) ) p_sys->i_eos++;
+
+
+ for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
+ {
+ logical_stream_t *p_stream = p_sys->pp_stream[i_stream];
+
+ if( ogg_stream_pagein( &p_stream->os, &oggpage ) != 0 )
+ continue;
+
+ while( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
+ {
+ /* Read info from any secondary header packets, if there are any */
+ if( p_stream->secondary_header_packets > 0 )
+ {
+ if( p_stream->fmt.i_codec == VLC_FOURCC('t','h','e','o') &&
+ oggpacket.bytes >= 7 &&
+ ! memcmp( &oggpacket.packet[1], "theora", 6 ) )
+ {
+ Ogg_ReadTheoraHeader( p_stream, &oggpacket );
+ p_stream->secondary_header_packets = 0;
+ }
+ else if( p_stream->fmt.i_codec == VLC_FOURCC('v','o','r','b') &&
+ oggpacket.bytes >= 7 &&
+ ! memcmp( &oggpacket.packet[1], "vorbis", 6 ) )
+ {
+ Ogg_ReadVorbisHeader( p_stream, &oggpacket );
+ p_stream->secondary_header_packets = 0;
+ }
+ else if ( p_stream->fmt.i_codec == VLC_FOURCC('c','m','m','l') )
+ {
+ p_stream->secondary_header_packets = 0;
+ }
+ }
+
+ if( p_stream->b_reinit )
+ {
+ /* If synchro is re-initialized we need to drop all the packets
+ * until we find a new dated one. */
+ Ogg_UpdatePCR( p_stream, &oggpacket );
+
+ if( p_stream->i_pcr >= 0 )
+ {
+ p_stream->b_reinit = 0;
+ }
+ else
+ {
+ p_stream->i_interpolated_pcr = -1;
+ continue;
+ }
+
+ /* An Ogg/vorbis packet contains an end date granulepos */
+ if( p_stream->fmt.i_codec == VLC_FOURCC( 'v','o','r','b' ) ||
+ p_stream->fmt.i_codec == VLC_FOURCC( 's','p','x',' ' ) ||
+ p_stream->fmt.i_codec == VLC_FOURCC( 'f','l','a','c' ) )
+ {
+ if( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
+ {
+ Ogg_DecodePacket( p_demux, p_stream, &oggpacket );
+ }
+ else
+ {
+ es_out_Control( p_demux->out, ES_OUT_SET_PCR,
+ p_stream->i_pcr );
+ }
+ continue;
+ }
+ }
+
+ Ogg_DecodePacket( p_demux, p_stream, &oggpacket );
+ }
+ break;
+ }
+
+ i_stream = 0; p_sys->i_pcr = -1;
+ for( ; i_stream < p_sys->i_streams; i_stream++ )
+ {
+ logical_stream_t *p_stream = p_sys->pp_stream[i_stream];
+
+ if( p_stream->fmt.i_cat == SPU_ES )
+ continue;
+ if( p_stream->i_interpolated_pcr < 0 )
+ continue;
+
+ if( p_sys->i_pcr < 0 || p_stream->i_interpolated_pcr < p_sys->i_pcr )
+ p_sys->i_pcr = p_stream->i_interpolated_pcr;
+ }
+
+ if( p_sys->i_pcr >= 0 )
+ {
+ es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr );
+ }
+
+
+ return 1;
+}
+
+/*****************************************************************************
+ * Control:
+ *****************************************************************************/
+static int Control( demux_t *p_demux, int i_query, va_list args )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ int64_t *pi64;
+ int i;
+
+ switch( i_query )
+ {
+ case DEMUX_GET_TIME:
+ pi64 = (int64_t*)va_arg( args, int64_t * );
+ *pi64 = p_sys->i_pcr;
+ return VLC_SUCCESS;
+
+ case DEMUX_SET_TIME:
+ return VLC_EGENERIC;
+
+ case DEMUX_SET_POSITION:
+ for( i = 0; i < p_sys->i_streams; i++ )
+ {
+ logical_stream_t *p_stream = p_sys->pp_stream[i];
+
+ /* we'll trash all the data until we find the next pcr */
+ p_stream->b_reinit = 1;
+ p_stream->i_pcr = -1;
+ p_stream->i_interpolated_pcr = -1;
+ ogg_stream_reset( &p_stream->os );
+ }
+ ogg_sync_reset( &p_sys->oy );
+
+ default:
+ return demux2_vaControlHelper( p_demux->s, 0, -1, p_sys->i_bitrate,
+ 1, i_query, args );
+ }
+}
+